概述
首先我们扫一下盲:this
在javascript这门语言中只有在函数内部才有被讨论的价值。
this的指向应该始终由调用方来决定,而不是由定义方决定
。当然我们这篇文章是针对ES5,至于ES6中箭头函数的this指向由定义方决定这种问题我们这里不进行讨论
应用场景分析
1、普通函数调用
普通函数的调用,在非严格模式下this指向window,当然严格模式下修复了指向window这个bug,我们在这儿不在赘述,因为这不是我们这次讨论的范畴。
var name = 'ice';
function foo() {
this.age = 18;
return this.name;
}
foo(); // ice
console.log(age); // 18
2、对象方法调用
- 当作为对象方法调用,this通常指向该对象
var name = 'ace';
function getName() {
return this.name;
}
var obj = {
name: 'ice',
getName: getName
}
obj.getName(); // ice
- 也会有一些“对象方法的调用并未指向该对象”的情况,其实不然,新对象的方法调用时并未继承旧对象的作用域,所以this还是指向新对象,如下:
// 例1
function getName() {
return this.name;
}
var obj = {
name: 'ice',
getName: getName
}
var _obj = {
name: 'ace',
getName: obj.getName
}
_obj.getName(); // ace
// 例2
document.body.onclick = obj.getName;
// 当点击body元素输出:undefined,此时this指向body元素
3、构造函数被调用
作为构造函数时,this指向该构造函数实例化的对象。当然也有奇葩的写法来扰乱我们的视线,即使这样并不会改变this的指向,只是实例的作用域问题,如下例2:
// 例1
function Person() {
this.name = 'ice';
}
var person = new Person();
console.log(person.name); // ice
// 例2
function Person() {
this.name = 'ice';
return {name: 'ace'}
}
var person = new Person();
console.log(person.name); // ace
4、apply、call、bind做主了
apply和call可以在调用期间改变this指向,而bind可以在函数定义期间就可以改变this指向:
// 例1
function getName() {
return this.name;
}
var obj = {
name: 'ice',
getName: getName
}
obj.getName.call({name: 'ace'}) // ace
/**
* obj.getName.apply({name: 'ace'}) // ace
*/
// 例2
function getName() {
return this.name;
}
var obj = {
name: 'ice',
getName: getName.bind({name: 'ace'})
}
obj.getName() // ace
5、setTimeout
我们最后来说一个使用场景很多,但this定位很尴尬的使用方式setTimeout,当作为setTimeout的回调函数时,this指向window(当然是非严格模式),不过我们可以用bind或者参数传递等方法实现功能(例3):
// 例1
var name = 'ice';
setTimeout(function() {
console.log(this.name); // ice
}, 1000)
// 例2
function showTagName() {
console.log(this);
console.log(this.tagName);
}
var obj = {
tagName: 'OBJ',
showTagName: showTagName
}
document.body.onclick = function() {
setTimeout(showTagName, 1000)
// 1、window。2、undefined
}
// 例3
document.body.onclick = function() {
setTimeout(showTagName.bind(this), 1000)
// 1、body元素。2、"BODY"
}
至此我们对于javascript这门语言的this
指向有了一个比较清晰的理解了,其实导致this指向这么杂乱的主要原因是javascript之父(布兰登·艾奇(Brendan Eich,1961年~))只用相当短的时间(10天)创造了这门语言,已经很伟大了,有诸如this这种问题不可避免。
ES6、ES7、ES8、node等都在完善javascript,它依然是当下最流行的脚本语言,所以好好撸吧。