前端科举八股文-手撕代码篇

news2024/9/8 17:59:35

前端科举八股文-手撕代码篇

  • 手撕排序算法
    • 选择排序
      • 思路
    • 冒泡排序
      • 思路
    • 快速排序
      • 思路
  • 手撕bind方法
    • 思路解析
  • 手撕js的继承方案
    • 构造继承
      • 实现原理
    • 原型继承
      • 实现原理
    • 组合继承
      • 实现原理
    • 寄生组合继承
      • 实现原理
  • 手撕instanceOf
    • 实现原理
  • 手撕new 操作符
  • 手撕防抖
    • 实现原理
  • 手撕节流
    • 实现原理
  • 手撕深拷贝
    • 直接调用api实现深拷贝
  • 手撕Promise
    • 实现原理
  • 手撕promise.then方法
    • 实现原理
    • 惊天反转!!!
  • 手撕promise.all方法

手撕排序算法

选择排序

const originalList = [3, 5, 1, 2, 4, 9, 6, 8, 7]

        const selectSort = (list) => {
            for (let i = 0; i < list.length - 1; i++) {
                // 初始化最大值为每次循环的第一个数
                let max = list[i]
                // 初始化最大值下标当前索引
                let maxIndex = i;
                for(let j = i+1;j< list.length;j++){
                    if(list[j] > max){
                        // 有最大值更新最大值和最大值索引
                        max = list[j];
                        maxIndex = j;
                    }
                }
                // 把当前循环第一个值和最大值调换位置
                const currentNumber = list[i]
                list[i] = list[maxIndex]
                list[maxIndex] = currentNumber;
            }
        }
        selectSort(originalList)
        console.log(originalList)

思路

基本思路,嵌套遍历,每次循环都找出最大值或者最小值与当前遍历的第一个交换
菜鸟讲的比我讲的好

冒泡排序

	
        const originalList = [3, 5, 1, 2, 4, 9, 6, 8, 7]
        const popSort = (list) => {
            for (let i = 0; i < list.length - 1; i++) {
                for (let j = 0 ; j < list.length - 1 - i; j++) {
                    if (list[j] > list[j + 1]) {
                    	// 每次循环只拿相邻值做比较并且交换
                        const flag = list[j + 1]
                        list[j + 1] = list[j];
                        list[j] = flag;
                    }
                }
            }
        }

        popSort(originalList)
        console.log(originalList)

思路

基本思路,还是嵌套遍历,不过比选择排序先进一点,每次遍历不止交换一次,而是相邻的值去比较与交换。
菜鸟讲的还是比我好
这里声明一下里面循环的次数是list.length - 1 - i,因为每次进循环时本质上最后i个元素已经排序完成了,写成list.length - 1 - i可以提高算法执行效率

快速排序

	         const originalList = [3, 5, 1, 2, 4, 9, 6, 8, 7]

        const quickSort = (list) => {
            if (list.length <= 1) {
                return list
            }
            // 选一个基准值 (随便选)
            const middleNumber = list[list.length - 1]
            // 找出比基准值小的数组
            const leftList = list.filter(item => item < middleNumber)
            // 找出比基准值大的数组
            const rightList = list.filter(item => item > middleNumber)
            // console.log('right', rightList)
            return [...quickSort(leftList), middleNumber, ...quickSort(rightList)]
            // quickSort([...leftList, middleNumber, ...rightList])
        }

        console.log(quickSort(originalList))

思路

用到了递归的思路,每次找一个基准值,然后区分出比基准值小的数组,再找出比基准值大的数组,最后递归使用快排来排序小值数组和大值数组,可能在人类理解中比较抽象,但是在计算机中可以更快的得出排序结果
看看动图呗

手撕bind方法

	// 只考虑了bind方法改变this的情况 不考虑其他复杂情况
	 Function.prototype.myBind = function (context, ...args){
            const _this = this;
            return () => {
                _this.call(context,...args)
            }
        }

思路解析

