实现call、alpply、bind

Tags
Published
Author

1.实现 call apply

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数语法:function.call(thisArg, arg1, arg2, …)
//实现apply只要把下一行中的...args换成args即可Function.prototype.myCall = function (context, ...args) { if (typeof this !== "function") { throw new Error("must be invoked with function"); } let fn = Symbol("fn"); // 声明一个独有的Symbol属性, 防止fn覆盖已有属性 let target = context || window; // 若没有传入this, 默认绑定window对象 target[fn] = this; // this指向调用call的对象,即我们要改变this指向的函数 let result = target[fn](...args); //重点代码,利用this指向,相当于context.caller(...args) delete target[fn]; return result;};//测试//变更函数调用者示例function foo(num, string) { console.log(this.name, num, string);}// 测试const obj = { name: "托马斯",};foo.myCall(obj, 1, "2"); // 输出'托马斯' 1 '2'

2.实现 bind

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。 语法: function.bind(thisArg, arg1, arg2, …)
核心要点:
1.对于普通函数,绑定 this 指向
2.对于构造函数,要保证原函数的原型对象上的属性不能丢失
  • bind()除了 this 还接收其他参数,bind()返回的函数也接收参数,这两部分的参数都要传给返回的函数
  • new 会改变 this 指向:如果 bind 绑定后的函数被 new 了,那么 this 指向会发生改变,指向当前函数的实例
  • 需要保留原函数在原型链上的属性和方法
Function.prototype.bind = function (context, ...args) { let self = this; //谨记this表示调用bind的函数 if (typeof self !== "function") { throw new Error("must be invoked with function"); } let fBound = function () { //this instanceof fBound为true表示构造函数的情况。如new func.bind(obj) return self.apply( self instanceof fBound ? self : context || window, args.concat(Array.prototype.slice.call(arguments)) ); }; fBound.prototype = Object.create(self.prototype); //保证原函数的原型对象上的属性不丢失 return fBound;};////测试const obj = { name: "托马斯" };function foo() { console.log(this.name); console.log(arguments);}foo.myBind(obj, "a", "b", "c")(); //托马斯 ['a', 'b', 'c']

3.实现 new 关键字

核心要点:
  1. 创建一个全新的对象
  1. 这个对象的proto要指向构造函数的原型对象
  1. 执行构造函数
  1. 构造函数返回值为 object 类型则作为 new 方法的返回值返回,否则返回上述全新对象
function myNew(fn, ...args) { // 把obj挂原型链上 let obj = Object.create(fn.prototype); // 执行构造方法, 并为其绑定新this, 这一步是为了让构造方法能进行this.name = name之类的操作 let res = fn.apply(obj, args); return typeof res === "object" ? res : obj;}// new 创建一个对象,关联原型,执行构造函数,依据执行结果被返回不同的值function newFactory() { const object = new Object(); const constructor = Array.prototype.shift.apply(arguments); object.__proto__ = constructor.prototype; const res = constructor.apply(object, arguments); return typeof res === "object" ? res : object;}