关于 apply, call, bind, this
这个话题在网上的讨论有很多,本文仅为浅析及重点备注。
apply,call,bind 三者的主要作用是为了改变函数中使用的this的指向。
那么问题来了:
为什么要改变this 的指向呢?
这就谈论到了ES5了,在ES5中,this的指向,始终指向最后调用它的对象。
如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var name = "windowsName";
function tFun() {
var name = "Cherry";
console.log(this.name); // windowsName
console.log("inner:" + this); // inner: Window
}
tFun();
console.log("outer:" + this) // outer: Window
//tFun() 相当于是隐式调用 window.tFun() 所以最后调用的对象是 window。
var name = "windowsName";
var obj = {
name: "Cherry",
fn : function () {
console.log(this.name); // Cherry
}
}
obj.fn();
// obj.fn() 为 对象obj 调用,所以log 的是 Cherry
以上为使用对象调用时的方式, 那么我们知道对象是可被赋值/调用的。
被赋值或调用时,会出现什么状况:
1
2
3
4
5
6
7
8
9
10
11
var name = "windowsName";
var obj = {
name : null,
// name: "Cherry",
fn : function () {
console.log(this.name); // windowsName
}
}
var another = obj.fn;
another();
当对象obj的函数fn赋值到another 时,尚未被 调用,another() 相当于 window.another(),所以this指向的最后调用它的对象应该是 window
怎样改变this的指向呢?
- 使用ES6中的箭头函数
- 箭头函数的 this 始终指向函数定义时的 this,而非执行时。
- 临时变量赋值 _self = this
- 使用apply、call、bind
- new 一个对象
如何使用apply,call,bind?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var name = 'windowname';
var obj = {
name : 'objname',
objFunApply: function(){
setTimeout(function(){
console.log(this.name)
}.apply(obj),100)
},
objFunCall: function(){
setTimeout(function(){
console.log(this.name)
}.call(obj),100)
},
objFunBind: function(){
setTimeout(function(){
console.log(this.name)
}.bind(obj),100)
}
}
obj.objFunApply()
obj.objFunCall()
obj.objFunBind()
apply,call,bind的区别
apply的调用方式:
1
fun.apply(thisArg, [argsArray])
- thisArg 为指定的this
- argsArray 为参数数组
call 的调用方式:
1
fun.call(thisArg[, arg1[, arg2[, ...]]])
- thisArg 为指定的this
- arg1 , arg2,…. argn 为 若干个参数
bind 的调用方式:
- 按照MDN的说明: bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
如:
1
2
3
4
5
6
7
8
9
10
11
12
var name = "windowname";
var obj = {
name: "objname",
objFun: function(value1, value2) {
console.log(value1, value2);
}
};
var another = obj.objFun;
another.apply(obj, [1, 2]);
another.call(obj, 1, 2);
another.bind(obj,1,2)()