我们将方法挂载到函数原型上是为了让自定义的bind方法的调用方式和原生bind方法的调用方式一模一样,即function.bind(context),其内部实现,const _this = this其实是为了拿到真实调用的函数,因为js中的函数调用有个潜规则 函数的this,永远都是指向函数的调用者 那么我们如果通过function.bind(context)调用时,_this就可以拿到真实的调用者。然后因为bind方法返回的是一个函数,所以我们内部实现也会返回一个函数,在函数内部

手撕js的继承方案

构造继承

// es6之前的继承方式
		function Person(name) {
            this.name = name
        }

        function Student(name, age) {
            Person.call(this, name)
            this.age = age
        }

        const student = new Student('wxs', 26)
        console.log(student)

实现原理

构造继承的本质就是在子类中去调用父类的构造函数,但是这种继承方式有一个很明显的缺陷,和他的继承方式有关,可以从他的本质上是把父类的this指到了子类里面,但是由于并没有生成父类的实例,实际上是无法继承父类原型上的属性或者方法的(因为只有实例才能继承构造函数原型上的属性和方法)。直接看🌰

	  function Person(name) {
            this.name = name
        }

        Person.prototype.basic = {
            eyes: '两只',
            nose: '一个',
            mouth: '一张',
            ears: '两个',
        }


        function Student(name, age) {
            Person.call(this, name)
            this.age = age
        }

        const student_1 = new Student('wxs', 26)
        console.log(student_1.basic) // undefined

原型继承

那么为了继承原型上的属性或者方法,我们就要用到原型继承了

	 function Person(name) {
            this.name = name
        }
        
        Person.prototype.basic = {
            eyes: '两只',
            nose: '一个',
            mouth: '一张',
            ears: '两个',
        }

        Student.prototype = new Person()

        function Student(name, age) {
            this.age = age
        }

实现原理

原型继承的实现原理实际上是生成一个父类的实例,然后赋值给子类的原型,那么子类的实例就会同时有子类实例属性/方法,子类原型属性/方法,父类实例属性/方法,父类原型属性/方法。但是这个的缺陷也十分之明显,最明显的就是子类构造函数中的name形参无法传到父类中了!第二个,可以看到由于子类继承的是同一个父类原型实例,所以其实所有的子类实例,会共享父类中的引用对象类型数据,在改变时也会造成同步污染。举个🌰

	  function Person(name) {
            this.name = name
        }

        Person.prototype.basic = {
            eyes: '两只',
            nose: '一个',
            mouth: '一张',
            ears: '两个',
        }

        Student.prototype = new Person()

        function Student(name, age) {
            this.age = age
        }

        const student_1 = new Student('wxs', 26)
        const student_2 = new Student('someBody', 27)

        // 学生1只有一只耳朵
        student_1.basic.ears = '一只'

        console.log('学生2有几只耳朵', student_2.basic.ears) // 一只

组合继承

	 function Person(name) {
            this.name = name
        }

        Person.prototype.basic = {
            eyes: '两只',
            nose: '一个',
            mouth: '一张',
            ears: '两个',
        }

        Student.prototype = new Person()

        function Student(name, age) {
            Person.call(this, name)
            this.age = age
        }

实现原理

实现原理其实没什么好说的,因为原型继承不能穿参,构造继承不能继承原型上的属性和方法,所以把两者结合起来,但是这种方法也有缺陷,可以看到new Person()调用了一次父类构造函数,Person.call又调用了一次,一次继承就调用了两次无疑是造成了很大了资源消耗,所以我们来看看终极解决方案—寄生组合继承

寄生组合继承

	 function extend(son,father){
            const midPrototype = Object.create(father.prototype)
            midPrototype.constructor = son
            son.prototype = midPrototype
        }

实现原理

寄生组合继承的终极目的实际上就是为了弥补上述继承方式的不足(父类构造函数多构造了一次、不能继承父类原型上的属性和方法)执行了上述extend方法之后父类子类的原型链关系就会变成 son.prototype === midPrototype,而midPrototype又是 father.prototype通过Object.create方法新建的对象,
在这里插入图片描述
所以说midPrototype是以 father.prototype为原型,所以可以继承father.prototype原型上的属性或者方法,同时也避免了重复执行父类构造函数!

