[javacript 的 this 指向问题, 高手请进]

2022-11-19 10:21:53 +08:00
 Angela2022
name = "哈哈"
const pet1 = {
name: 'Fluffy',
getName1: () => this.name
};
console.log(pet1.getName1()); //哈哈

function pet(name) {
this.name = name;
this.getName1 = () => this.name;
}
const cat = new pet('Fluffy');
console.log(cat.getName1()); //Fluffy

请问: 上面两个 console.log 都是打印相同的箭头函数, 为啥上面一个打印"哈哈", 下面一个打印 Fluffy ? 谢谢
3449 次点击
所在节点    程序员
20 条回复
looking0truth
2022-11-19 10:26:25 +08:00
() => 的上下文在声明时所在的函数中
下面的 this 是 pet ,上面的是 global
isolcat
2022-11-19 10:46:47 +08:00
这里的 this 指向要根据你调用的环境来决定,第一个 pet1.getName1()就是指向的 global ,第二个 cat.getName1()在声明了参数'Fluffy'的情况下自然也就会指向所声明的函数
你可以在 MDN 里搜索 this ,讲解的很详细
anc95
2022-11-19 10:56:56 +08:00
一楼说的对,二楼说了和没说一样
sweetcola
2022-11-19 11:09:17 +08:00
上面的 getName1 相当于只是一个函数变量,指向的是当前 context 的 this
下面的 getName1 在函数中,new 之后就相当于在一个闭包里,context 不会随你在哪里调用而改变
hahamy
2022-11-19 11:26:00 +08:00
箭头函数的 this 和调用无关,定义的位置在哪,this 就指向哪
我简单粗暴的理解是,看结束的分号 ; 在哪,this 就指向分号位置的对象
weiwoxinyou
2022-11-19 11:43:29 +08:00
()=>{}中的 this 自动指向上一层
rabbbit
2022-11-19 12:44:52 +08:00
箭头函数没有 this
zhaomeicheng
2022-11-19 14:43:37 +08:00
1. 箭头函数里的 this 是在箭头函数被定义那一刻决定的,且后续不会再变了。
2. 箭头函数里的 this 是离它最近的外层普通函数的 this ,如果最外层是全局环境,那么即 window 。

第一个输出:
箭头函数定义的那一刻,外层没有普通函数,那么 this 是 window 。
第二个输出:
箭头函数定义的那一刻,外层普通函数是 pet 函数,且 pet 函数被调用是通过 new 操作符,所以 pet 函数的 this 是 cat 对象,即箭头函数的 this 是 cat 。
lisongeee
2022-11-19 16:38:36 +08:00
普通函数的 this 像是一个关键字语法糖,从 ast 的角度看,当这个函数被以 MemberExpression 被调用时,函数内的 this 是 Identifier
箭头函数的 this 像是一个 const 变量语法糖,当箭头函数被声明时,额外在当前作用域声明了一个 <const>_this ,并将
这个 _this 永久作为箭头函数内的 this

```js
function Pet(name) {
this.name = name;
const _this = this;
this.getName1 = () => _this .name;
}
```
QGabriel
2022-11-19 16:53:52 +08:00
1. 箭头函数的 thsi 是上层的 this;
console.log(pet1.getName1()) 相当于 window.pet1.getName1(); pet1 的 this 是 window

2. new 方法 会在函数内隐式的声明一个 this 变量 值为空对象; let this = {}
function pet('Fluffy') {
this.name ='Fluffy';
this.getName1 = () => this.name;
}
dcsuibian
2022-11-19 17:02:46 +08:00
一般的函数,都有一个隐藏的 this 参数。例如:
function add ( a , b ){
return a+b
}
这个函数的完整形式,你可以想象成:
function add ( this, a , b ){
return a+b
}
我习惯称这种形式为“函数的绝对表示”。

