请教一个关于箭头函数this的问题
发布于 7 年前 作者 nar142857 4371 次预览 最后一次回复是 7 年前 来自 问答
var x=11; var obj={ x:22, say:()=>{ console.log(this.x); } } obj.say(); // undefined
这个输出的为什么是undefined 而不是11? 打印出整个this的话 是个空对象 {}; 网上查了好多都说这里是输出11, 难道是我的运行环境的问题?
程序完整截图如下
16 回复
箭头函数中的this指向父级作用域的this
@WPBLRUN 在命令行直接打印代码运行确实用var的时候会输出x=11,this为全局对象,用let的时候全局没有x这个变量输出是undefined,这些表现和我的理解是符合的。但是在IDE或者在在命令行 运行node test.js 文件的时候, 不论用var 还是let this指向的都是一个空对象{}; 这就让我有点费解了。这些环境应该也是有全局对象才对的啊。

@lucky-leaf 是应该指向父级的this, 但运行结果和预期不一致啊, 在IDE中运行 this指向了{};
@nar142857
https://cnodejs.org/topic/52308842101e574521c16e06
node 的命令行里输入代码执行和直接 使用node xxx.js执行还是有区别的。可以看下上个链接,在node test.js 执行时候,箭头函数实际绑定的this 是 module.exports 也就是 {};
undefined是你say方法的返回值, 你仔细看看是先打印11 然后打印undefined。 因为你say方法没有返回值,所以是undefined。 你改成这样看看打印啥。 var x=11; var obj={ x:22, say:()=>{ console.log(this.x); return 1; } } obj.say();
undefined就变成11了。
@nar142857
我实在想不到怎么把代码放在一个对象里执行,也没折腾出等价的代码来,晚上实在想不出例子了。现在也只是通过打log的代码更明显地看到this空对象是什么怎么来的。
@Visiters 希望有深入理解模块化的能够解惑,谢谢了!
先说结论,在node.js中执行箭头函数,其中的this永远指向文件的全局对象module.exports。如果是function的写法的话指向的是最近的父级作用域 验证过程如下:
萌新第一次发言,如果有错请指正
@Gitforxuyang 你单独建一个xx.js文件执行以下, 和return 没关系哦, 输出的还是undefined, 楼上应该是正解。
@WPBLRUN 这个应该是正解,辛苦了。 经我测试发现,箭头函数的this指向的是 module.exports指向的对象,而不是module.exports对象。
我改变了module.exports的指向,但this并没有改变。 这样就会有另外一个问题,好多框架在都会在文件开头写exports = module.exports ={} 这样的语句,但是如果在这样的文件里面使用箭头函数,感觉会导致this的指向和预期的不一致。
@Masterlu1998 感觉你的理解不太对, 普通function函数的this指向的应该是这个函数的调用者对象, 使用call和apply函数的时候可以明显的看出来, 箭头函数没有this所以使用this的时候会向定义生效时的父级查找。
@nar142857 这个例子“箭头函数的this指向的是 module.exports指向的对象,而不是module.exports对象。” 厉害,找到根本原因了。学习了
箭头函数没有this…
个人认为是let关键字建立了块级作用域,声明的全局变量不会被注册到 window 上; 而此时的this指向的是当前的全局对象;浏览器即window,node的话。。看是在模块内(module.exports)还是全局(global)
然后抛出一个揣测: let声明的变量不具有声明提前和变量提升。
1、声明提前即为 在声明之前无法使用,编译器不会将let声明的变量在当前作用于提前(根据MDN提供的相关文档这一点应该是正确的)。
2、其实变量提升这里我是有点混乱的,
在{}块级作用于下let声明的变量不会像使用var关键字或者不使用关键字声明的变量一样会提升到{}的同级作用域(根据MDN提供的相关文档这一点应该是正确的),
但在没有{}的情况下 例如刚才的例子 let声明的变量是否为全局变量 如下看起来好像是这样的
接下来我们看一下全局对象的定义(开始大段摘抄)
综上所述,let声明的变量不是全局变量,只是因为这种情况下我们的代码都会被隐式的加上{},成为全局作用域内的块级作用域, 而{}内的var声明的变量会提升到全局作用域 并且在{}中我们可以使用let声明的变量 造成了彷佛我们用let声明了全局变量,其实并非如此
回答的有些晚了 会不会沉了? 欢迎指教
如果你在全局作用域内使用 let 或 const,那么绑定就会发生在全局作用域内,但是不会向全局对象内部添加任何属性。这就意味着你不能使用 let 或 const 重写全局变量,而仅能屏蔽掉它们。如下所示:
在这里,let 声明创建了新的 RegExp 绑定并屏蔽掉了全局对象的 RegExp 属性。也就是说 window.RegExp 和 RegExp 并不等同,所以全局作用域并没有被污染。同样 const 声明创建了新的绑定的同时也没有在全局对象内部添加任何属性。这个设定使得在全局作用域内使用 let 或 const 声明要比 var 安全得多,特别是在你不想在全局对象内部添加属性的时候。