Java / Coffeescript中关于this / @的困惑

|| 我正在研究Trevor Burnham的CoffeeScript书,并且遇到了关于
this
/
@
的怪异难题。这个难题有几个部分(我可能会很困惑),所以我将尽力使这一点变得清楚。 我遇到的主要问题是,通过不同的REPL和解释器运行相同的代码,会得到各种各样且不一致的结果。我正在使用(1)
coffee
REPL和解释器,(2)Node \的REPL和解释器以及(3)v8的REPL和解释器进行测试。 这是代码,首先是Coffeescript,然后是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是正确的:在我看来,
name
和ѭ6global在全球范围内应该是同一件事。但是我非常愿意相信我不理解Javascript中的
this
。) 编辑:如果我在调用
setName
之前添加
this.name = null
/
@name = null
(如Pointy在下面建议),那么Coffeescript和Node给我\'Lulu \'和\'null \'回来,但v8仍然为两者返回\'Lulu \'。 (v8在这里对我来说仍然更有意义。我最初在全局上下文中将
name
设置为
null
,但是后来
setName
将其(在全局上下文中)设置为''Lulu \'。因此,此后,我应该在这里看到。 )     
已邀请:
        因此,首先,CoffeeScript REPL有一个错误,版本1444,在Telemachus引起我注意之后,我报告了该错误。 但是,这里更有趣的问题(也是我在CoffeeScript书中需要注意的一个问题)是,Node.js模块的最外层范围中的ѭ0不是15,而是该模块的16。试试看:
console.log this is exports
console.log do -> this is global
当您在Node模块中运行该代码时,您会发现这两个语句的计算结果均为18。这就是为什么ѭ5和ѭ20会得出不同的结果的原因:ѭ5本身将始终指向ѭ22,除非它在ѭ23声明的范围之内。但是在
global
上下文中调用的函数中,
@name
只会指向
global.name
(默认值)。在Node.js模块的任何函数之外,它将指向
exports.name
。     
        我不知道为什么会得到不同的结果,但是知道函数的隐式调用涉及设置“ 0”。因此,内部函数“ setName()\”具有其自己的
this
值,而与定义它的外部函数中的
this
值无关。因此,通过调用\“。call()\”设置
this
的事实对内部\“ setName()\”函数内部的
this
值没有任何影响,因为调用\“ setName()\”时没有接收者参与。     
        我对CoffeeScript的了解不多,但是对JavaScript的了解却很少,所以我只能从编译后的代码做什么(或应该做什么)的角度来解释一下:
(function(){
  // In here \"this\" === [global]
  //
  // The purpose of this wrapper pattern is that it causes \"this\" to be
  // the global object but all var declared variables will still be 
  // scoped by the function.

  var ctx = this;     // let\'s keep test a ref to current context

  var setName;
  setName = function(name) {
    console.log(this === ctx);   // !! true !!

    // Because in here \"this\" is the global context/object
    // this is setting [global].name = name
    return this.name = name;
  };

  setName(\'Lulu\');         // It\'s context will be [global]

  console.log(name);       // (name === [global].name) == true
  console.log(this.name);  // (this.name === [global].name) == true

}).call(this);
实际上(或应该发生)的是这种情况(假设全局浏览器为
window
的浏览器):
(function() {
  var setName;
  setName = function(name) {
    return window.name = name;
  };
  setName(\'Lulu\');
  console.log(window.name);   // \'Lulu\'
  console.log(window.name);   // \'Lulu\'
}).call(this);
那么,为什么引擎之间不匹配呢? 因为不同的环境使用不同的方式将全局对象交给您并处理范围。很难确定地说,每种环境都有其行为的单独原因。这在很大程度上取决于他们如何评估代码(这是假设所有引擎都没有错误)。     

要回复问题请先登录注册