JavaScript this 关键字指向详解与常见陷阱

作者:函数茶馆时间:2026-10-28 15:11:29浏览:542

本文详细解析JavaScript中this关键字的六种指向场景:构造函数实例、对象方法调用、全局对象、apply/call绑定、回调函数及bind方法。通过代码示例说明不同上下文下的this行为,并提供避免遗漏new关键字及处理闭包中this丢失的实用技巧。

this指向构造函数实例化对象

一、this指向构造函数实例化对象

在前文讨论中,我们对比了使用new关键字与不使用new调用构造函数的区别,具体示例如下:

代码如下:

function Benjamin(username, sex) {
this.username = username;
this.sex = sex;
}
var benjamin = new Benjamin("zuojj", "male");
//Outputs: Benjamin{sex: "male",username: "zuojj"}
console.log(benjamin);
var ben = Benjamin("zhangsan", "female");
//Outputs: undefined
console.log(ben);

当构造函数被当作普通函数调用时,函数没有返回值,且内部的this指向全局对象。为了避免因遗漏new关键字导致的问题,我们可以采取以下措施:

代码如下:

function Benjamin(username, sex) {
//Check whether "this" is a "Benjamin" object
if(this instanceof Benjamin) {
this.username = username;
this.sex = sex;
}else {
return new Benjamin(username, sex);
 }
}
var benjamin = new Benjamin("zuojj", "male");
//Outputs: Benjamin{sex: "male",username: "zuojj"}
console.log(benjamin);
var ben = Benjamin("zhangsan", "female");
//Outputs: Benjamin {username: "zhangsan", sex: "female"}
console.log(ben);

在上述示例中,我们首先检查this是否为Benjamin的实例。如果不是,则自动使用new调用构造函数并返回新实例。这样便无需担心遗漏new关键字。不过,这种做法可能养成不良编码习惯。若要避免此类现象,可以抛出错误,如下所示:

代码如下:

function Benjamin(username, sex) {
//Check whether "this" is a "Benjamin" object
if(this instanceof Benjamin) {
this.username = username;
this.sex = sex;
}else {
// If not, throw error.
throw new Error("`Benjamin` invoked without `new`");
 }
}

this指向调用该函数的对象

二、this指向调用该函数的对象

参考以下示例:

代码如下:

var x = 10;
var obj = {
x: 10,
output: function() {
//Outputs: true
console.log(this === obj);
return this.x;
 },
innerobj: {
x: 30,
output: function() {
//Outputs: true
console.log(this === obj.innerobj);
return this.x;
  }
 }
};
//Outputs: 10
console.log(obj.output());
//Outputs: 30
console.log(obj.innerobj.output());

this指向全局对象

三、this指向全局对象

在讨论构造函数时,我们提到不使用new时this指向全局对象。下面分析两种常见的易错场景:

代码如下:

var x = 100;
var obj = {
x: 10,
output: function() {
(function() {
//Outputs: true
console.log(this === window);
//Outputs: Inner: 100
console.log("Inner:" + this.x);
  })();
  
return this.x;
 }
};
//Outputs: 10
console.log(obj.output());

在使用闭包时,作用域发生变化,this指向window(浏览器环境)。

代码如下:

var x = 100;
var obj = {
x: 10,
output: function() {
return this.x;
 }
};
var output = obj.output;
//Outputs: 10
console.log(obj.output());
//Outputs: 100
console.log(output());
var obj2 = {
x: 30,
output: obj.output
}
//Outputs: 30
console.log(obj2.output());

此时,this始终指向函数调用时的对象。

this指向apply/call()方法指派的对象

四、this指向apply/call()方法指派的对象

代码如下:

var x = 100;
var obj = {
x: 10,
output: function() {
return this.x;
 }
};
//Outputs: 10
console.log(obj.output());
var obj2 = {
x: 40,
output: obj.output
}
//Outputs: 40
console.log(obj.output.call(obj2));
//Outputs: 10
console.log(obj2.output.apply(obj));

callback函数內的this指向

五、callback函数內的this指向调用该callback的函数的this所指向的对象

代码如下:

//<input type="text" value="3" id="txt_username">
$("#username").on("click", function() {
console.log(this.value);
});

Function.prototype.bind中的this

六、Function.prototype.bind中的this

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called. 实例一:

代码如下:

function person() {
return this.name;
}
//Function.prototype.bind
var per = person.bind({
name: "zuojj"
});
console.log(per);
var obj = {
name: "Ben",
person: person,
per: per
};
//Outputs: Ben, zuojj
console.log(obj.person(), obj.per());

实例二:

代码如下:

this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
//Outputs: 81
console.log(module.getX());
var getX = module.getX;
//Outputs: 9, because in this case, "this" refers to the global object
console.log(getX);
// create a new function with 'this' bound to module
var boundGetX = getX.bind(module);
//Outputs: 81
console.log(boundGetX());
作者最新文章