JavaScript中this关键字的四种调用规则详解
本文详细解析JavaScript中this关键字的四种核心调用规则:全局函数调用、对象方法调用、事件处理中的隐式绑定以及构造函数调用。通过对比不同场景下this指向的变化,结合jQuery示例与apply/call方法,帮助开发者避免常见的上下文错误,编写更健壮的代码。
全局函数调用中的this指向
JavaScript函数调用规则一
(1)全局函数调用:
代码如下:
function makeArray( arg1, arg2 ){
return [this , arg1 , arg2 ];
} 这是最常用的函数定义方式。熟悉JavaScript的人对其调用方式应不陌生。
调用代码如下:
makeArray('one', 'two');
// => [ window, 'one', 'two' ]
此种方式属于全局函数调用。
为何称之为全局函数?
因为它是全局对象window的一个方法,
我们可以通过以下方式验证:
alert( typeof window.methodThatDoesntExist );
// => undefined
alert( typeof window.makeArray);
// => function
因此,我们之前的调用方式与下述调用等价:
window.makeArray('one', 'two');
// => [ window, 'one', 'two' ]
对象方法调用与事件处理陷阱
JavaScript函数调用规则二
(1)对象方法调用:
代码如下:
//creating the object
var arrayMaker = {
someProperty: 'some value here',
make: makeArray
};
arrayMaker.make('one', 'two'); // => [ arrayMaker, 'one', 'two' ]
//或者采用以下调用方式:
arrayMaker['make']('one', 'two'); // => [ arrayMaker, 'one', 'two' ] 此处与前例的区别在于,this的值指向了对象本身。
或许你会质疑:原始函数定义未变,为何this会变化?
提出疑问是合理的。这涉及JavaScript中函数的传递机制,
在JavaScript中,函数是一种标准数据类型,
确切地说是一个对象。你可以传递或复制它们。
仿佛整个函数连同参数列表和函数体都被复制,
并赋值给arrayMaker中的属性make,这等同于如下定义arrayMaker:
代码如下:
var arrayMaker = {
someProperty: 'some value here',
make: function (arg1, arg2) {
return [ this, arg1, arg2 ];
}
}; 若未弄懂调用规则二,事件处理代码中常会出现各类bug。例如:
代码如下:
<input type="button" value="Button 1" id="btn1" />
<input type="button" value="Button 2" id="btn2" />
<input type="button" value="Button 3" id="btn3" onclick="buttonClicked();"/>
< script type="text/javascript">
function buttonClicked(){
var text = (this === window) ? 'window' : this.id;
alert( text );
}
var button1 = document.getElementById('btn1');
var button2 = document.getElementById('btn2');
button1.onclick = buttonClicked;
button2.onclick = function(){
buttonClicked();
};
< /script> 点击第一个按钮将显示”btn1”,因为这是方法调用,this指向所属对象(按钮元素)。
点击第二个按钮将显示”window”,因为buttonClicked是被直接调用的(非obj.buttonClicked()形式),
这与第三个按钮将事件处理函数直接置于标签内的情况一致。因此,点击第三个按钮的结果与第二个相同。
故请大家注意:
代码如下:
button1.onclick = buttonClicked;
button2.onclick = function(){
buttonClicked();
}; 两者的this指向存在差异。
使用jQuery和apply/call重置this上下文
JavaScript函数调用规则三
若使用jQuery库,则无需过多考虑,它会重写this的值以确保其包含当前事件源元素的引用。
代码如下:
//使用jQuery
$('#btn1').click( function() {
alert( this.id ); // jQuery ensures 'this' will be the button
}); 那么jQuery是如何重载this的值呢?
答案是:call()和apply();
随着函数使用增多,你会发现所需的this可能不在相同的上下文中,这会导致通信困难。
在Javascript中函数也是对象,函数对象包含一些预定义的方法,其中两个便是apply()和call(),我们可以使用它们来对this进行上下文重置。
代码如下:
<input type="button" value="Button 1" id="btn1" />
<input type="button" value="Button 2" id="btn2" />
<input type="button" value="Button 3" id="btn3" onclick="buttonClicked();"/>
< script type="text/javascript">
function buttonClicked(){
var text = (this === window) ? 'window' : this.id;
alert( text );
}
var button1 = document.getElementById('btn1');
var button2 = document.getElementById('btn2');
button1.onclick = buttonClicked;
button2.onclick = function(){
buttonClicked.call(this); // btn2
};
< /script> 构造函数调用与new运算符的重要性
JavaScript函数调用规则四
(1)构造器
此处不深入探讨JavaScript中类型的定义,但此刻需知JavaScript中没有类,
且任何自定义类型需要一个初始化函数。使用原型对象(作为初始化函数的一个属性)定义类型也是不错的选择,
让我们创建一个简单的类型
代码如下:
//声明一个构造器
function ArrayMaker(arg1, arg2) {
this.someProperty = 'whatever';
this.theArray = [ this, arg1, arg2 ];
}
// 声明实例化方法
ArrayMaker.prototype = {
someMethod: function () {
alert( 'someMethod called');
},
getArray: function () {
return this.theArray;
}
};
var am = new ArrayMaker( 'one', 'two' );
var other = new ArrayMaker( 'first', 'second' );
am.getArray();
// => [ am, 'one' , 'two' ]
other.getArray();
// => [ other, 'first', 'second' ] 一个非常重要且值得注意的点是函数调用前的new运算符。若无此运算符,函数将如同全局函数,且我们创建的那些属性都将是创建在全局对象上(window),而这并非你所愿。
另一点,由于构造器内无返回值,若忘记使用new运算符,将导致部分变量被赋值为undefined。
因此,构造器函数以大写字母开头是一个好习惯,这可作为提醒,让你在调用时不忘记前置new运算符。
这样,初始化函数内的代码与你其他语言中编写的初始化函数相似。this的值将是你即将创建的对象。
总结
我希望通过这些内容帮助你理解各种函数调用方式的不同,
使你的JavaScript代码远离bug。
知晓this的值是你避免bug的第一步。
5款主流JS在线运行工具对比:CodePen、JSFiddle与StackBlitz怎么选
2026-11-05 17:04:04
JavaScript入门书籍避坑:这些书不适合初学者
2026-11-05 16:31:15
JS使用Math.round实现保留两位小数的原理与代码
2026-11-05 15:35:55
JavaScript 原生 Date 对象怎么实现日期加减
2026-11-05 14:30:00
JavaScript函数定义的三种方式:声明、表达式与箭头函数
2026-11-05 13:50:55
