参考
《JavaScript 设计模式与开发实践》
前言
JavaScript 的 this 总是指向一个对象,这个对象就是运行时局域函数的执行环境来动态绑定。
this 指向的四种情况
- 作为对象的方法调用
- 作为普通函数(方法)调用
- 构造器(构造函数)调用
- call 和 apply 的调用
作为对象的属性方法被调用
作为对象的方法被调用的时候,this 指向该对象。
一个实例
var obj = {
name:"张三",
//getName 此时是对象 obj 的一个属性(方法)
getName:function(){
alert(this.name);
}
}
//张三
obj.getName();
作为普通函数被调用
当函数不是作为对象属性被调用的时候,就是作为普通函数被调用。此时 this 指向全局对象,在浏览器环境中就是 window 对象
一个实例
window.name = "张三";
var obj = function(){
alert(this.name);
}
//张三
obj();
一个容易出错的地方
window.name = "全局对象";
var obj = {
name:"属性对象",
getName:function(){
alert(this.name);
}
}
var obj2 = obj.getName();
//属性对象
obj2;
var obj3 = obj.getName;
//全局对象
obj3();
分析:对于 obj2 ,我们把 obj 的方法 getName()赋给了 obj2 , 我们知道方法也是对象,所以是可以这样进行的,因为赋值本身是对象属性的调用,所以 this 指向对象。而对于 obj3,因为 是把 obj.getName 的指针赋给了 obj3 (如果函数没有加圆弧括号是指函数指针),所以, obj3 此时作为普通函数的函数名,所以 this 指向全局对象。
另一个容易出错的地方
比如我们对某个 元素进行操作的时候(比如一个点击事件),如果我们相对这个操作执行一个回调函数,但是此时回调函数是一个普通函数,它的 this 指向 window 对象,而不是我们想要的 这个元素节点,我们怎么办呢,通过一个实例来了解。
//window 可以不要,因为默认是 window
window.id = 'window';
document.getElementById("div1").onclick = function(){
// 弹出警告框 div1
alert(this.id);
var callback = function(){
alert(this.id);
}
// 弹出警告框 window
callback();
}
正式因为 callback( ) 函数不是某个对象的属性,所以调用全局,但是我们往往希望是调用 “这个” 元素结点,所以有下面的改进方式。
//window 可以不要,因为默认是 window
window.id = 'window';
document.getElementById("div1").onclick = function(){
// 弹出警告框 div1
alert(this.id);
var improve = this;
var callback = function(){
alert(improve.id);
}
// 弹出警告框 div1
callback();
}
我们把这个函数的 this 付给一个变量 improve,然后后面在 callback ()中调用 improve 就可以解决这个问题了。
作为构造器(构造函数)被调用
构造函数和普通函数的区别在于,调用的时候,构造函数是通过 new 关键字调用
默认情况下,构造函数会自动返回一个对象,而 this 就是指向这个对象的。
一个实例
var con = function(){
this.name = "构造函数";
}
//构造函数调用
var obj = new con();
//弹出警告框 构造函数
alert(obj.name);
注意:如果在构造函数中显式的 return 一个对象,那么将调用这个显式的内容
var con = function(){
this.name = "构造函数";
return this.name = "这个是显式调用"
}
var obj = new con();
alert(obj.name);
call 和 apply
在借用构造函数的继承方式中(当然还有其他继承的方式)我们使用 call 和 apply 来在子类中调用父类,这个时候就要用到 call 或者 apply 的方法中的 this 上下文,这里不展开说明,有兴趣的同学可以参考《JavaScript 高级教程-继承》的章节。