一个前端基础需要掌握的 28 个 JavaScript 技巧(第
不论你是javascript新手还是老鸟,不论是面试求职,还是日常开发工作,我们经常会遇到这样的情况:给定的几行代码,我们需要知道其输出内容和顺序。因为javascript是一门单线程语言,所以我们可以得出结论:
各位小伙伴在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于HTML/CSS/javaScript/Vue等多个知识点高级进阶干货需要的可以免费分享给大家,有需要者请进群点击进入1045267283
一个前端基础需要掌握的 28 个 JavaScript 技巧(第一章)
14. 实现函数 bind 方法
实现函数的 bind 方法核心是利用 call 绑定 this 指向,同时考虑了一些其他情况,例如
bind 返回的函数被 new 调用作为构造函数时,绑定的值会失效并且改为 new 指定的对象
定义了绑定后函数的 length 属性和 name 属性(不可枚举属性)
绑定后函数的 prototype 需指向原函数的 prototype(真实情况中绑定后的函数是没有 prototype 的,取而代之在绑定后的函数中有个 内部属性 [[TargetFunction]] 保存原函数,当将绑定后函数作为构造函数时,将创建的实例的 __proto__ 指向 [[TargetFunction]] 的 prototype,这里无法模拟内部属性,所以直接声明了一个 prototype 属性)
15. 实现函数 call 方法
原理就是将函数作为传入的上下文参数(context)的属性执行,这里为了防止属性冲突使用了 ES6 的 Symbol 类型
16. 简易的 CO 模块
使用方法:
run 函数接受一个生成器函数,每当 run 函数包裹的生成器函数遇到 yield 关键字就会停止,当 yield 后面的 promise 被解析成功后会自动调用 next 方法执行到下个 yield 关键字处,最终就会形成每当一个 promise 被解析成功就会解析下个 promise,当全部解析成功后打印所有解析的结果,衍变为现在用的最多的 async/await 语法
17. 函数防抖
leading 为是否在进入时立即执行一次,原理是利用定时器,如果在规定时间内再次触发事件会将上次的定时器清除,即不会执行函数并重新设置一个新的定时器,直到超过规定时间自动触发定时器中的函数
同时通过闭包向外暴露了一个 cancel 函数,使得外部能直接清除内部的计数器
18. 函数节流
和函数防抖类似,区别在于内部额外使用了时间戳作为判断,在一段时间内没有触发事件才允许下次事件触发,同时新增了 trailing 选项,表示是否在最后额外触发一次
19. 图片懒加载
getBoundClientRect 的实现方式,监听 scroll 事件(建议给监听事件添加节流),图片加载完会从 img 标签组成的 DOM 列表中删除,最后所有的图片加载完毕后需要解绑监听事件
intersectionObserver 的实现方式,实例化一个 IntersectionObserver ,并使其观察所有 img 标签
当 img 标签进入可视区域时会执行实例化时的回调,同时给回调传入一个 entries 参数,保存着实例观察的所有元素的一些状态,比如每个元素的边界信息,当前元素对应的 DOM 节点,当前元素进入可视区域的比率,每当一个元素进入可视区域,将真正的图片赋值给当前 img 标签,同时解除对其的观察
20. new 关键字
21. 实现 Object.assign
22. instanceof
原理是递归遍历 right 参数的原型链,每次和 left 参数作比较,遍历到原型链终点时则返回 false,找到则返回 true
23. 私有变量的实现
使用 Proxy 代理所有含有 _ 开头的变量,使其不可被外部访问
通过闭包的形式保存私有变量,缺点在于类的所有实例访问的都是同一个私有变量
另一种闭包的实现,解决了上面那种闭包的缺点,每个实例都有各自的私有变量,缺点是舍弃了 class 语法的简洁性,将所有的特权方法(访问私有变量的方法)都保存在构造函数中
通过 WeakMap 和闭包,在每次实例化时保存当前实例和所有私有变量组成的对象,外部无法访问闭包中的 WeakMap,使用 WeakMap 好处在于当没有变量引用到某个实例时,会自动释放这个实例保存的私有变量,减少内存溢出的问题
24. 洗牌算法
早前的 chrome 对于元素小于 10 的数组会采用插入排序,这会导致对数组进行的乱序并不是真正的乱序,即使最新的版本 chrome 采用了原地算法使得排序变成了一个稳定的算法,对于乱序的问题仍没有解决
通过洗牌算法可以达到真正的乱序,洗牌算法分为原地和非原地,图一是原地的洗牌算法,不需要声明额外的数组从而更加节约内存占用率,原理是依次遍历数组的元素,将当前元素和之后的所有元素中随机选取一个,进行交换
25. 单例模式
通过 ES6 的 Proxy 拦截构造函数的执行方法来实现的单例模式
26. promisify
使用方法:
promisify 函数是将回调函数变为 promise 的辅助函数,适合 error-first 风格(nodejs)的回调函数,原理是给 error-first 风格的回调无论成功或者失败,在执行完毕后都会执行最后一个回调函数,我们需要做的就是让这个回调函数控制 promise 的状态即可
这里还用了 Proxy 代理了整个 fs 模块,拦截 get 方法,使得不需要手动给 fs 模块所有的方法都包裹一层 promisify 函数,更加的灵活
27. 优雅的处理 async/await
使用方法:
无需每次使用 async/await 都包裹一层 try/catch ,更加的优雅,这里提供另外一个思路,如果使用了 webpack 可以编写一个 loader,分析 AST 语法树,遇到 await 语法,自动注入 try/catch,这样连辅助函数都不需要使用
28. 发布订阅 EventEmitter
通过 on 方法注册事件,trigger 方法触发事件,来达到事件之间的松散解耦,并且额外添加了 once 和 off 辅助函数用于注册只触发一次的事件以及注销事件
29. 实现 JSON.stringify(附加)
使用 JSON.stringify 将对象转为 JSON 字符串时,一些非法的数据类型会失真,主要表现如下
如果对象含有 toJSON 方法会调用 toJSON
在数组中
存在 Undefined/Symbol/Function 数据类型时会变为 null
存在 Infinity/NaN 也会变成 null
在对象中
属性值为 Undefined/Symbol/Function 数据类型时,属性和值都不会转为字符串
属性值为 Infinity/NaN ,属性值会变为 null
日期数据类型的值会调用 toISOString
非数组/对象/函数/日期的复杂数据类型会变成一个空对象
循环引用会抛出错误
相关CSS知识点:这一次让你彻底弄懂 JavaScript 执行机制
在此小编再次感谢大家对我的支持,需要更多相关资料,视频请加群点击进入1045267283