2017-07-27 51 views
0

我動態建立的對象將具有在其上的發送方:類型錯誤:此[(( 「_」 +(中間值))+ 「_listener」)]不是一個函數

var coins = {}; 

['USD','EUR'].forEach((product_id) => { 
    coins[`_${product_id}`] = {}; 
    coins[`_${product_id}_listener`] = (val) => { 
     log.info(process.pid, 'terminal send', product_id, [`_${product_id}`]); 
     terminal.send({ 
      action: product_id, 
      data: this[`_${product_id}`], 
      timestamp: new Date, 
     }); 
    }; 

    Object.defineProperty(coins, product_id, { 
     set: (val) => { 
      this[`_${product_id}`] = val; 
      this[`_${product_id}_listener`](val); 
     }, 
     get: (val) => { 
      return this[`_${product_id}`]; 
     }, 
    }); 
}); 

不幸的是,當我設置一個硬幣的東西......

coins['USD'] = {a: 4}; 

我得到一個錯誤:

TypeError: this[(("_" + (intermediate value)) + "_listener")] is not a function 
at Object.set (repl:15:32) 
at repl:1:18 
at sigintHandlersWrap (vm.js:22:35) 
at sigintHandlersWrap (vm.js:73:12) 
at ContextifyScript.Script.runInThisContext (vm.js:21:12) 
at REPLServer.defaultEval (repl.js:340:29) 
at bound (domain.js:280:14) 
at REPLServer.runBound [as eval] (domain.js:293:12) 
at REPLServer.<anonymous> (repl.js:538:10) 
at emitOne (events.js:101:20) 

這顯然是指T的第二線他是二傳手,但我不知道爲什麼。如果我評論一下,得到並設置工作正常。我的聽衆只是不開火...顯然。這裏的目標是讓聽衆開火。

跟進

我也注意到,與該行註釋掉,該對象看起來不(IMO):

> coins['USD'] = {a: 4}; 
{ a: 4 } 
> coins 
{ _USD: {}, 
    _USD_listener: [Function], 
    _EUR: {}, 
    _EUR_listener: [Function] } 
> coins['_USD'] 
{} 
> coins['USD'] 
{ a: 4 } 

由於我的二傳手是supposively設置爲_USD,爲什麼_USD在我打印出coins時看起來沒有設置?

回答

1

問題是,不同於普通功能的箭頭功能不允許更改上下文(this)。 Docs

An arrow function expression has a shorter syntax than a function expression and does not bind its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions

所以當你創建一個箭頭函數的上下文將被捕獲一次所有的調用。

您可以使用coins作爲上下文切換到正常功能或創建箭頭功能。例如,將coins作爲上下文傳遞給.forEach調用,並用正常函數替換iteratee以允許動態上下文。

var coins = {}; 
 

 
['USD','EUR'].forEach(function(product_id) { 
 
    this[`_${product_id}`] = {}; 
 
    this[`_${product_id}_listener`] = (val) => { 
 
     console.log(`${product_id} - ${val}`) 
 
    }; 
 

 
    Object.defineProperty(coins, product_id, { 
 
     set: (val) => { 
 
      this[`_${product_id}`] = val; 
 
      this[`_${product_id}_listener`](val); 
 
     }, 
 
     get: (val) => { 
 
      return this[`_${product_id}`]; 
 
     }, 
 
    }); 
 
}, coins) 
 

 
coins.USD = 10 
 
coins.EUR = 100 
 
console.log(`USD ${coins.USD}, EUR ${coins.EUR}`)

或者更好地利用正常的功能,因爲你有 「方法」

var coins = {}; 
 

 
    ['USD','EUR'].forEach(product_id => { 
 
     coins[`_${product_id}`] = {}; 
 
     coins[`_${product_id}_listener`] = function(val) { 
 
      console.log(`${product_id} - ${val}`) 
 
     }; 
 

 
     Object.defineProperty(coins, product_id, { 
 
      set: function(val) { 
 
       this[`_${product_id}`] = val; 
 
       this[`_${product_id}_listener`](val); 
 
      }, 
 
      get: function() { 
 
       return this[`_${product_id}`]; 
 
      }, 
 
     }); 
 
    }) 
 

 
    coins.USD = 10 
 
    coins.EUR = 100 
 
    console.log(`USD ${coins.USD}, EUR ${coins.EUR}`)

+0

非常感謝您的快速和完整的答案!起初,我認爲這是深夜編碼引起的問題,但現在我再次醒來,我仍然不確定你的第二個答案或[mozilla的例子](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set#Defining_a_setter_on_existing_objects_using_defineProperty)工作,而我的工作沒有。這個''['_ $ {product_id}'] = val'出現(在我身上)在'function'的上下文之外。我認爲這是一個特殊的對象指針,但我想有一些我並沒有完全掌握的繼承。 – VertigoRay

+1

@VertigoRay考慮下面的例子'const obj = {fn(){return this},arrow:()=> this}'。如果你使用'console.log(obj.fn(),obj.arrow())',你會看到不同的輸出,因爲'obj.smth()'相當於'obj.smth.call(obj)'。如果'smth'是箭頭函數,它不會影響它的上下文,因爲它是一次性設置的,就像你使用普通函數「綁定」一樣。 –

0

顯然,將所有this變量替換爲coins將解決此問題。我仍然不能100%確定它爲什麼不起作用,或者這是最好的解決方案。

var coins = {}; 

['USD','EUR'].forEach((product_id) => { 
    coins[`_${product_id}`] = {}; 
    coins[`_${product_id}_listener`] = (val) => { 
     log.info(process.pid, 'terminal send', product_id, [`_${product_id}`]); 
     terminal.send({ 
      action: product_id, 
      data: coins[`_${product_id}`], 
      timestamp: new Date, 
     }); 
    }; 

    Object.defineProperty(coins, product_id, { 
     set: (val) => { 
      coins[`_${product_id}`] = val; 
      coins[`_${product_id}_listener`](val); 
     }, 
     get: (val) => { 
      return coins[`_${product_id}`]; 
     }, 
    }); 
}); 

我更喜歡別人提供的答案......或者至少驗證這是它應該完成的方式。謝謝!

相關問題