基本原则:
1,普通函数的 this 是在调用时决定的,它的值取决于函数的调用方式。
当一个普通函数作为对象的方法被调用时,this 将引用该对象。
当一个普通函数独立调用时,this 的值将取决于函数执行环境。
2,构造函数中:当函数作为构造函数使用时,"this"指向新创建的对象。
3,箭头函数,没有自己的 this 绑定,而是继承外部作用域的 this 值。而不是由函数调用方式决定的。跟写代码时的位置关系比较大。
详解:
1,全局环境下:在全局作用域中,函数被直接调用时,"this"指向全局对象。例如:
console.log(this); // 指向全局对象(如浏览器中的"window"对象)
2,对象方法中:当函数作为对象的方法被调用时,"this"指向该对象。例如
const obj = {
name: "Alice",
sayHello: function() {
console.log("Hello, " + this.name);
}
};
obj.sayHello(); // 输出:Hello, Alice
3,构造函数中:当函数作为构造函数使用时,"this"指向新创建的对象。例如:
function Person(name) {
this.name = name;
}
const person = new Person("Bob");
console.log(person.name); // 输出:Bob
4,使用"call"或"apply"方法:可以使用"call"或"apply"方法显式地设置函数的上下文,并将"this"指向指定的对象。例如
function sayHello() {
console.log("Hello, " + this.name);
}
const obj = { name: "Charlie" };
sayHello.call(obj); // 输出:Hello, Charlie
5,箭头函数不同于普通函数,它没有自己的 this 绑定,而是继承外部作用域的 this 值。而不是由函数调用方式决定的。跟写代码时的位置关系比较大。
<!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>
let this_general = null;
let this_arrow = null;
let obj = {
name: 'Alice',
greet: function () {
this_general = this; //由于greet函数是以对象的方法被调用的即obj.greet(),所以this指向obj对象
setTimeout(() => {
//箭头函数中this继承外部作用域中的this,外部作用域是greet函数,也就是继承greet函数中的this,
//greet函数是以对象的方法被调用的,所以greet函数中的this指向obj对象,所以箭头函数中的this也指向obj对象。
this_arrow = this;
}, 1000);
}
};
obj.greet();
setTimeout(() => {
console.log(this_general); //输出对象obj
console.log(this_arrow); //输出对象obj
console.log(this_general === this_arrow); //true
}, 2000);
</script>
</body>
</html>
6,重点难点,搞明白下边5种情况,看注释,主要是搞明白外层作用域!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- <script src="./vue.js"></script> -->
</head>
<body>
<script>
let a = 1;
{
let a = 2;
let b = {
a: 3,
c: {
a: 4,
d: function () { //第1种情况
//这里输出2。而不是1、3、4,可见,这里的作用域是和“let a = 2;”相同的。也就是说对象b和c并不是作用域。
console.log('函数f输出的a:', a);
//由于此函数不是箭头函数,当函数作为对象中的方法被调用时this指向该对象,所以这里的this指向对象{a: 4, d: ƒ, f: ƒ},即对象b.c。
console.log('函数d输出的this:', this);
},
f: () => { //第2种情况
//这里输出2。而不是1、3、4,可见,这里的作用域是和“let a = 2;”相同的。也就是说对象b和c并不是作用域。
console.log('函数f输出的a:', a);
//在箭头函数中,this 的值是由外层作用域决定的(写代码位置的外层作用域),而不是由函数调用方式决定的。
//那外层作用域是哪里呢?我们把这里的this改成a,输出一下就知道作用域了,改成a后输出是2,可见这里的作用域是和“let a = 2;”相同的。也就是说对象b和c并不是作用域。
//所以这里的this,就继承了“let a = 2;”那里的this,由于那里的this指向的是Window对象,所以这个箭头函数的this也指向Window对象
console.log('函数f输出的this:', this);
},
//第3情况。这里的this指向Window对象。因为b.c.g不是对象中的方法(因为它根本不是方法),所以这里的this 的值是由外层作用域决定的(写代码位置的外层作用域)。
//那外层作用域是哪里呢?我们把这里的this改成a,输出一下就知道作用域了,改成a后输出是2,可见这里的作用域是和“let a = 2;”相同的。也就是说对象b和c并不是作用域。
//所以这里的this,就继承了“let a = 2;”那里的this,由于那里的this指向的是Window对象,所以这个箭头函数的this也指向Window对象
g: this,
},
}
b.c.d(); //见第1种情况的注释 this指向对象{a: 4, d: ƒ, f: ƒ},即对象b.c
b.c.f(); //见第2种情况的注释 this指向Window对象
console.log(b.c.g);//见第3种情况的注释 this指向Window对象
console.log('花括号作用域内的this:', this); //第4种情况,输出Window对象。由于{}花括号只是一个作用域,它并没有自己的this,所以向外找到了全局的Window对象
}
{
let this_general = null;
let this_arrow = null;
let obj = {
name: 'Alice',
greet: function () {
this_general = this; //由于greet函数是以对象的方法被调用的即obj.greet(),所以this指向obj对象
setTimeout(() => {
//第5种情况
//箭头函数中this继承外部作用域中的this,外部作用域是greet函数,也就是继承greet函数中的this,
//greet函数是以对象的方法被调用的,所以greet函数中的this指向obj对象,所以箭头函数中的this也指向obj对象。
this_arrow = this;
}, 1000);
}
};
obj.greet();
setTimeout(() => {
console.log(this_general); //输出对象obj
console.log(this_arrow); //输出对象obj
console.log(this_general === this_arrow); //true
}, 2000);
}
</script>
</body>
</html>
上边5种情况的输出