手撕instanceOf

	 function myInstanceOf(targetObejct, constructFn) {
            let targetObejctProto = targetObejct.__proto__
            do {
                if (targetObejctProto === constructFn.prototype) {
                    return true
                }
                targetObejctProto = targetObejctProto.__proto__
            } while (targetObejctProto)
            return false
        }

实现原理

要实现instanceof,首先要知道这个api是干什么,根据MDN官方解释
在这里插入图片描述
所以要实现起来就很简单了,我们首先拿出实例对象取出实例对象的原型,看看是否指向构造函数的原型,如果不等于我们要递归的一直取【原型】的【原型】,一直取到Object.__proto__也就是undefined为止。

手撕new 操作符

	 function myNew(contructor, ...args) {
            let obj = new Object()
            contructor.call(obj, ...args)
            obj.constructor = contructor
            obj.__proto__ = constructor.prototype
            return obj;
     }

手撕防抖

首先我们来看看没有做防抖的情况,比如有一个场景需要在用户下拉的时候获取最新数据。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <style>
        .body{
            height: 3000px;
        }
    </style>

</head>

<body>
    <div class="body">123</div>
    
    <script>
        const scrollHandle = () => {
            console.log('开始发送ajax请求获取最新的数据')
        }

        window.addEventListener('scroll',scrollHandle)

    </script>

</body>

</html>

实现原理

由于是高频次触发事件,所以在下拉事件中,scrollhandle事件被多次触发,而由此带来的性能开销也是十分巨大的。而仔细分析后,我们往往只需要在用户停止操作的时候触发一次请求加载动作即可。正好满足防抖的设计思想将多次操作合并成一次接下来看看优化后的代码

	<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .body {
            height: 3000px;
        }
    </style>
</head>
<body>
    <div class="body">123</div>
    <script>
        const scrollHandle = () => {
            console.log('开始发送ajax请求获取最新的数据')
        }
        const throttle = (fn, timeOut = 500) => {
            return () => {
                clearTimeout(fn.tId)
                fn.tId = setTimeout(() => {
                    fn()
                }, timeOut);
            }
        }
        window.addEventListener('scroll', throttle(scrollHandle))
    </script>
</body>
</html>

手撕节流

	const debounce = (fn, timeOut = 1000) => {
            return () => {
                if (fn.tid) {
                    return
                }
                fn.tid = setTimeout(() => {
                    fn.tid = null
                    clearTimeout(fn.tid)
                    fn()
                }, timeOut);
            }
        }

实现原理

其实就是在防抖的基础上加了一个定时触发的逻辑,只要tid还在,就直接return,如果不存在,就重设tid为定时器的唯一id,在定时器的回调里面去清空这个值。

手撕深拷贝

 const deepClone = (targetObj) => {
            let resultObj = null
            if (typeof targetObj !== "object") {
                // 基础类型
                resultObj = targetObj
                return resultObj
            } else {
                if (Array.isArray(targetObj)) {
                    // 数组对象
                    resultObj = []
                    for (let i = 0; i < targetObj.length; i++) {
                        resultObj[i] = targetObj[i]
                    }
                    return resultObj
                } else {
                    resultObj = {}
                    // 对象类型
                    Object.entries(targetObj).forEach(([key, value]) => {
                        if (typeof value === "object") {
                            resultObj[key] = deepClone(value)
                        } else {
                            resultObj[key] = value
                        }
                    })
                    return targetObj
                }
            }
        }

直接调用api实现深拷贝

        const b = JSON.parse(JSON.stringify(originalObj))
        但是由于json对象是没有函数和空对象的概念,所以当原对象的value中有null和函数时会报错

手撕Promise

嘿嘿 到这里也算是半个小中级前端CV工程师了,都要手写ES6API了。

// 首先来看看ES6标准的Promise是如何调用的
       // const P_1 = new Promise((resolve, reject) => {
       //     const result = Math.random()
       //     if (result > 0.5) {
       //         resolve('成功了')
       //     } else {
       //         reject('失败了')
       //     }
       // })

       // console.log(P_1)

class WxsPromise {
           // 缓存当前promise实例状态 promise状态只有三种 pending resolve reject
           promiseState = 'pending'
           // 缓存promise的结果值
           promiseResult
           
