乐趣区

关于javascript:javascript中this的指向全攻略

写之前先做个分类,大抵就这 6 种状况:

  1. function 中的 this // 指向调用者自身
  2. 箭头函数 () => {} 中的 this // 定义时最靠近的 function 运行时的 this
  3. funtion 在 call, bind, apply 等 中的 this // 指向重定向的 this
  4. 箭头函数 在 call, bind, apply 等 中的 this // 定义时最靠近的 function 运行时的 this
  5. funciton 回调函数中的 this // 虚空调用,指向全局
  6. 箭头函数 回调函数中的 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 指向,如果是虚空运行(回调函数中,则指向全局)

退出移动版