Javascript/Coffeescript 中关于 this/@ 的谜题 [英] A puzzle about this/@ in Javascript/Coffeescript

查看:26
本文介绍了Javascript/Coffeescript 中关于 this/@ 的谜题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读 Trevor Burnham 的 CoffeeScript 书,遇到了一个关于 this/@ 的奇怪谜题.这个谜题有几个部分(我可能只是很困惑),所以我会尽量把它说清楚.

I'm working through Trevor Burnham's CoffeeScript book and I've run into a weird puzzle concerning this/@. The puzzle has a few parts (and I may be just very confused), so I'll try to make this as clear as I can.

我遇到的主要问题是,通过不同的 REPL 和解释器运行相同的代码,我得到了不同且不一致的结果.我正在测试 (1) coffee REPL 和解释器,(2) Node 的 REPL 和解释器以及 (3) v8 的 REPL 和解释器.

The main problem I'm having is that I get varied and inconsistent results running the same code through different REPLs and interpreters. I'm testing with (1) the coffee REPL and interpreter, (2) Node's REPL and interpreter and (3) v8's REPL and interpreter.

这是代码,首先是 Coffeescript,然后是 Javascript:

Here's the code, first as Coffeescript then as Javascript:

// coffeescript
setName = (name) -> @name = name

setName 'Lulu'
console.log name
console.log @name

// Javascript via the coffee compiler
(function() {
  var setName;
  setName = function(name) {
    return this.name = name;
  };
  setName('Lulu');
  // console.log for node below - print for v8
  // uncomment one or the other depending on what you're trying
  // console.log(name);
  // console.log(this.name);
  // print(name);
  // print(this.name);
}).call(this);

结果如下:

$ coffee setName.coffee
Lulu
undefined

# coffee REPL
# This appears to be a bug in the REPL
# See https://github.com/jashkenas/coffee-script/issues/1444
coffee> setName = (name) -> @name = name
[Function]
coffee> setName 'Lulu'
'Lulu'
coffee> console.log name
ReferenceError: name is not defined
    at repl:2:1
    at Object.eval (/Users/telemachus/local/node-v0.4.8/lib/node_modules/coffee-script/lib/coffee-script.js:89:15)
    at Interface.<anonymous> (/Users/telemachus/local/node-v0.4.8/lib/node_modules/coffee-script/lib/repl.js:39:28)
    at Interface.emit (events.js:64:17)
    at Interface._onLine (readline.js:153:10)
    at Interface._line (readline.js:408:8)
    at Interface._ttyWrite (readline.js:585:14)
    at ReadStream.<anonymous> (readline.js:73:12)
    at ReadStream.emit (events.js:81:20)
    at ReadStream._emitKey (tty_posix.js:307:10)

coffee> console.log @name
undefined

$ v8 setName.js
Lulu
Lulu

# v8 REPL
>> (function(){var setName; setName=function(name){return this.name=name;};setName('Lulu');print(name);print(this.name);}).call(this);
Lulu
Lulu

# Switch print to console.log or require puts from sys
$ node setName.js
Lulu
undefined

# node REPL
> (function() {
...   var setName;
...   setName = function(name) {
...     return this.name = name;
...   };
...   setName('Lulu');
...    console.log(name);
...    console.log(this.name);
... }).call(this);
Lulu
Lulu

所以我想,真正的问题是 (1) 我应该期待什么结果以及 (2) 为什么这些解释器和 REPL 不能相处?(我的理论是 v8 是正确的:在全局上下文中,namethis.name 应该是同一件事,我想.但我已经准备好了相信我不懂 Javascript 中的 this.)

So the real questions, I suppose, are (1) what results should I expect and (2) why can't these interpreters and REPLs get along? (My going theory is that v8 is right: in the global context name and this.name should be the same thing, I would have thought. But I'm very ready to believe that I don't understand this in Javascript.)

编辑:如果我在调用 setName 之前添加 this.name = null/@name = null (正如下面 Pointy 建议的那样)然后 Coffeescript 和 Node 给我 'Lulu' 和 'null' 但 v8 仍然为两者返回 'Lulu'.(v8 在这里对我来说仍然更有意义.我最初在全局上下文中将 name 设置为 null,但随后 setName 设置它(在全局上下文)到Lulu".所以之后,这就是我应该在那里看到的.)

Edit: If I add this.name = null/@name = null before calling setName (as Pointy suggests below) then Coffeescript and Node give me 'Lulu' and 'null' back but v8 still returns 'Lulu' for both. (v8 still makes more sense to me here. I set name to null initially in the global context, but then setName sets it (in the global context) to 'Lulu'. So afterwards, this is what I should see there.)

推荐答案

首先,CoffeeScript REPL 有一个错误,issue 1444,这是在 Telemachus 引起我注意后我报告的.

So, first off, there's a bug with the CoffeeScript REPL, issue 1444, which I reported after Telemachus brought this to my attention.

但这里更有趣的问题(我需要在 我的 CoffeeScript 书) 是 Node.js 模块最外层范围内的 this 不是 global — 它是该模块的 exports.试试这个:

But the more interesting issue here (and one that I need to note in my CoffeeScript book) is that this in the outermost scope of a Node.js module isn't global—it's that module's exports. Try this out:

console.log this is exports
console.log do -> this is global

当您在 Node 模块中运行该代码时,您会发现这两个语句的计算结果都为 true.这就是为什么 name@name 评估不同的东西的原因:name 本身总是指向 global.name,除非它在 ​​var name 声明的范围内;但 @name 只会在 global 上下文中调用的函数中指向 global.name(默认值).在 Node.js 模块中,在任何函数之外,它都会指向 exports.name.

You'll find that both statements evaluate to true when you run that code in a Node module. That's why name and @name evaluate to different things: name by itself will always point to global.name, unless it's in the scope of a var name declaration; but @name will only point to global.name in a function called in the global context (the default). In a Node.js module, outside of any function, it'll point to exports.name.

这篇关于Javascript/Coffeescript 中关于 this/@ 的谜题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