           // 内置resolve函数
           static resolve(successResult) {
               this.promiseState = 'resolve'
               this.promiseResult = successResult
           }
           // 内置reject函数
           static reject(errorResult) {
               this.promiseState = 'reject'
               this.promiseResult = errorResult
           }
           constructor(func) {
               func(WxsPromise.resolve.bind(this), WxsPromise.reject.bind(this))
           }
       }

       const P_2 = new WxsPromise((resolve, reject) => {
           const result = Math.random()
           if (result > 0.5) {
               resolve('成功了')
           } else {
               reject('失败了')
           }
       })

实现原理

这里代码前半部分是ES6标准的promise调用方式,可以看到Promise是通过new调用的,所以我们自己实现第一步就是新建一个Class类,promise接受一个函数作为参数,所以我们自定义类的construcor的形参也是一个func,由于Promise里传入的函数是同步执行的(这里不理解的话可以去了解EventLoop模型),所以在construcor中传入形参后就立即调用,后续部分就是promise的关键点了,resolve和reject,resolve和reject都是Promise的静态方法(所谓静态方法就是只能通过构造函数本身去调用),所以我们定义的resolvereject方法都有static前缀,在func调用时传入这两个静态方法,但是我们通过打印es6的promise实例可以得出,每个实例都有自己的promiseStatepromiseResult,所以在两个实例方法中又需要改变每个实例中的promiseStatepromiseResult,那么在传入这个静态方法时就使用到了bind方法去改变实例方法的this指向,指向到了每一个promise实例上。

手撕promise.then方法

老规矩,先来看看原生promise.then的调用方法

	 // 首先来看看ES6标准的Promise是如何调用的
       const P_1 = new Promise((resolve, reject) => {
           const result = Math.random()
           if (result > 0.5) {
               resolve('成功了')
           } else {
               reject('失败了')
           }
       })

       // 看看标准的then方法调用结果
       P_1.then(res => {
           console.log('成功回调', res)
       }, (errResult) => {
           console.log('失败回调', errResult)
       })

很明显,我们需要在自定义实例上挂载一个then方法,接着上次的写

	  class WxsPromise {
           // 缓存当前promise实例状态 promise状态只有三种 pending resolve reject
           promiseState = 'pending'
           // 缓存promise的结果值
           promiseResult

           // 内置resolve函数
           static resolve(successResult) {
               this.promiseState = 'resolve'
               this.promiseResult = successResult
           }
           // 内置reject函数
           static reject(errorResult) {
               this.promiseState = 'reject'
               this.promiseResult = errorResult
           }
           constructor(func) {
               func(WxsPromise.resolve.bind(this), WxsPromise.reject.bind(this))

           }
           then(successCallback, failCallback) {
               // promise执行成功
               if (this.promiseState === 'resolve') {
                   successCallback(this.promiseResult)
               }
               if (this.promiseState === 'reject') {
                   failCallback(this.promiseResult)
               }
           }
       }

实现原理

如果掌握了上一小节后,promise.then方法实现起来确实不是什么问题,then方法接受两个回调函数作为参数,执行成功执行第一个回调,执行失败执行第二个回调。那么实现思路就直接在类里面定义then方法接受两个参数,并且根据当前实例的promiseState来执行对应的回调即可。

惊天反转!!!

莫要以为这样就实现了promise.then方法,因为promise是为了处理异步函数而诞生的标准API,我们把promise内部的函数进行改写一下。

	 const P_1 = new Promise((resolve, reject) => {
            const result = Math.random()
            if (result > 0.5) {
                setTimeout(() => {
                    resolve('成功了')
                }, 500);

            } else {
                setTimeout(() => {
                    reject('失败了')
                }, 500);
            }
        })
	 P_1.then(res => {
            console.log('成功回调', res)
        }, (errResult) => {
            console.log('失败回调', errResult)
        })

此时P_1.then方法还是能正常调用的,但是如果把自定义promise里面的函数换成了异步之后再调用then方法,那么此时的控制台是没有任何输出的。

            // 缓存当前promise实例状态 promise状态只有三种 pending resolve reject
            promiseState = 'pending'
            // 缓存promise的结果值
            promiseResult

            // 内置resolve函数
            static resolve(successResult) {
                this.promiseState = 'resolve'
                this.promiseResult = successResult
            }
            // 内置reject函数
            static reject(errorResult) {
                this.promiseState = 'reject'
                this.promiseResult = errorResult
            }
            constructor(func) {
                func(WxsPromise.resolve.bind(this), WxsPromise.reject.bind(this))

            }
            then(successCallback, failCallback) {
                // promise执行成功
                if (this.promiseState === 'resolve') {
                    successCallback(this.promiseResult)
                }
                // promise执行失败
                if (this.promiseState === 'reject') {
                    failCallback(this.promiseResult)
                }
            }
        }

        const P_2 = new WxsPromise((resolve, reject) => {
            const result = Math.random()
            if (result > 0.5) {
                setTimeout(() => {
                    resolve('成功了')
                }, 500);

            } else {
                setTimeout(() => {
                    reject('失败了')
                }, 500);
            }
        })

        // console.log(P_2)

        P_2.then(res => {
            console.log('成功回调', res)
        }, (errResult) => {
            console.log('失败回调', errResult)
        })

没有输出的原因也很简单,由于promise里面执行的是异步方法,在then方法内部执行时判断当前promiseState的状态时异步方法还没有调用,所以promiseState的值还没有改变,所以针对promiseState的判断逻辑不会执行在这里插入图片描述
所以针对异步情况下对promise做一些改动

	  class WxsPromise {
            // 缓存当前promise实例状态 promise状态只有三种 pending resolve reject
            promiseState = 'pending'
            // 缓存promise的结果值
            promiseResult

            // 内置resolve函数
            static resolve(successResult) {
                this.promiseState = 'resolve'
                this.promiseResult = successResult
                this.successCallback && this.successCallback(this.promiseResult)
            }
            // 内置reject函数
            static reject(errorResult) {
                this.promiseState = 'reject'
                this.promiseResult = errorResult
                this.failCallback && this.failCallback(this.promiseResult)
            }
            constructor(func) {
                func(WxsPromise.resolve.bind(this), WxsPromise.reject.bind(this))
            }
            then(successCallback, failCallback) {
                // promise执行成功
                if (this.promiseState === 'resolve') {
                    successCallback(this.promiseResult)
                }
                if (this.promiseState === 'reject') {
                    failCallback(this.promiseResult)
                }
                if(this.promiseState === 'pending'){
                    // 还没执行完 将函数缓存起来,待异步函数执行完成再调用
                    this.successCallback = successCallback
                    this.failCallback = failCallback
                }
            }
        }

手撕promise.all方法

首先我们知道promise.all方法返回的也是是一个promise实例,如果all参数中的promise数组悉数调用成功,那么.then方法返回的是参数中所有所有promise数组返回结果构成的数组,如果调用失败,那么返回的便是第一个调用失败的结果,看🌰

	 // 首先来看看原生promise.all方法如何调用
        const promiseConstructor = (promiseResult, timeOut, promiseState = 'resolve') => {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    if (promiseState === 'resolve') {
                        resolve(promiseResult)
                    }
                    if (promiseState === 'reject') {
                        reject(promiseResult)
                    }
                }, timeOut)
            })
        }


        Promise.all([promiseConstructor('第一个成功回调', 2000), promiseConstructor('第二个成功回调', 1000), promiseConstructor('第三个成功回调', 3000)]).then(resList => {
            console.log("看一下打印res", resList)
        }) 

        Promise.all([promiseConstructor('第一个成功回调', 2000), promiseConstructor('第二个失败回调', 1000, 'reject'), promiseConstructor('第三个成功回调', 3000)]).then(resList => {
            console.log("看一下打印res", resList)
        }, (errResult) => {
            console.log('调用失败啦', errResult)
        })

上方代码可以copy运行,也可以直接看看我的返回截图
在这里插入图片描述
知道参数,知道运行结果之后,要实现all方法就不难了。

	 const wxsPromiseAll = (promiseList) => {
            return new Promise((resolve, reject) => {
                const resultList = []
                let dealPromiseCount = 0
                promiseList.forEach((promiseItem, promiseIndex) => {
                    promiseItem.then(res => {
                        resultList[promiseIndex] = res
                        dealPromiseCount++;
                        if (dealPromiseCount === promiseList.length) {
                            resolve(resultList)
                        }
                    },(err) => {
                        reject(err)
                    })
                })
            })
        }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1961203.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java8 新特性,看这篇文章就够了

