共计 2373 个字符,预计需要花费 6 分钟才能阅读完成。
写之前先做个分类,大抵就这 6 种状况:
- function 中的 this //
指向调用者自身
- 箭头函数 () => {} 中的 this //
定义时最靠近的 function 运行时的 this
- funtion 在 call, bind, apply 等 中的 this //
指向重定向的 this
- 箭头函数 在 call, bind, apply 等 中的 this //
定义时最靠近的 function 运行时的 this
- funciton 回调函数中的 this //
虚空调用,指向全局
- 箭头函数 回调函数中的 this //
定义时最靠近的 function 运行时的 this
由浅入深剖析:
1. funtion 中的 this 指向调用者自身
最根本的 this 指向问题,哪个对象调用就指向这个对象。
比方 dom 操作中:document.getElementById('btn').onclick = function() {console.log(this);}// 当 btn 被 click 的时候,this 指向的就是 document.getElementById('btn')
这里 onclick 是一个 function , 当被点击的时候 => document.getElementById(‘btn’)调用 onclick 函数,所以指向了 document.getElementById(‘btn’);
比方在 Object 中:
const man = {
age: 18,
getAge: function(){console.log(this.age)},
};
window.age = 0;
man.getAge(); // 18
const getAge = man.getAge;
getAge(); // 0
getAge 只是一个 function,当被 man 调用的时候,则指向 man,当被全局调用的时候则指向了 window(严格模式下指向 undefined,下一篇对于内存会讲)
2. 箭头函数 () => {} 中的 this // 定义时最靠近的 function 运行时的 this
听起来有点绕口,不过起因也比较简单,
箭头函数自身的设计是用于匿名函数的,
没有本身的 this 和 arguments, 两者皆从属于定义时最靠近的 function,
而 function 的 this 则取决于它运行时候的调用对象,所以合并起来就是 被定义时最靠近的 function + 运行时的 this
举 3 个例子:1.const a = {cb: function(){setTimeout(() => console.log(this))}};
const fn = () => console.log(this); // 箭头函数,定于于全局
2.const b = {cb: function(){setTimeout(fn)}} // 通过变量名引入到 b.cb 中
3.const c = {cb: function(params_fn){setTimeout(params_fn)}} // 试验中会讲 fn 通过传参引入到 c.cb 中
而后一个个运行
a.cb() // this 指向 a , 因为箭头定义最靠近的 function->cb, this 从属 cb,cb 运行时候是 a 调用的
b.cb() // this 指向 window, 因为箭头定义是虚空定义,指向全局,所以运行时候指向了 window
c.cb(fn) // this 指向 window, 理由同 b
下面的例子还不足以证实 this 是从属最靠近的 function,再加一个 const cb = a.cb;
cb();// this 指向 window
由此可见箭头函数的 this 间接从属了定义时候的最靠近的 function, this 的指向取决于 从属 function 的运行环境
3 + 4. bind ,call ,apply
这三个就简略点说了,因为用过的都晓得这个是强行转变 this 指向的,比方 bind(‘ 硬气 ’), 相当于一个装璜器, 间接 this = ‘ 硬气 ’, 然而因为箭头函数没有 this 和 arguments, 所以对箭头函数不失效,箭头函数的指向曾经不受影响。
5 + 6. 回调函数中的 this 指向
回调函数中,不顾是 function 还是 () => {}, 运行的时候实际上都属于虚空运行,什么叫虚空运行,就是 没有调用对象 ,而在没有调用对象的时候,function 的 this 个别都指向全局(严格模式下为 undefined)
, 箭头函数仍旧依赖从属 this 来确定 this 指向。
回调函数个别都是定义于一个函数之内的,箭头函数很容易确定 this 的指向,同时不会扭转回调函数外部的 this 指向,所以这也是回调函数,多用箭头函数的起因。
扩大一下:防抖函数
防抖函数自身的知识点是闭包,不过外面的一个定时器却是用了 this 指向的技巧
写一个惯例的防抖
function dobounce(fn, time = 1000) {
let timeout = null; // 创立变量
return function() {if(timeout) clearTimeout(timeout); // 如果已有定时器,革除定时器
timeout = setTimeout(() => fn.apply(this, arguments), time); // 从新创立定时器
}
}
这里的 setTimeout()中箭头函数间接继承闭包返回值 function 的 this 和 arguments, 而后调用这个防抖 a = {name: 4, test: dobounce(function(a, b) {console.log(this.name + a + b)})};
a.test(5, 6) // 15
不过防抖外面传入的 fn 就不要用箭头函数了,起因参考箭头函数的 this 指向问题。
总结:
箭头函数因为没有本人的 this,所以不会被各种外界因素扭转 this,只从属于定义时最靠近的 function
而 function 个别状况下 this 都是取决于调用对象,然而能够被 bind, call ,apply 等扭转 this 指向,如果是虚空运行(回调函数中,则指向全局)