一篇搞定this指向问题!
标签搜索

一篇搞定this指向问题!

指针原来是套娃的
2024-09-13 / 0 评论 / 9 阅读 / 正在检测是否收录...

大佬说,要搞定this指向问题就要理解谁有thisthis又指向什么东西
重点记住一句话:this是存在执行上下文中的 指向的是一个对象
执行上下文 分三种 全局执行上下文 函数执行上下文 和 eval执行上下文
即this只有全局、函数(箭头函数不存在this)、eval中存在,指向一个对象,在浏览器环境下全局this指向window对象
请理解上面内容,尝试做一下下面几道题(浏览器环境 非严格模式)

1

a = 100;
const obj = {
  a: 1,
  b: () => {
    const a = 10;
    console.log(this.a);
  },
};
obj.b();

2

a = 100;
function b() {
  var a = 1000;
  const c = () => {
    var a = 1;
    console.log(this.a);
  };
  c();
}
b();

3

a = 100;

function b() {
  const c = () => {
    var a = 1;
    console.log(this.a);
  };
  c();
}
const obj = {
  a: 1000,
  m: b,
};
obj.m();

4

a = 100;
const b = {
  a: 1,
  c: function () {
    var a = 1000;
    console.log(this.a);
  },
};
const m = b.c;
m();

5

a = 100;
const b = {
  a: 1,
  c: function () {
    var a = 1000;
    console.log(this.a);
    (function () {
      console.log(this.a);
    })(a);
  },
};
b.c();
const m = b.c;
m();

6

a = 100;
const b = {
  a: 1,
  c: () => {
    var a = 1000;
    console.log(this.a);
  },
};
const m = b.c;
m();

请思考一下我们再解释哦!

这里的难度是循序渐进的,因为浏览器环境和Node环境内全局this有些不一样,所以我们先讨论浏览器环境下的输出。
看一下第一题:

a = 100;
const obj = {
  a: 1,
  b: () => {
    const a = 10;
    console.log(this.a);
  },
};
obj.b();

还记的一开始说的话吗?this存在于执行上下文中,只有全局和函数还有eval拥有this,他指向的是一个对象。同时,箭头函数是没有自己的this的。
先说答案:
m1069cn8.png
在浏览器环境下输出为100
b是一个箭头函数,没有自己的this,所以再往外找,是obj调用的b()函数,但是对象也没有this,再向外找,obj.b()是在全局下调用,所以这里打印的this是全局的this浏览器环境下,全局this指向全局window对象,所以打印的this.a实际是window.a 值为100。
这里的重点就是,对象是没有this的
我们把这六道题一一对一下,就会清楚整个的执行原理了。
第二题和第一题由有一些区别,不过只有搞清楚谁的this,指向哪个对象,也很简单。

a = 100;
function b() {
  var a = 1000;
  const c = () => {
    var a = 1;
    console.log(this.a);
  };
  c();
}
b();

this是谁的?最内层的c函数是箭头函数没有this,外面b函数拥有this,所以不用再往外找了。第一点,当前打印的this是b函数的
this指向的谁?b函数是在全局下调用的,所以指向的对象是全局的window对象,这里打印的this.a也是全局的window.a
m1070xgh.png

不清楚的话我们再看第三题!

a = 100;

function b() {
  const c = () => {
    var a = 1;
    console.log(this.a);
  };
  c();
}
const obj = {
  a: 1000,
  m: b,
};
obj.m();

this是谁的?在b函数内调用的c函数,因为c是箭头函数没有this,所以向上层寻找,b是一个函数,拥有this。找到了,打印的this是b函数所拥有的this
一开始说过,this指向一个对象,这个对象就是调用该函数的对象,在这里是obj调用的,所以b函数的this指向obj对象,打印的this.a是obj.a,值为1000。
m106mz96.png
这三道题看完是不是清晰一些了?
请带着你的理解再思考一下第四题!

a = 100;
const b = {
  a: 1,
  c: function () {
    var a = 1000;
    console.log(this.a);
  },
};
const m = b.c;
m();

this是不是c函数的?都不用往外找了,m()运行的时候是在全局下调用的,所以c函数的this指向全局对象window,打印值为100。
不要被b.c迷糊了哦
m10a9v4r.png
越来越熟练了,下面看第五题:

a = 100;
const b = {
  a: 1,
  c: function () {
    var a = 1000;
    console.log(this.a);
    (function () {
      console.log(this.a);
    })(a);
  },
};
b.c();
const m = b.c;
m();

这个有两次调用,每次调用会打印两次,所以一共有四次打印,没有异步情况,从上往下看就好了。
先看b.c(),这里的this是c函数的this,调用者是b,所以指向b对象,先打印一个1。
然后进入立即执行函数里,不要被传入的a迷糊了,立即执行函数是在全局下执行的,这里的this是全局的变量,打印100。
m赋值了b.c这个函数,所以m就是c函数了,已经和b没有任何关系了,这里的this是c函数的this,调用在全局里,所以指向全局对象,打印100。
立即执行函数同上,打印一百。
最后结果就是1 100 100 100
m10ajuiv.png
第六题!

a = 100;
const b = {
  a: 1,
  c: () => {
    var a = 1000;
    console.log(this.a);
  },
};
const m = b.c;
m();

有上面的铺垫相信这道题可以直接秒了。
c是箭头函数没有this,向外面找,m()在全局下执行,this为全局this,指向全局对象,打印100。
m10an80r.png

为什么在最后放一个这么简单的题呢?其实我想借这个第六问说一下另一种情况。
上面的截图都是在浏览器环境下执行的,如果改成Node环境呢?
Node环境的this和浏览器的this有什么区别?
浏览器情况说完了,下面再说一下Node环境中的打印。
我们知道,浏览器环境下全局对象是window对象,全局this指向了window对象。
这里就是最大的区别,在Node环境中全局对象是global对象,而全局的this指向的却不是全局对象global
在cjs模块下,全局this === module.exports === exports
它指向的是导出对象,所以涉及全局的部分会和浏览器有所差别。
m10b0xup.png
因为没有导入该模块,所以这里的导出都是空对象,a挂载到了全局对象global里。但是this不指向global对象呀,{}空对象里没有a,所以打印为undefined。
把后缀名改成mjs,就切换到了ES模块,在ES模块执行这个代码,全局this为undefined,undefinde中根本没有a,所以this.a会报错。
这就是Node和浏览器不同的地方,差别只在涉及全局this部分,如第三道题,不涉及全局this,打印值和浏览器环境中是一样的。
m10b973x.png

以上!

0

评论

博主关闭了所有页面的评论