10-讨论
5.2.3 讨论
$(this) 到底是什么?为什么总是不起作用呢?如果将它分成两部分—— $() 和 this ,就更容易理解。
$() 看上去很神秘,实际上并非如此:它只是一个函数调用。 $ 是对jQuery函数的引用,只是 jQuery() 较为简短的写法而已。它只是返回一个对象的普通JavaScript函数调用。
注意
如果你要使用另一个重新定义
$的JavaScript程序库,就是另外一回事了——之后你就不能在jQuery代码中使用$(),而应该使用jQuery()或者自定义的别名。
this 是jQuery中较容易混淆的特性之一,因为它用在许多不同的方面。在面向对象的JavaScript编程中, this 用于在对象方法中引用该对象,和Python或者Ruby中的 self 类似:
function Foo( value ) {
this.value = value;
}
Foo.prototype.alert = function() {
alert( this.value );
};
var foo = new Foo( 'bar' );
foo.alert(); // 'bar'
在传统 onevent 属性的代码中, this 引用接收事件的元素——但是只在属性中,而不在从属性调用的函数中:
<a href="#" id="test" onclick="clicked(this);">Test</a>
function clicked( it ) {
alert( it.id ); // 'test'
alert( this.id ); // undefined
alert( this === window ); // true (什么?)
}
从第三个 alert() 中可以看到, this 实际上是函数中的 window 对象。由于历史原因,当直接调用函数(也就是说,不是作为对象方法调用)时, window 是 this 的“默认”含义。
在jQuery事件处理程序中, this 是处理事件的DOM元素,所以 $(this) 是用于该DOM元素的一个jQuery包装器。这就是为什么在“问题”代码中 $(this).addClass() 能够按照预期工作的原因。
但是,代码接着调用 setTimeout() , setTimeout() 以直接函数调用的方式工作: this 指的是 window 对象。所以当代码调用 $(this).removeClass() 时,实际上试图从 window 对象中删除类!
为什么将 this 或者 $(this) 复制到一个局部变量中能够解决这个问题?JavaScript为参数和函数的局部变量创建了一个闭包。
闭包初看似乎很神秘,但实际上可以归纳为三条简单的原则:
- 可以在JavaScript函数中嵌套另一个函数,嵌套可以为多级。
- 函数不仅能读写自己的参数和局部变量,而且能读写嵌套函数中的变量。
- 前一条原则始终有效,即使外部函数已经返回之后再调用内部函数也是如此(例如,时间处理程序或者
setTimeout()回调)。
不管函数是命名的还是匿名的,上述原则对所有函数都适用。但是, this 不是函数参数或者局部变量——它是特殊的JavaScript关键字——所以这些原则不适用于它。通过将 this 的值复制到一个局部变量中,就能利用闭包使该值在任何嵌套函数中可用。