簡體   English   中英

關於這個/ @在Javascript / Coffeescript中的一個難題

[英]A puzzle about this/@ in Javascript/Coffeescript

我正在研究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是正確的:在全局上下文namethis.name應該是相同的東西,我會想。但我已經准備好相信我在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的書 )是this在Node.js的模塊的最外面的范圍不是global -它的那個模塊的exports 試試這個:

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

我不知道為什么你得到不同的結果,但知道函數的調用隱含涉及設置this 因此,該內部函數“的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);

那么,為什么引擎之間不匹配呢?

因為不同的環境使用不同的方法將全局對象交給您並處理范圍。 很難肯定地說,每個環境可能都有其獨立的行為原因。 這在很大程度上取決於他們如何評估代碼(假設沒有引擎有錯誤)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM