本文主要介绍setTimeout的回调函数的this指向问题
例子1:回调函数是一个普通函数
setTimeout
的回调函数是一个普通函数,而不是箭头函数,因此它有自己的上下文,this
指向全局对象(在浏览器中是 window
对象)
var name = "我是全局的name"; // 注意这里的name必须用var声明,不可以是let,用let打印出来的就是undefined// 因为var可以让a是全局作用域,但是let不可以,所以访问对象不存在的属性返回undefinedconst obj = {name: "我是局部的name:John",greet: function () {setTimeout(function () {console.log("this", this); // windowconsole.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是objconsole.log("this", this); // objconsole.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); // objlet fn = () => {console.log(str);console.log("sleep里面的fn", this); // 该箭头函数中的 this 与 sleep 中的 this 一致// obj};// 调用箭头函数fn();},};// 动态添加方法user.sayHi = sayHi;// 函数调用user.sayHi();user.sleep();user.walk();</script>