JavaScript开发中this给程序员挖的坑,你遇到过吗?
对于程序员来说,this这个关键字应该是再熟悉不过了,在C++、C#以及Java中,它的身影随处可见,this也可以说是编程语言JavaScript的精髓,但是一定也有不少JavaScript开发者都遇到过this的陷阱。
在C++、C#、Java中,this拥有十分明确的含义,就是单纯指向当前的对象实例,但是,在动态编程语言JavaScript中,相同的this写法,却有不同的含义。
JavaScript中的this代表函数运行时自动生成的一个内部对象,只能在函数内部使用。并且,你不能在创建统计this的时候就确定它,而应该在函数执行时进行确定,所以,一不留神,你就会掉进意想不到的坑!
0、谁调用了就谁来负责
我们先来看看代码:
var name = 'a';
var obj = {
name: 'b',
getName: function() {
console.log(this.name);
}
};
obj.getName(); // b
var getName = obj.getName;
getName(); // a
var obj2 = (function() {
return function() {
console.log(this.name);
}
})();
obj2(); // a
首先,obj.getName()打印出来b,因为,obj调用了getName(),所以其this指向obj,this.name就是b。
其次,getName()打印出a的原因:理由是此时的obj并不调用getName(),而是全局变量window,因此,结果是a
最后,obj2中,因为采用了立即执行函数,它返回一个函数,而当我们调用时,调用它的也是全局变量window,所以打印结果也是a。
需要注意的是,匿名函数内的this是指向window的,更准确的说是指向调用者。
1、必须了解new的过程
function Test() {
console.log(this.name);
}
Test(); // a
var test = new Test(); // undefined
function Test2() {
this.name = 'c';
}
var test2 = new Test2();
console.log(test2.name); // c
为什么这个例子最终打印出来的是c呢?这里new的过程不可忽略,new Test2() 其实执行了三步动作:
首先,创建一个空对象obj(var obj = {};),然后,将这个空对象的[[Prototype]](__proto__)成员指向了Test2函数对象prototype成员对象最后,将Test2函数对象的this指针替换成obj:
obj.__proto__ = Test2.prototype;
Test2.call(obj);
当没有显式返回值或者返回为基本类型、null时,默认将 this 返回(参考2)
因此,在这个例子中,当你使用new的时候,函数内部的this指向已经改变了,不再指向window。
主要应该搞清楚new的过程,然后就知道打印出c的原因了。
2、奇怪的return
看过上面的例子后,你是否觉得已经掌握了new的函数内的this指向?千万别掉以轻心,在JavaScript中,多的是例外,如:
function Test3() {
this.name = 'd';
return {};
}
var test3 = new Test3();
console.log(test3.name); // undefined
function Test4() {
this.name = 'd';
return 1;
}
var test4 = new Test4();
console.log(test4.name); // d
可以再试试return 'd' | null | undefined中的一个或更多类型。
结论:如果return的是一个对象(null除外),那么this指向的这个对象,否则this依旧指向实例对象。