本文全面解析JavaScript中this关键字的指向规则。涵盖全局函数在严格与非严格模式下的差异、对象方法调用的绑定逻辑、构造函数实例化时的this行为、事件处理函数中的目标对象引用,以及ES6箭头函数词法作用下的this继承机制。通过具体代码示例与场景分类,帮助开发者清晰理解不同调用环境对this绑定的影响。
前言
- 前端初学者在掌握JavaScript中this指向时往往感到困惑,特别是在ES6引入箭头函数之前,这一概念更是令人头疼。
- this指向之所以复杂,是因为它并非在定义时确定,而是在代码执行过程中,依据具体的调用环境和上下文动态绑定的。
- 本文旨在系统梳理并总结各种场景下this的指向规律。若文中存在疏漏或错误,欢迎指正与交流。
在深入具体场景之前,先回顾this的基础概念:
- this是JavaScript的关键字,而非普通变量。
- this指向一个对象,具体指向哪个对象或该对象的值为何,取决于函数的调用方式及所处的环境。
- this的指向可通过call、bind、apply等方法进行手动修改。
- 严格模式与非严格模式下,this的绑定行为存在差异。
一、全局普通函数
在非严格模式下,全局普通函数中的this指向window对象。
var a = 0; // 相当于window.a = 0
function testWindow() {
this.a = 1; //相当于window.a
console.log(this.a); //1
console.log(window.a); // 1
console.log(this); //Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
}
testWindow();
而在严格模式下,全局普通函数中的this值为undefined。
var a = 1;
function testStrict() {
"use strict";
console.log(this); //undefined
console.log(this.a); // Uncaught TypeError: Cannot read property 'a' of undefined
}
testStrict();二、对象的函数方法
// 不管是严格模式还是非严格模式,调用对象的函数方法时,被调用函数中的this永远指向这个对象
var a = 2;
var obj = {
a: 1,
b: function () {
console.log(this); //{a: 1, b: ƒ}
console.log(this.a); //1
}
};
obj.b();对上述代码稍作调整,进行一个小练习:
var a = 2;
var obj = {
a: 1,
b: function () {
console.log(this); // indow {window: Window, self: Window, …}
console.log(this.a); // 2
}
};
var foo = obj.b;
foo(); // 相当于window.foo()为何此时this指向了window?
前文已提及,对象中函数的调用,this应指向调用该函数的对象。
此处foo变量接收了obj对象中的b函数,并在全局作用域下执行,这等同于执行window.foo()。
因此,这回归到第一种情况:全局作用域下普通函数调用指向window(非严格模式下)。
三、构造函数
//不管是严格模式还是非严格模式,构造函数中的this都是指向构造函数创建的对象实例
function Test(a) {
this.a = a;
console.log(this.a); //1
}
Test.prototype.say = function () {
console.log(this); //test {a: 1}
console.log(this.a); //1
};
var t = new test(1);
console.log(t); //test {a: 1}
t.say();
四、事件处理函数
<body>
<button id="btn">click</button>
<button id="btn1">click1</button>
<script>
/**
* this指向被绑定的目标对象
* */
var btn = document.getElementById("btn");
btn.onclick = function () {
console.log(this); // <button id="btn">click</button>
this.innerHTML = "loading..";
this.disabled = true;
};
var btn1 = document.getElementById("btn1");
btn1.onclick = () => {
console.log(this); //window
};
</script>
</body>五、内联函数
以下代码展示了严格模式与非严格模式下的不同表现。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button onclick=" alert(this);">内联事件处理0</button> //元素本身即button
<button onclick="alert((function(){'use strict'; return this})());">内联事件处理1</button>
//undefined
<button onclick="alert((function(){ return this})());">内联事件处理2</button>
//window
<button onclick="'use strict'; alert(this.tagName.toLowerCase());">内联事件处理3</button>
//button
</body>
</html>六、全局作用域
全局作用域下的规则较为简单,牢记即可。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
/**
* 不管是严格模式还是不是严格模式this都指向window
* */
"use strict";
console.log(this); // window
</script>
</body>
</html>值得扩展的是,不同运行环境中的全局对象有所不同:
- 浏览器Web环境:window、self、frames
- Node.js环境:global
- Web Worker环境:self
在ES2020标准中,最终定义了globalThis作为在任何上下文中引用全局对象的标准方式。2020年初,所有现代浏览器和Node.js均已实现此特性,具体详情可参考:mdn web_docs。
七、箭头函数
我们将箭头函数单独列出总结,ES6中箭头函数的引入大大简化了this指向的复杂性:
- 箭头函数自身不绑定this;
- 箭头函数的this并非在调用时决定,而是在定义时所处环境就已确定。
- 技巧:判断箭头函数的this,需看外层是否有函数。
- 1). 如果有,外层函数的this即为内部箭头函数的this。
- 2). 如果没有,this指向window。
全局环境下的普通箭头函数始终指向window。
let testES6 = () => {
console.log(this); //Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
};
testES6();
let testES6Strict = () => {
"use strict";
console.log(this); //Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
};
testES6Strict();
在对象中的箭头函数,this指向执行该对象所处的执行上下文(执行环境)。
var obj = {
fun: () => {
console.log(this); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
}
};
obj.fun(); // fun箭头函数外层没有函数,指向window
var obj = {
fun: () => {
"use strict";
console.log(this); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
}
};
obj.fun();
事件处理中的箭头函数,this指向window。
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button id="btn1">click1</button>
<script>
var btn1 = document.getElementById("btn1");
btn1.onclick = () => {
console.log(this); //window
};
</script>
</body>
</html>以上即为JavaScript中this指向的全面总结,更多JavaScript this指向相关内容,敬请关注本站其他文章!