在实际应用中,了解
this
的行为是非常重要的,特别是在编写库或框架时,或者当你需要在回调函数中访问特定的上下文时,通常推荐使用箭头函数或者其他方法来确保this
的正确指向。
在ES6中,this
的值取决于它是如何被调用的。
this
不是一个函数或对象,而是一个特殊的关键字,其值在函数被调用时确定。
以下是在不同场景中 this
的值的概述:
01 全局作用域中的this
在JavaScript中,全局作用域指的是在代码的任何位置都可以访问的、变量和函数的范围。
具体可以这么理解:当你在脚本的顶层(不在任何函数或代码块内部)声明一个变量或函数时,它就在全局作用域中。
在全局作用域中,this
指向全局对象。
在浏览器环境中,全局对象是 window
;
在 Node.js 环境中,全局对象是 global
。
下面是一个在浏览器环境中演示这一点的简单例子:
javascript
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
"use strict"
// 在全局作用域中
console.log(this === window); // 应该输出 true,表示 this 指向 window 对象
console.log(this); // 输出window对象
// 定义一个全局变量
var globalVar = "I am a global variable";
// 使用 this 访问全局变量
console.log(this.globalVar); // 输出 "I am a global variable"
// 使用 window 访问全局变量
console.log(window.globalVar); // 输出 "I am a global variable"
// 定义一个函数,并在全局作用域中调用它
function testFunction() {
console.log(this); // 在浏览器环境中,输出 window 对象,"use strict"下输出undefined
}
testFunction();
</script>
</body>
</html>
在这个例子中,this
在全局作用域中指向 window
对象。我们通过比较 this
和 window
来验证这一点,并且使用 this
和 window
来访问一个全局变量 globalVar
,以证明它们都可以用来访问全局作用域中的变量。
如果你在 Node.js 环境中运行代码,全局对象将是 global
,你可以类似地测试:
javascript
// 在 Node.js 的全局作用域中
console.log(this === global); // 应该输出 true,表示 this 指向 global 对象
// 定义一个全局变量
global.globalVar = "I am a global variable";
// 使用 this 访问全局变量
console.log(this.globalVar); // 输出 "I am a global variable"
// 使用 global 访问全局变量
console.log(global.globalVar); // 输出 "I am a global variable"
// 定义一个函数,并在全局作用域中调用它
function testFunction() {
console.log(this); // 在 Node.js 环境中,输出 global 对象
}
testFunction();
在这个 Node.js 例子中,this
在全局作用域中指向 global
对象,并且我们同样使用 this
和 global
来访问一个全局变量 globalVar
。
02 函数调用中的this
当一个函数不是作为对象的方法调用时(也就是说,它是独立调用的,或者作为回调函数等被调用),this
的值在非严格模式下默认为全局对象(在浏览器中通常是 window
),而在严格模式下它是 undefined
。
下面我将给出两个示例程序来演示这个行为。
首先是非严格模式下的示例:
javascript
// 非严格模式
function exampleFunction() {
console.log(this); // 在非严格模式下,this 指向 window 对象
console.log(this.globalVar); // => I am a global variable
}
exampleFunction();
// 你可以通过检查 window 对象来验证这一点
function setGlobalVar() {
window.globalVar = "I am a global variable";
}
setGlobalVar();
exampleFunction(); // 输出包含 globalVar 的 window 对象
在这个例子中,exampleFunction
不是作为任何对象下的方法调用的,因此在非严格模式下,this
指向 window
对象。
我们在 setGlobalVar
函数中设置了一个全局变量 globalVar
,然后在 exampleFunction
中通过 this
访问它,证明了 this
确实指向 window
。
03 对象方法中的this
当一个函数作为对象的方法被调用时,this
关键字指向调用该方法的对象。下面是一个简单的示例来展示这个行为:
javascript
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>03-对象方法中的this</title>
</head>
<body>
<script>
// 定义一个对象,它有一个方法叫做 greet
const person = {
name: "Alice",
getName: function () {
console.log(this.name);
}
};
// 调用 person 对象的 getName方法
person.getName(); // 输出 "Alice"
// getName中this指向person对象,因为getName是作为 person 的方法被调用的
</script>
</body>
</html>
在这个例子中,getName
函数是 person
对象的一个方法。当我们通过 person.getName()
调用这个方法时,this
关键字在函数内部指向了 person
对象。因此,this.name
访问的是 person
对象的 name
属性,并输出了相应的信息。
04构造函数中的this
当一个函数被用作构造函数,并使用 new
关键字调用时,this
关键字会指向新创建的对象实例。下面是一个简单的例子来说明这个行为:
javascript
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>04-构造函数中的this</title>
</head>
<body>
<script>
// 定义一个构造函数
function Person(name, age) {
this.name = name;
this.age = age;
// 可以添加一个方法来访问实例属性
this.greet = function () {
console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
};
}
// 使用 new 关键字来调用构造函数,创建一个新的对象实例
const alice = new Person('Alice', 25);
alice.greet(); // 输出 "Hello, my name is Alice and I'm 25 years old."
// 验证 this 指向的是 alice 对象
console.log(alice.name); // 输出 "Alice"
console.log(alice.age); // 输出 25
// 创建一个新的对象实例
const bob = new Person('Bob', 30);
bob.greet(); // 输出 "Hello, my name is Bob and I'm 30 years old."
// 验证 this 指向的是 bob 对象
console.log(bob.name); // 输出 "Bob"
console.log(bob.age); // 输出 30
</script>
</body>
</html>
每次使用 new
关键字调用 Person
构造函数时,都会创建一个新的对象实例,并且 this
都会指向那个新对象。这就是为什么 alice
和 bob
有各自独立的 name
和 age
属性,以及它们各自的 greet
方法。
在这个例子中,Person
函数被用作构造函数,因为我们使用 new
关键字来调用它。当构造函数被调用时,JavaScript 会创建一个新的空对象,并将这个新对象的内部链接([[Prototype]]
)设置为构造函数的 prototype
对象。然后,构造函数中的代码执行,其中 this
关键字引用新创建的对象。
因此,当我们设置 this.name
和 this.age
时,我们实际上是在新创建的对象上设置属性。同样,this.greet
方法也是添加到新对象上的一个方法。
05箭头函数中的this
箭头函数在 JavaScript 中是一个非常重要的特性,它提供了一种更简洁的函数书写方式,并且它不绑定自己的 this
,而是继承自包围它的函数或全局作用域的 this
。
这意味着在箭头函数内部,this
的值是在定义箭头函数时确定的,而不是在调用时确定的。
下面是一个简单的示例来说明这个行为:
javascript
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>05-箭头函数中的this</title>
</head>
<body>
<script>
function OuterFunction() {
this.value = 42;
// 这是一个普通函数
function innerFunction() {
console.log(this.value); // 这里的 this 指向 OuterFunction 的实例
}
// 这是一个箭头函数
const arrowFunction = () => {
console.log(this.value); // 这里的 this 继承自 OuterFunction 的实例
};
// 调用普通函数和箭头函数
innerFunction(); // 输出 42
arrowFunction(); // 输出 42
}
const obj = new OuterFunction();
// 当我们在外部调用 innerFunction 时,this 指向全局对象(在浏览器中通常是 window)
// 因此,以下代码会抛出一个错误,因为 this.value 是 undefined
obj.innerFunction(); // Uncaught TypeError: Cannot read property 'value' of undefined
// 但是,箭头函数不会改变它的 this 上下文
// 因此,即使我们在外部调用 arrowFunction,它仍然可以访问 OuterFunction 的 this 上下文
obj.arrowFunction(); // 输出 42
</script>
</body>
</html>
在OuterFunction
中定义了一个普通函数 innerFunction
和一个箭头函数 arrowFunction
。
当 OuterFunction
被调用时,它创建了一个新的对象实例,并且 this
在 innerFunction
和 arrowFunction
中都指向这个新创建的对象。
当我们直接调用 obj.innerFunction()
时,this
指向了全局对象(在浏览器中是 window
),因此 this.value
是 undefined
,导致抛出一个错误。
然而,当我们调用 obj.arrowFunction()
时,即使我们是在外部调用的,arrowFunction
内部的 this
仍然指向 OuterFunction
的实例,因此可以正确地访问 value
属性。这是因为箭头函数不绑定自己的 this
,而是从定义它的上下文中继承 this
。
TODO 嵌套函数
全局函数中的嵌套函数
对象方法中的嵌套函数
总结
场景 | this 的值 |
描述 |
---|---|---|
全局作用域 | window (浏览器) 或 global (Node.js) |
在全局作用域中,this 指向全局对象。 |
函数调用 | undefined (严格模式) 或 window (非严格模式) |
当一个函数不是作为对象的方法调用时,this 的值在非严格模式下是 window ,在严格模式下是 undefined 。 |
对象方法 | 调用该方法的对象 | 当一个函数作为对象的方法被调用时,this 指向调用该方法的对象。 |
构造函数 | 新创建的对象 | 当一个函数作为构造函数使用 new 关键字调用时,this 指向新创建的对象。 |
箭头函数 | 定义时的上下文 | 箭头函数不绑定自己的 this ,它继承自包围它的函数或全局作用域的 this 。 |
事件处理器 | 调用事件处理器的对象 | 在DOM事件处理器中,this 通常指向触发事件的元素。 |
定时器函数 | undefined (严格模式) 或 window (非严格模式) |
在 setTimeout 或 setInterval 的回调函数中,this 的值在非严格模式下是 window ,在严格模式下是 undefined 。 |
Call, Apply, Bind | 指定的对象 | 使用 call 、apply 或 bind 方法可以显式地设置 this 的值。 |
请注意,箭头函数的行为略有不同,因为它们不绑定自己的 this
。相反,它们从定义它们的上下文继承 this
。
希望这个表格能帮助你理解ES6中 this
的不同行为!
在JavaScript中,特别是在ES6及其之后的版本中,回调函数中使用普通函数和箭头函数时,this
的值可能会有所不同。这主要取决于回调函数的调用方式和上下文。以下是普通函数和箭头函数在回调中作为方法使用时 this
的区别:
普通函数
当回调函数是一个普通函数时,this
的值通常取决于该函数如何被调用。如果该函数是作为对象的方法被调用,那么 this
将指向调用该方法的对象。如果该函数是作为回调函数被调用,并且没有使用 call
、apply
或 bind
方法来显式地设置 this
的值,那么 this
可能会指向全局对象(在浏览器中是 window
),或者在没有严格模式的情况下是 undefined
。
例如:
javascript
function Example() {
this.value = 5;
setTimeout(function() {
console.log(this.value); // this 指向全局对象或undefined(严格模式)
}, 1000);
}
const example = new Example(); // 输出可能是 undefined,取决于环境
箭头函数
箭头函数不绑定自己的 this
,它继承自包围它的函数或全局作用域的 this
。这意味着在箭头函数内部,this
的值将始终与包围它的外部函数的 this
保持一致。
因此,当回调函数是箭头函数时,this
将保持外部函数的 this
值,即使回调函数以不同的方式被调用。
例如:
javascript
function Example() {
this.value = 5;
setTimeout(() => {
console.log(this.value); // this 继承自Example函数的this,所以输出5
}, 1000);
}
const example = new Example(); // 输出 5
在这个例子中,即使 setTimeout
是一个全局函数,并且通常会导致回调函数中的 this
指向全局对象,但由于使用了箭头函数,this
仍然保持了 Example
函数的上下文。
总结:在回调函数中,普通函数的 this
值可能会根据回调函数的调用方式而改变,而箭头函数的 this
值则始终与其外部函数的 this
保持一致。因此,在需要确保 this
的值始终为特定上下文时,使用箭头函数通常是更安全的选择。
this不是常量, 它在程序中的不同地方会求值为不同的值。
this是面向对象编程中使用的关键字。在方法体中,this求值为调用方法的对象。
this
在 标准函数 和 箭头函数 中有不同的行为。
1、标准函数中的 this
javascript
window.color = 'red';
// 全局上下文中调用函数时,this 指向 windows
function sayColor() {
console.log(this.color);
}
sayColor(); // 'red'
let o = {
color: 'blue'
};
o.sayColor = sayColor;
o.sayColor(); // 'blue'
2、嵌套函数
嵌套函数普通函数内部的this是全局对象,嵌套箭头函数的this是外层对象的this
注意:vue中相反:vue中嵌套普通函数内部的this是vue,而嵌套箭头函数的this是全局对象
javascript
let o = {
m:function(){
let self = this;
this === o;
console.log('o.m() this:',this);
f();
function f(){
this === o;
self ===o;
console.log('o.m.f() this:',this);
}
const f2 = ()=>{
console.log('o.m.f2() this:',this);
}
f2();
const f3 = (function(){
console.log('o.m.f3() this:',this);
}).bind(this);
f3();
}
}
o.m();
console.log(o);
2、箭头函数中的this
javascript
window.color = 'red';
let sayColor = () => console.log(this.color);
sayColor(); // 'red'
let o = {
color: 'blue'
};
o.sayColor = sayColor;
o.sayColor(); // 'red'
javascript