如果你使用“对象.函数()”的方式调用,那么这个隐藏的 this 参数就会变成那个对象。比如 t.add(1,2),函数中收到的就是 add ( t, 1, 2)。

但箭头函数,没有这个隐藏的 this 参数,也就是说
let add=(a,b)=>{
return a+b
}
它的绝对表示也都是这样。
dcsuibian
2022-11-19 17:05:42 +08:00
用这种方法理解,那么你的函数:
function pet(name) {
this.name = name;
this.getName1 = () => this.name;
}
其实可以看做:
function pet( this, name) {
this.name = name;
this.getName1 = () => {
return this.name;
}
}
把 this 看成一个普通的参数,那么 this 其实就是使用了闭包机制。
liuw666
2022-11-19 18:03:32 +08:00
写了一年多 react 都是函数组件,好像几乎没用过 this
Justin13
2022-11-19 19:23:33 +08:00
箭头函数的 this 在声明时确定
第一个指的是全局作用域,第二个指的是函数作用域
而通常的 this,指向的是调用者
karott7
2022-11-19 23:46:21 +08:00
一楼答案正确且简洁
xinleibird
2022-11-20 00:35:06 +08:00
箭头函数的执行上下文不持有 ThisBinding ,采用的是 Lexical this (词法指的是执行上下文中的「环境」,理解为以作用域链替换 this 就成了)。其实这样越说越糊涂了……

```js
const obj = {
detail: "obj",
getDetail() {
console.log(this.detail);
}
}

obj.getDetail(); // obj

const getDetail = obj.getDetail;
getDetail(); // undefined ,此时上下文是 global ,非严格模式,global 下 this 指向 window ,window 没有 detail
```

```js
const obj = {
detail: "obj",
getDetail: () => {
console.log(this.detail);
},
};

obj.getDetail(); // undefined ,「对象字面量」 obj 不产生作用域,这个要注意。this 找上级作用域 window ,window 没有 detail 属性。
```
1. 执行上下文除了 global 其余都是函数执行产生的。
2. 你在函数中使用的 `this`,也就是执行上下文中的 `ThisBinding`,只与调用该函数的「对象」相关。
3. 箭头函数是个特殊情况,它采用词法 this ,也就说,`this` 与上下文中「动态的」 ThisBinding ( obj 或 window ,`.`点号之前的……)无关,与「静态的」环境有关,要到环境(作用域链)中找。
4. 而「对象字面量」`obj` 又不产生作用域(它顶多叫 namespace 名字空间)。由此会再向真正的作用域中找,外层的作用域就是 global ( window )。
5. **简而言之**:箭头函数的词法 this 产生的效果是:把箭头函数上下文中的 this 绑定到 **『外层作用域』** 中。

推荐到 https://muyiy.cn/blog/1/1.1.html 看看,博主写的很详细,跟着写写伪代码就清楚了。这样白嘴说其实越说越乱。
DOLLOR
2022-11-20 00:48:28 +08:00
上面所有人都忘记提到的一点,非严格模式下,没有经过 let 、const 声明就直接赋值给一个变量名,它就成为全局变量,并且成为 window 下的同名属性。
比如
name = "哈哈"
name 成了全局变量,并且也是 window.name 的值也是"哈哈"。如果在某个函数内 this 误指向了 window ,那么 this.name 的值也是"哈哈"。
这种特性应该避免误用。
AyaseEri
2022-11-20 10:42:08 +08:00
function 才能形成一个作用域吧,单纯字面量的对象并不能形成作用域。

function Senpai(name) {
this.name = name;
return {
getName1: () => this.name,
getName2() { return this.name }
}
}

这俩结果也是不一样的
yaphets666
2022-11-21 11:27:43 +08:00
就一句话,箭头函数的 this 指向和声明位置的 this 指向一致
huangqihong
2022-11-21 13:51:07 +08:00
看到高手就进来了,看到 this 指向问题就明白了,这无关“高手”的问题,

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/896372

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX