当前位置: 首页 > 科技观察

干货总结:中级前端工程师必须掌握的27个JavaScript技能

时间:2023-03-14 22:39:06 科技观察

和其他很多语言一样,JavaScript也需要很多小技巧来完成各种各样的事情。有些可能已经广为人知,而另一些可能会让您感到困惑。下面就为大家介绍27个可以马上上手的JavaScript小技巧。下面就和小编一起来看看吧!1.判断数据类型,使用带闭包的Object.prototype.toString。在保证判断数据类型准确的同时,也可以让这个函数变得非常灵活。通过传入不同的判断类型,可以返回不同的判断函数(注意传入的类型参数要大写)。2、ES5实现数组map方法。值得一提的是,map的第二个参数就是第一个参数回调中的this点。如果第一个参数是箭头函数,那么设置第二个参数就是因为箭头函数。词法绑定失败。3.使用reduce实现数组map方法4.ES5实现数组过滤方法5.使用reduce实现数组过滤方法6.ES5实现数组的some方法执行some方法如果some方法的数组是空数组,最后总是返回false,另外一个数组的every方法如果是空数组,总是返回true。7、ES5实现数组的reduce方法8、使用reduce实现数组的flat方法因为selfFlat依赖this指向,所以reduce遍历的时候需要指定selfFlat的this指向,否则会默认指向window和会发生错误。原理是通过reduce遍历数组,当数组的某个元素还是数组时,通过ES6的展开操作符对其进行降维(ES5可以使用concat方法),并且这个数组元素还可能有一个嵌套数组里面,所以你需要递归调用selfFlat。同时原生的flat方法支持一个depth参数来表示降维的深度。默认值为1,表示将数组的维度减少一级。传递Inifity会将传递的数组变成一维数组。原理是每次递归将depth参数减1,如果depth参数为0则直接返回原数组。9、实现ES6类语法ES6类内部是基于寄生组合继承的,是目前最理想的继承方式。通过Object.create方法创建一个空对象,继承Object.create方法的参数。让子类(subType)的原型对象等于这个空对象,子类实例的原型可以等于这个空对象,这个空对象的原型等于父类原型的继承关系对象(superType.prototype)。而Object.create支持第二个参数,即为生成的空对象定义属性和属性描述符/访问器描述符。我们可以为这个空对象定义一个constructor属性,这样更符合默认的继承行为,而且是不可枚举的可枚举内部属性(enumerable:false)。ES6类允许子类继承父类的静态方法和静态属性,而普通的寄生组合继承只能实现实例间的继承。对于类之间的继承,需要定义额外的方法。这里使用Object.setPrototypeOf将superType设置为subType的原型,这样就可以从父类继承静态方法和静态属性。10.如何使用函数柯里化:柯里化是函数式编程中的一项重要技术,它是一种将一个使用多个参数的函数转换为一系列使用一个参数的函数的技术。compose,函数式编程的另一个重要功能,可以组合函数,组合后的函数只接受一个参数,所以如果需要接受多个函数又需要使用compose来组合函数,就需要使用currypair一个函数,即readytobecomposed被部分评估,因此它总是只接受一个参数。借用SaeYu的博客的例子:11.函数currying(支持占位符)用法:使用占位符让currying更加灵活,思路是先把每一轮传入的参数填入上一轮的占位符,如果当前轮parameter包含占位符,会放在内部保存的数组的末尾,当前轮次的元素不会填入当前轮次参数的占位符,只会填入传入的数字前的占位符。12.如何使用偏函数:偏函数和柯里化的概念是相似的。个人认为它们的区别在于,partialfunctions会固定你传入的几个参数,然后一次性接受剩下的参数,而functioncurrying会根据你传入的参数一直返回给函数,直到parameters满足柯里化前函数的参数个数。Function.prototype.bind函数是偏函数的典型代表。它接受第二个参数,这是预先添加到绑定函数的参数列表中的参数。与bind不同的是,上面的函数还支持计费位数。13、斐波那契数列及其优化使用函数内存来保存前面计算的结果,对于经常依赖前面结果的计算,比如斐波那契数列,可以节省很多时间。缺点是闭包对象中的obj会占用额外的内存。14.实现函数bind方法函数bind方法的核心是使用call,同时考虑一些其他情况,例如:当bind返回的函数被new作为构造函数调用时,绑定的值会失效并更改为new指定的对象定义指定了绑定函数的length属性和name属性(不可枚举属性)。绑定函数的原型需要指向原始函数,这里使用ES6Symbol类型来防止属性冲突。16、CO模块的简单使用方法:run函数接受一个生成器函数。每当run函数包裹的生成器函数遇到yield关键字时,它就会停止。当yield后面的promise解析成功后,会自动调用next方法执行,在下一个yield关键字处,最终形成每一个promise解析成功,再解析下一个promise,当所有解析完成成功,所有的解析结果都会被打印出来,演变成最常用的async/await语法。17、功能防抖前导是进入时是否立即执行一次,尾随是事件触发结束后是否再触发一次。原理是利用定时器。如果在指定时间内再次触发该事件,则最后一个定时器将被清零,即该函数不会被执行,并重新设置一个新的定时器,直到定时器中的函数在指定的时间后自动触发。同时通过闭包暴露了一个取消函数,使得外部可以直接清除内部计数器。18.函数节流类似于函数防抖,不同的是内部多了一个时间戳作为判断,只有在一段时间内没有触发事件后才允许触发下一个事件。19.图片延迟加载getBoundClientRect的实现,监听滚动事件(建议在监听事件上加节流),图片加载完成后,会从img标签组成的DOM列表中删除,最后全部删除图片需要在事件加载后解除绑定。intersectionObserver的实现,实例化一个IntersectionObserver,让它观察所有的img标签。当img标签进入可见区域时,会执行实例化回调,同时会向回调传递一个entries参数,保存实例观察到的所有元素的一些状态,比如每个元素的边界信息元素,以及当前元素对应的DOM节点,当前元素进入可见区域的比例,每当有元素进入可见区域,将真实图像赋值给当前img标签,同时释放其观察。20.new关键字21.Object.assignObject.assign的实现原理可以参考我的另一篇博客。22、instanceof的原理是递归遍历右参数的原型链,每次都和左参数比较,遍历到原型链末尾返回false,找到返回true。23、私有变量的实现使用Proxy代理所有以_开头的变量,使其无法被外部访问。以闭包形式保存私有变量的缺点是类的所有实例都访问同一个私有变量。闭包的另一种实现解决了上述闭包的不足。每个实例都有自己的私有变量。缺点是它放弃了类语法的简单性,将所有特权方法(访问私有变量的方法)都存储在构造函数中。通过WeakMap和闭包,在每次实例化时保存当前实例和所有私有变量组成的对象,外部无法访问闭包中的WeakMap。使用WeakMap的好处是不用担心内存溢出。24.ShuffleAlgorithm早期的chrome会对小于10个元素的数组使用插入排序,这样会导致数组的乱序并不是真正的乱序,即使最新版的chrome使用了in-place算法让排序变成了一个稳定的算法已经建立,但是乱序的问题还没有解决。真正的乱序可以通过shuffle算法来实现。洗牌算法分为原地和非原地。图1显示了就地改组算法。无需声明额外的数组来节省内存使用量。原理是顺序遍历数组的元素,从当前元素和后面的所有元素中随机选择一个进行交换。25、单例模式是通过ES6的Proxy拦截构造函数的执行方法实现的单例模式。26、如何使用promisify:promisify函数是一个辅助函数,将回调函数变成promise。适用于错误优先风格(nodejs)的回调函数。原理是无论成功还是失败,都给出error-first风格的回调。要执行最后一个回调函数,我们需要做的就是让这个回调函数控制promise的状态。这里使用Proxy来代理整个fs模块并拦截get方法,这样就不需要手动用promisify函数包装fs模块的所有方法,更加灵活。27、async/await用法的优雅处理:不用每次使用async/await都包裹一层try/catch,更加优雅。这是另一个想法。如果你使用webpack,你可以写一个loader来分析AST语法树。遇到await语法,自动注入try/catch,这样连辅助功能都不用用了。