Java8 是 Java 编程语言的一个重要版本&#xff0c;于 2014 年 3 月发布。它引入了许多新的功能和改进&#xff0c;其中包括 Lambda 表达式、Stream API、新的日期/时间 API 和 Nashorn JavaScript 引擎等。 Java 8 的主要特点如下&#xff1a; Lambda 表达式&#xff1a;Lamb…

Linux进程--exec族函数

exec族函数函数的作用&#xff1a; 我们用fork函数创建新进程后&#xff0c;经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时&#xff0c;该进程被完全替换为新程序。因为调用exec函数并不创建新进程&#xff0c;所以前后进程的ID并没有改变。 原文链…

电测量数据交换DLMSCOSEM组件第53部分:DLMSCOSEM应用层(下)

3.DLMS/COSEM应用层协议规范 3.1控制功能 3.1.1客户机侧功能的状态定义 图37显示了客户机侧CF的状态机。 客户机CF(和AL包含CF)的状态定义如下: ——INACTIVE:在该状态下,CF完全没有活动;它既不给AP提供服务,也不使用协议支撑层服务; ——IDLE:在没有AA存在…

SpringBoot(看这一篇就够了)

目录&#xff1a; SpringBootSpring的缺点什么是SpringBoot&#xff1f;Springboot3 版本要求Springboot的三种构建方式官网搭建通过IDEA脚手架搭建通过Maven搭建项目 SpringBoot的项目结构编写一个测试代码YAML文件自定义配置文件Value读取配置文件ConfigurationProperties读取…

阿里P8大佬推荐的前端书籍资料,限时免费领取!

&#x1f381; 限时福利大放送&#xff01; &#x1f389; 亲爱的前端小伙伴们&#xff0c;今天给大家分享几个前端必备资料 有P8大佬的算法解题笔记, 最新大厂高频100题, 前端经典八股文&#xff0c;也有一些前端经典书籍&#xff0c;如nodejs&#xff0c;http&#xff0c;jav…

ros笔记04--从零体验ros2行为通信方式

ros笔记04--从零体验ros2行为通信方式 介绍创建步骤体验官方案例基于python开发行为案例创建action接口创建action sever和client 注意事项说明 介绍 行为是ros2中的一种通信方式&#xff0c;其多被用于一些长时间运行的任务&#xff0c;它包含了目标、反馈、结果三部分。 行为…

科普文:从源码解读5种Redis基本数据类型

键值对字符串 char* 与 SDS char* 的不足&#xff1a; 操作效率低&#xff1a;获取长度需遍历&#xff0c;O(N)复杂度 二进制不安全&#xff1a;无法存储包含 \0 的数据 SDS 的优势&#xff1a; 操作效率高&#xff1a;获取长度无需遍历&#xff0c;O(1)复杂度&#xff08…

HIS系统搭建|HIS系统功能|HIS系统开发

在当今医疗信息化的浪潮中&#xff0c;医院信息系统&#xff08;HIS&#xff09;的搭建成为了提升医疗服务效率和质量的关键。HIS系统不仅仅是一个简单的数据记录工具&#xff0c;它是一个集成了预约挂号、病历管理、药品管理、财务结算等多个功能模块的综合性平台。通过这一系…

使用idea集成的springboot实现注册接口

跟黑马程序员学pringboot3vue3,代码都是黑马程序员视频里的代码 实战篇-03_注册接口_哔哩哔哩_bilibili 本文仅仅用于学习记录 开发用户接口 注册接口 开发流程&#xff1a;明确需求>>阅读接口文档>>思路分析>>开发>>测试 分析&#xff1a; 这个…

使用SDL库以及C++实现的简单的贪吃蛇:AI Fitten生成

简单使用AI代码生成器做了一个贪吃蛇游戏 设计的基本逻辑都是正确的&#xff0c;能流畅运行 免费准确率高&#xff0c;非常不错&#xff01;支持Visual Studio系列 Fitten&#xff1a;https://codewebchat.fittenlab.cn/ SDL 入门指南&#xff1a;安装配置https://blog.csdn.n…

