call
简单来说
call()方法在将函数的第一个参数值指定到 this 和剩余参数指定的情况下调用某个函数或方法。
使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var foo = { name: "lilei", }; function bar(a, b) { console.log(this, a, b); }
bar.call(foo, 1, 2);
bar.call(foo);
bar.call(); bar.call(null); bar.call(undefined);
|
模拟实现
call 方法的模拟实现需要明白 call 的原理:
- this 指向的改变
- call 函数中执行调用的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| Function.prototype.myCall = function (context, ...args) { if (context === null || context === undefined) { context = window; } else { context = Object(context); } context.fn = this; delete context.fn(...args); return; }; var foo = { name: "lilei", }; function bar(a, b) { console.log(this, a, b); } bar.myCall(foo, 1, 2); bar.myCall(foo); bar.myCall(); bar.myCall(null); bar.myCall(undefined); bar.myCall(23, 24);
|
apply
apply 的使用与 apply 基本一致,两者之间的区别:apply 的第二个参数是数组[arg1,arg2,arg3,…],call 的第二个参数是列表(arg1,arg2,arg3,…);
使用示例:
1 2 3 4 5 6 7 8 9 10 11
| var foo = { name: "lilei", }; function bar(a, b) { console.log(this, a, b); } bar.apply(foo, [1, 2]); bar.apply(foo); bar.apply(); bar.apply(null); bar.apply(undefined);
|
模拟实现
1 2 3 4 5 6 7 8 9 10
| Function.prototype.myApply = function (context, args) { if (context === null || context === undefined) { context = window; } else { context = Object(context); } context.fn = this; delete context.fn(args); return; };
|
bind
引用 MDN 中的介绍
bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
由此看出 bind 的特点:
- bind 返回一个新的函数。
- 这个新的函数可以预置参数。
举个例子
1 2 3 4 5 6 7 8
| var foo = { name: "lilei", }; function bar(a, b) { console.log(this, a, b); } var fn = bar.bind(foo, 1, 2); fn();
|
模拟实现
1.实现返回一个函数,并可以传递参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Function.prototype.myBind = function () { var _this = arguments[0]; var args = [].slice.call(arguments, 1); var self = this; return function () { var restArgs = [].slice.call(arguments); var allArgs = args.concat(restArgs); return self.apply(_this, allArgs); }; };
|
- 接下来最重要的一点,bind 返回的函数支持 new 调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| Function.prototype.myBind = function () { var self = this; if (typeof self !== "function") { throw new Error("绑定的目标必须是函数"); } var _this = arguments[0]; var args = [].slice.call(arguments, 1); var fNOP = function () {}; var fBound = function () { var restArgs = [].slice.call(arguments); var allArgs = args.concat(restArgs); return self.apply(this instanceof fBound ? this : _this, allArgs); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; };
|
参考文献
https://github.com/mqyqingfeng/Blog/issues/11