本文深入解析JavaScript中this关键字的指向规则。通过全局函数、事件处理函数及对象方法三种场景,阐明this始终指向调用者的核心逻辑。重点剖析DOM事件绑定中赋值与引用的区别,并介绍利用apply和call手动改变this指向的方法,帮助开发者避免常见误区。
首先抛出一个核心结论:在JavaScript中,this关键字始终指向函数(或方法)的调用者。
全局函数中的this指向
全局函数场景
参考以下代码示例:
function introduce() {
alert("Hello, I am Laruence\r\n");
}针对上述定义的函数,我们需要确定this关键字的具体指向。
正如前文关于JavaScript作用域的讨论所述,定义在全局作用域下的函数,其所有者即为当前页面环境,也就是window对象。
因此,我们将函数名用引号包裹起来进行描述,是因为在全局作用域定义的函数,本质上就是window对象的一个方法属性。
基于此,我们既可以直接通过函数名进行调用,也可以通过window.方法名的方式进行调用。在这两种调用方式下,函数内部的this关键字均指向其所有者,即window对象。
若我们直接查看window对象的introduce属性,将会得到如下结果:
代码示例如下:
var name = "I am Laruence";
function introduce() {
alert(this.name);
}
alert(window.introduce);观察上述代码,读者可能会产生疑问:既然全局函数是window对象的方法,而全局变量又是window对象的属性(如JavaScript作用域章节所述),那么在全局函数内部是否可以通过this关键字来访问这些全局变量?
答案是肯定的。当调用introduce函数时,通过this.name即可获取到全局变量name的值,从而输出"I am Laruence"。
事件处理函数中的this机制
事件处理函数场景
对于this关键字的困惑,很大程度上源于将函数用作事件处理程序时的行为差异。
HTML代码示例:
<input id="name" type="text" name="name" value="Laruence" />例如,我们需要在点击id为"name"的输入框时,显示该输入框的value值。对应的JavaScript代码可以编写如下:
function showValue() {
alert(this.value);
}
document.getElementById('name').onclick = showValue;上述代码运行正常,但为何如此?前文提到this指针永远指向函数所有者,且全局函数的所有者是window对象,这里似乎存在矛盾。
若能提出此疑问,说明读者进行了深入思考;否则建议重新阅读前文,以免产生误解。
确实,showValue函数定义在全局对象中,问题的关键在于onclick事件绑定的机制。
在JavaScript中,一切皆对象,函数和方法也是对象的属性,区别仅在于函数具有可执行的内部属性。因此,在上述代码中,对onclick属性赋值处理器时,实际上是将showValue函数引用赋给了id为name的DOM输入框对象的onclick属性。
换言之,我们将showValue函数“复制”(引用)给了name输入框对象的onclick属性。若此时查看该onclick属性,会发现:
代码验证如下:
function showValue() {
alert(this.value);
}
document.getElementById('name').onclick = showValue;
alert(document.getElementById('name').onclick);因此,当点击事件触发时,程序会调用name输入框的onclick方法。此时,this关键字自然指向触发事件的DOM元素,即name输入框本身。
然而,存在一种容易混淆的写法:
HTML内联事件代码:
function showValue() {
alert(this.value);
}
<input id="name" type="text" name="name" value="Laruence" onclick="showValue()"/>这种写法往往无法按预期运行,原因何在?
关键在于,此处并非赋值操作,而是引用传递。
对比两种onclick的写法,前一种方式使用的是:
dom.onclick = showvalue; // 注意:没有调用括号()
而后一种方式使用的是:
onclick = "showvalue()" // 注意:包含调用括号()
这一差异侧面反映了两者的本质区别:前者是赋值(将函数对象赋给属性),后者是引用(字符串形式的代码执行)。若此时查看输入框的onclick属性,执行:
alert(dom.onclick);
观察返回结果即可理解差异所在。
此处分享一个有趣的示例,建议在IE浏览器环境下测试:
<img src="xxx" onerror="alert(1); function hi() { alert(2); }" />
手动改变this指向的方法
改变this指向的方法
既然明确了this指向的原理,我们该如何主动控制this的指向目标?
针对上述事件处理函数的场景,可采用以下几种写法:
dom.onclick = showValue(); dom.onclick = function() { alert(this.value) ;} <input onclick="alert(this.value);" /> // 注意前文引用的嵌入方式 dom.addEventListener(dom, showValue, false); // 仅Firefox支持
在非事件处理函数的场合,可以使用apply或call方法来手动改变this关键字的指向。
具体示例如下:
代码实现:
var laruence = {
name : 'laruence',
age : 26,
position : 'Senior PHP Engineer',
company : 'Baidu.inc'
};
function introduce() {
alert(this.name);
}
introduce.call(laruence);