本文主要介绍setTimeout的回调函数的this指向问题
例子1:回调函数是一个普通函数
setTimeout
的回调函数是一个普通函数,而不是箭头函数,因此它有自己的上下文,this
指向全局对象(在浏览器中是 window
对象)
var name = "我是全局的name"; // 注意这里的name必须用var声明,不可以是let,用let打印出来的就是undefined
// 因为var可以让a是全局作用域,但是let不可以,所以访问对象不存在的属性返回undefined
const obj = {
name: "我是局部的name:John",
greet: function () {
setTimeout(function () {
console.log("this", this); // window
console.log(" this.name:" + this.name);
}, 1000);
},
};
obj.greet();
参考文章
例子2:回调函数是箭头函数
箭头函数的this继承自外部的greet()
var name = "我是全局的name";
const obj = {
name: "John",
greet: function () {
setTimeout(() => {
// 因为是箭头函数,所以往上找,所以是greet的this,
// 那么greet的this是什么呢? 谁调用它就是谁,所以是obj
// 所以 这里的this是obj
console.log("this", this); // obj
console.log(" this.name:" + this.name); // 输出:Hello, John
}, 1000);
},
};
obj.greet();
例子3:回调函数是匿名函数
但是在匿名函数中,因为匿名函数的执行环境具有全局性,所以它的this一般指向window。
var name = "我是全局的name";
const obj = {
name: "John",
greet: function () {
setTimeout(function () {
console.log("this", this);
console.log(" this.name:" + this.name);
}, 1000);
},
};
obj.greet();
解决第一个例子中的this问题:使用bind
const obj = {
name: 'John',
greet: function() {
setTimeout(function() {
console.log(this.name);
}.bind(this), 1000);
}
};
obj.greet(); // 输出:Hello, John
在这个例子中,.bind(this)
将 this
绑定到了 setTimeout
内部的回调函数中,确保 this
在回调函数内部指向 obj
对象。
当然,也可以用例子2的箭头函数方法来解决
扩展案例
主要看 user.sleep();
的this指向!!
<script>
console.log(this); // 此处为 window
// 箭头函数
const sayHi = function () {
console.log("sayHi", this);
};
// 普通对象
const user = {
name: "小明",
// 该箭头函数中的 this 为函数声明环境中 this 一致
walk: () => {
console.log("walk", this); // 箭头函数本身没有this,所以往上找,
// user是对象,也没有this,所以继续向上找,所以最后是window
},
sleep: function () {
let str = "hello";
console.log("sleep的function", this); // obj
let fn = () => {
console.log(str);
console.log("sleep里面的fn", this); // 该箭头函数中的 this 与 sleep 中的 this 一致
// obj
};
// 调用箭头函数
fn();
},
};
// 动态添加方法
user.sayHi = sayHi;
// 函数调用
user.sayHi();
user.sleep();
user.walk();
</script>