JS中的this指向问题,及解决方法
问题
function A() {}
A.prototype.fna = function() {
console.log(this);
}
this指向
var a = new A();
a.fna(); // A {}
var fnt = a.fna;
fnt(); // window {...}
以及
1
2
3
4
5
6
7
8
9
10
11
12
13
14function A() {
this.name = 'A';
}
A.prototype.fna = function() {
return this.name;
}
function sayName(fn) {
console.log(fn());
}
sayName(a.fna); //undefined
sayName(a.fna.bind(a)); //A
再来一波
- 当this关键字在一个声明对象内部使用,其值会被绑定到调用该this的函数的最近的父对象。
1
2
3
4
5
6
7
8
9var person = {
first: 'John',
last: 'Smith',
full: function() {
console.log(this.first + ' ' + this.last);
}
};
person.full();
// 输出 'John Smith'
在被声明的对象person中的full函数里面使用了this, 那么调用this的full函数的最近的父对象就是person, 因此,this指向person。
多层嵌套中依旧生效
- new关键字,this直接绑定到这个新对象。
call, bind, 和apply
call()第一个参数是this需要绑定的对象,剩下的是add函数本来的参数。
add.apply()也类似,除了第二个参数是一个数组.
bind()函数和call()类似,但是bind()函数不会立即被调用。bind()函数会返回一个函数,并且将this绑定好。
1
2
3
4
5
6
7
8
9
10
11
12
13var small = {
a: 1,
go: function(b,c,d){
console.log(this.a+b+c+d);
}
}
var large = {
a: 100
}
small.go(2, 3, 4);
// 输出 10
想使用large.a的值,可以使用call/apply:
small.go.call(large, 2, 3, 4);
// 输出 109
现在还不知道这三个参数应该传入什么值,可以使用bind:
var bindTest = small.go.bind(large, 2);
将bindTest在控制台下打印出来,我们会看到:
console.log(bindTest);
// 输出 function (b,c,d)
该函数已经将this绑定到large对象,并且传入了第一个参数b。所以,我们接下来是需要传入余下的参数即可
bindTest(3, 4);
// 输出 109
箭头函数(->)
无法得到预期
1
2
3
4
5
6
7
8
9
10var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = function () {
return new Date().getFullYear() - this.birth; // this指向window或undefined
};
return fn();
}
};
箭头函数修复了this指向
1
2
3
4
5
6
7
8
9var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
return fn();
}
};
obj.getAge(); // 25
结论
- this的值通常是由当前函数的执行环境所决定;
- 在全局作用域,this指向全局对象 (window对象);
- 当使用new关键字声明,this指向新建对象;
- 我们可以使用call(), bind(), apply()来设置this;
- 箭头函数会绑定this。