揭秘 JS 之 call、apply、bind
定义
call()
、apply()
、bind()
都是用来重定义this
这个对象的。
var name = 'jay'
var obj = {
name: 'bob',
say: function (a, b) {
console.log(this.name)
console.log(a, b)
}
}
var obj2 = {
name : 'mary'
}
obj.say.apply(null) // jay 指向window
obj.say.apply(obj2) // mary
obj.say.call(obj2) // mary
obj.say.bind(obj2)() // mary 返回函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
以上bind
方法后面多了个()
外,结果返回都一致。
由此得出结论,apply
、call
都是直接执行指定的函数,bind
是返回一个新的函数,你必须重新调用才会被执行。
call
apply
bind
传参对比
obj.say.call(obj2, 'a', 'b') // a, b
obj.say.apply(obj2, [1, 2]) // 1, 2
obj.say.bind(obj2, 1, 2)() // 1, 2
obj.say.bind(obj2, [1, 2]])()// [1, 2] undefined
1
2
3
4
2
3
4
源码
call
如何实现Function.prototype.MyCall = function (context) {
var newContext = context || window // 缺省指向window
newContext.fn = this // this 指向调用它的函数
var args = [...arguments].slice(1) // 截取除去第一个对象以外的参数
var result = newContext.fn(...args) // 执行函数方法
delete newContext.fn // 执行完毕后,删除函数
return result // 返回函数return的值
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
apply
如何实现Function.prototype.MyApply = function (context, array) {
var newContext = context || window // 缺省指向window
newContext.fn = this
var result
if (Object.prototype.toString.call(array) === '[object Array]') {
result = context.fn(...array)
delete context.fn
return result
} else {
result = context.fn();
}
delete context.fn
return result
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
bind
如何实现Function.prototype.MyBind = function (context) {
context.fn = this
var args = [...arguments].slice(1)
return function () {
var result = context.fn(...args)
delete context.fn
return result
}
}
obj.say.MyBind(obj2, 1, 2)() // 1, 2
obj.say.MyBind(obj2, [1, 2])() // [1, 2], undefined
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12