浅谈箭头函数和setTimeout中的this
箭头函数会改变this的指向,这个大家看文档都看到过,可是有没有具体理解呢?
我发现自己应该可能大概是......emmmm,然后我整理了一遍,加强一下概念吧
顺带再讲一下setTimeout这个函数改写this的概念
首先分别讲一下两位主角
- 箭头函数:都2019年了,大家肯定不陌生了,用法很简单,可以自行百度,箭头函数有一个很大的特性是会改写内部的this指向,那么实际运用的过程中你考虑过注意过这个问题吗?箭头函数内部的this会指向声明箭头函数时所在作用域的this(划重点!!接下来要记住!)
- setTimeout:大家肯定都用过了,它的第一个参数是一个方法,传入的这个方法内部的this会被改写指向window(划重点!!接下来要记住!)
一贯风格,我们上代码来看问题
// 先给window加一个id,以便于确认之后this的指向 window.id = 0; // 声明一个函数fn const fn = { id: 1, say: function() { console.log('id:', this.id); }, sayArrow: () => { console.log('id:', this.id); }, say1: function() { setTimeout(function() { console.log('id:', this.id); }, 1000); }, say2: function() { let that = this; setTimeout(function() { console.log('id:', that.id); }, 1000); }, say3: function() { setTimeout(() => { console.log('id:', this.id); }, 1000); }, say4: () => { setTimeout(() => { console.log('id:', this.id); }, 1000); }, say5: () => { setTimeout(function() { console.log('id:', this.id); }, 1000); }, };
好了,接下来大家来做题,不要做晕了哈
fn.say(); fn.sayArrow(); setTimeout(fn.say, 1000); setTimeout(fn.sayArrow, 1000); setTimeout(() => fn.say(), 1000); setTimeout(() => fn.sayArrow(), 1000); fn.say1(); fn.say2(); fn.say3(); fn.say4(); fn.say5();
以上各自输出什么呢?接下来核对下答案,如果全对,那ojbk了
1 0 0 0 1 0 0 1 1 0 0
如果觉得自己可能没摸透,可以多包几层作用域再试试
接下来看代码讲原因!
fn.say(); /* 结果: 1 原因: 通过fn调用的say, say是 函数声明, this指向fn,输出的是fn.id */ fn.sayArrow(); /* 结果: 0 原因: 通过fn调用的say, say是 箭头函数声明, this指向箭头函数声明时作用域的this,也就是this指向window,输出的是window.id */ setTimeout(fn.say, 1000); /* 结果: 0 原因: 通过setTimeout调用, setTimeout改写所传函数的this, 也就是this指向window,输出的是window.id */ setTimeout(fn.sayArrow, 1000); /* 结果: 0 原因: 通过setTimeout调用, setTimeout改写所传函数的this, 也就是this指向window,输出的是window.id */ setTimeout(() => fn.say(), 1000); /* 结果: 1 原因: 通过setTimeout调用, 但是fn.say()是被箭头函数包裹,所以fn.say()调用不受this改变的影响,原因参考第一句输出 ps: 等同于 setTimeout(function () { fn.say(); } , 1000); */ setTimeout(() => fn.sayArrow(), 1000); /* 结果: 0 原因: 同上雷同,具体原因可参考第二句输出 ps: 等同于 setTimeout(function () { fn.sayArrow(); } , 1000); */ fn.say1(); /* 结果: 0 原因: setTimeout改写函数内部的this, 使其指向window, 输出window.id */ fn.say2(); // 1 /* 结果: 1 原因: setTimeout虽然改写函数内部的this,但是输出的是that.id,这个that在setTimout外面声明,指向的是fn,所以输出fn.id */ fn.say3(); // 1 /* 结果: 1 原因: fn.say3函数其内部的this指向的fn,而setTimeout内部传了一个箭头函数,箭头函数内部中的this就指向了fn.say3内的this,也就是fn,最后输出fn.id */ fn.say4(); // 0 /* 结果: 0 原因: fn.say4这个函数本身就是使用箭头函数声明,其内部的this指向的是箭头函数声明时所在的作用域,即window,而且setTimeout也是传了一个箭头函数,这里面的this指向外层箭头函数内部中的this,传引用也指向了window,最后输出window.id */ fn.say5(); // 0 /* 结果: 0 原因: fn.say5用箭头函数声明,其内部的this指向window,而且setTimeout也会改写内部this指向window,最后输出window.id */
其实有一些调用其根本原因是相同的,但是我个人喜欢各个方面去验证一下,加深一下印象也好,勿喷
附带说一嘴,如果有同学在学node, node内部是没有window对象的,window是浏览器规范,所以具体情况看你在哪里用了,不过概念是差不多的
写完觉得这篇文章真的是浅谈...好low啊哈哈哈哈,写给自己看!