本文转自《JavaScript设计模式与开发实践》曾探著 第二章
this的指向大致可以分为以下4种
- 作为对象的方法调用
- 作为普通函数调用
- 构造器调用
- Function.prototype.call 或 Function.prototype.apply 调用
1.作为对象的方法调用
当函数作为对象的方法被调用时, this指执向该对象:
var obj = {
a: 1,
getA: function() {
alert(this == obj) //true
alert(this.a) //1
},
}
obj.getA()
2.作为普通函数调用
当函数不作为对象的属性被调用时, 也就是我们常说的普通函数方式, 此时的this 总是指向全局对象。在浏览器的JavaScript里, 这个全局对象是window对象。
window.name = 'globaName'
var getName = function() {
return this.name
}
console.log(getName()) //globaName
或者:
window.name = 'globaName'
var myObject = {
name: 'sven',
getName: function() {
return this.name
},
}
var getName = myObject.getName
console.log(getName()) //globaName
有时候我们会遇到一些困扰, 比如在div节点的事件函数内部, 有一个局部的callback方法,callback被作为普通函数调用时, callback内部的this指向了window, 但我们往往是想让它指向该div节点, 见如下代码:
<html>
<body>
<div id="div1"></div>
</body>
<script>
window.id = 'window'
document.getElementById('div1').onclick = function() {
alert(this.id) //'div1'
var callback = function() {
alert(this.id) //'window'
}
callback()
}
</script>
</html>
此时有一种简单的解决方案, 可以用一个变量保存div节点的引用:
document.getElementById('div1').onclick = function() {
var that = this //保存div的引用
var callback = function() {
alert(that).id) //'div1'
}
callback()
}
3.构造器调用
JavaScript中没有类, 但是可以从构造器中创建对象, 同时也提供了new运算符, 使得构造器看起来更像一个类。 除了宿主提供的一些内置函数, 大部分JavaScript函数都可以作为构造器使用。构造器 的外表跟普通函数一模一样, 它们的区别在于被调用的方式。当用new运算符调用函数时, 该 函数总会返回一个对象, 通常情况下, 构造器里的this就指向返回的这个对象, 见如下代码:
var MyClass = function() {
this.name = 'sven'
}
var obj = new MyClass()
alert(obj.name) //sven
但用new调用构造器时, 还要注意一个问题, 如果构造器显式地返回了一个object类型 的对象, 那么此次运算结果最终会返回这个对象, 而不是我们之前期待的this:
var MyClass = function() {
this.name = 'sven'
return { //显式地返回一个对象
name: 'anne',
}
}
var obj = new MyClass()
alert(obj.name) //anne
如果构造器不显式地返回任何数据, 或者是返回一个非对象类型的数据, 就不会造成 上述问题:
var MyClass = function() {
this.name = 'sven'
return name: 'anne'
}
var obj = new MyClass()
alert(obj.name) //sven
4.Function.prototype.call 或 Function.prototype.apply 调用
跟普通的函数调用相比, 用Function.prototype.call 或Function.prototype.apply 可以动态地改变传入函数的this:
var obj1 = {
name: 'sven',
getName: function() {
return this.name
},
}
var obj2 = {
name: 'anne',
}
console.log(obj1.getName()) // sven
console.log(obj1.getName().call(obj2)) // anne
call和apply方法能够很好地体现JavaScript的函数式语言特性, 在JavaScript中, 几乎每一次编写函数式语言风格的代码, 都离不开call和apply。