new new 操作符
new 的原理是什么?通过 new 的方式创建对象和通过字面量创建有什么区别?
在调用new
的过程中会发生四件操作
新建了一个对象
新对象链接到原型对象上
绑定 this
返回这个新对象
1 2 3 4 5 6 7 8 9 10 11 12 function create ( ) { let obj = {}; let Con = [].shift .call (arguments ); obj.__proto__ = Con .prototype ; let result = Con .apply (obj, arguments ); return result instanceof Object ? result : obj; }
关于上面代码的第四条注释:构造函数如果返回原始值,那么这个返回值毫无意义
1 2 3 4 5 6 7 function Test (name ) { this .name = name; return 1 ; }const t = new Test ("zhl" );console .log (t.name );
对于创建一个对象来说,更推荐使用字面量的方式创建对象(无论性能上还是可读性)。因为你使用 new Object()
的方式创建对象需要通过作用域链一层层找到Object
,但是你使用字面量的方式就没这个问题。
instanceof 原理
instanceof
的原理是什么?
instanceof
可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype
1 2 3 4 5 6 7 8 9 function myInstanceof (left, right ) { let prototype = right.prototype ; left = left.__proto__ ; while (true ) { if (left === null || left === undefined ) return false ; if (prototype === left) return true ; left = left.__proto__ ; } }
分析:
首先获取类型的原型
然后获得对象的原型
然后一直循环判断对象的原型是否等于类型的原型,直到对象原型为 null
,因为原型链最终为 null
防抖与节流
之前看到一个很形象的比喻。节流防抖就好比乘电梯,比如 delay 是 10 秒,防抖就是电梯每进来一个人就要等 10 秒再运行,而节流就是电梯保证每 10 秒可以运行一次
手写 call、apply、bind call 实现 1 2 3 4 5 6 7 8 Function .prototype .myCall = function (context, ...args ) { context = context || globalThis; const mySymbol = Symbol ('mySymbol' ) context[mySymbol] = this const result = context[mySymbol](...args) delete context[mySymbol] return result }
apply 实现 1 2 3 4 5 6 7 8 9 Function .prototype .myApply = function (context, args ) { context = context || globalThis; const mySymbol = Symbol ('mySymbol' ) context[mySymbol] = this const result = context[mySymbol](...args) delete context[mySymbol] return result }
bind 实现 1 2 3 4 5 6 Funtion .prototype .myBind = function (context, ...args ) { const fn = this return function (...newArgs ) { return fn.apply (context, args.concat (newArgs)) } }