call、apply、bind 实现
1. call 实现
首先我们要知道系统的 call 方法主要实现了什么
先看系统的call方法
function foo() { console.log("foo函数被执行", this); }
function sum(num1, num2) { console.log("sum函数被执行", this); return num1 + num2 }
foo.call({})
foo.call(null)
foo.call("abc")
let res = sum.call("123", 10,20) console.log(res)
|
接下来我们开始实现自己的call(主要是实现思路,没有把所有的边缘条件考虑完全,但是基本都有)
1.1 让函数执行起来
Function.prototype.mycall = function() { let fn = this fn() }
foo.mycall()
|
2.2 显式绑定this
现在我们要绑定我们指定的this
- 先看第一种:
foo.mycall({name: 'hello'})
,绑定一个对象
Function.prototype.mycall = function(thisArg) { let fn = this thisArg.fn = fn thisArg.fn() delete thisArg.fn }
|
Function.prototype.mycall = function(thisArg) { let fn = this thisArg = Object(thisArg) thisArg.fn = fn thisArg.fn() delete thisArg.fn }
|
- 如果传入的是 null / undefined 呢
Function.prototype.mycall = function(thisArg) { let fn = this thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window thisArg.fn = fn thisArg.fn() delete thisArg.fn }
|
2.3 接下来要考虑参数了
Function.prototype.mycall = function(thisArg, ...args) { let fn = this thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window thisArg.fn = fn let result = thisArg.fn(...args) delete thisArg.fn return result }
|
到此,基本的call就已经实现了
检验一下叭
foo.mycall({name: 'hello'}) foo.mycall("123") foo.mycall(undefined) foo.mycall(null)
sum.mycall({name: "hello"}, 10, 20) let res1 = sum.mycall(123, 10, 20) console.log(res1);
|
2. apply 实现
跟 call 类似,只不过参数的处理有不同
Function.prototype.myapply = function(thisArg, argsArray) { let fn = this
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
thisArg.fn = fn argsArray = argsArray || [] let result = thisArg.fn(...argsArray)
delete thisArg.fn return result }
|
3. bind 实现
bind 需要我们返回一个新的函数,并且调用 bind 的时候不需要执行函数
Function.prototype.mybind = function(thisArg, ...args) {
var fn = this
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
function newFn() { thisArg.fn = fn let result = thisArg.fn(...args) delete thisArg.fn return result }
return newFn }
|
大体上也差不多,但我们可以就下面这种情况改进一下
function sum2(num1, num2, num3, num4) { console.log("sum2函数被执行", this); return num1 + num2 + num3 + num4 }
let newSum2 = sum2.mybind("abc", 10,20) console.log(newSum2(30,40));
|
这种情况,我们就需要把两次传入的参数合并起来,再调用
Function.prototype.mybind = function(thisArg, ...args) { var fn = this
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
function newFn(...newArgs) { let allArgs = [...args, ...newArgs]
thisArg.fn = fn let result = thisArg.fn(...allArgs) delete thisArg.fn return result } return newFn }
|
到此,基本的bind也实现了
最后说明一下,实现的思路是这样,但是方法不唯一的,可能还有一些边边角角没有考虑到的话,可以自己添加进去