高效数据抓取:Scrapy框架详解

一、Scrapy框架简介 Scrapy是一个为了爬取网站数据、提取结构性数据而编写的爬虫框架。它支持异步处理&#xff0c;能够快速抓取大量网页&#xff0c;并且易于扩展。Scrapy使用Twisted这个事件驱动的网络引擎&#xff0c;可以处理大量的并发请求&#xff0c;从而提高数据抓取的…

C语言分支结构作业

作业 输入你的身高和体重&#xff0c;测试你的健康状况。 计算bmi的值&#xff0c; bmi &#xff08;体重/身高的平方) 如果bmi 小于18.5&#xff0c;则显示“偏瘦&#xff0c;注意加强营养” 如果bmi 在18.5和23.9之间&#xff0c;则显示“体重指数良好&#xff0c;注意保持…

【全栈实战】大模型自学:从入门到实战打怪升级,20W字总结(二)

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本栏讲解【全栈实战】大模型自学&#xff1a;从入门到实战打怪升级。 &#x1f514;专栏持续更新&#xff0c;适合人群&#xff1a;本科生、研究生、大模型爱好者&#xff0c;期…

基于单片机的电梯控制系统的设计

摘 要: 本文提出了一种基于单片机的电梯控制系统设计 。 设计以单片机为核心&#xff0c;通过使用和设计新型先进的硬件和控制程序来模拟和控制整个电梯的运行&#xff0c;在使用过程中具有成本低廉、 维护方便、 运行稳定 、 易于操作 、 安全系数高等优点 。 主要设计思路是…

聚焦全局应用可用性的提升策略,详解GLSB是什么

伴随互联网的快速发展和全球化趋势的深入&#xff0c;企业对网络应用的需求日渐增长。为满足全球范围内用户大量的访问需求&#xff0c;同时解决容灾、用户就近访问以及全球应用交付等问题&#xff0c;GLSB&#xff08;全局负载均衡&#xff09;也因此应运而生。那么GLSB是什么…

Axure RP:打造动态交互的大屏可视化设计利器

Axure大屏可视化是指使用Axure RP这款原型设计工具来创建具有视觉冲击力和数据展示功能的大屏幕界面。Axure以其强大的交互设计和丰富的组件库&#xff0c;成为了实现大屏可视化的重要工具之一。以下是对Axure大屏可视化的详细阐述&#xff1a; 一、Axure在大屏可视化中的优势 …

​易能医药董事长易跃能博士荣获“湖湘药学领航奖”

近日&#xff0c;湖南省药学会主办的“湖南省药学会70周年庆典暨第六届湖南药学大会”在湖南长沙隆重召开。易能医药董事长易跃能博士荣获由湖南省药学会颁发的“湖湘药学领航奖”。此次“湖湘药学领航奖”由湖南药学大会学术委员会组织评选&#xff0c;湖南省全省仅有八个名额…

六、3 PWM 舵机代码

目录 1、通道选择 2、参数计算 3、代码部分 1、通道选择 PA1对应通道2 注意&#xff1a;同一个定时器不同通道输出PWM的特点 同一个定时器的不同通道输出的PWM&#xff0c;频率相同&#xff08;因为它们共用一个计数器&#xff09;&#xff0c;占空比可以各自设定&#xff…

Kubernetes 学习记录

https://note.youdao.com/ynoteshare/index.html?idbc7bee305611b52d6900ba209a92bd4d&typenote&_time1694072007342 概览 K8S官网文档&#xff1a;https://kubernetes.io/zh/docs/home/ K8S 是Kubernetes的全称&#xff0c;源于希腊语&#xff0c;意为“舵手”或“…

ITSS:IT服务工程师

证书亮点&#xff1a;适中的费用、较低的难度、广泛的应用范围以及专业的运维认证。 总体评价&#xff1a;性价比良好&#xff01; 证书名称&#xff1a;ITSS服务工程师 证书有效期&#xff1a;持续3年 培训要求&#xff1a;必须参加培训&#xff0c;否则将无法参与考试 发…