2015-03-31 31 views
8

我正在使用ES6類將一些功能捆綁在Node中。這裏是(基本上)是什麼樣子:ES6方法獲得null「this」並且類變量不可訪問

class processDocs { 
    constructor(id) { 
    this.id = id; 
    // console.log(this) returns { id: id } 
    } 

    getDocs(cb) { 
    // console.log(this) returns null 
    docs 
     .query(qb => { 
     qb.where('id', this.id); 
     }) 
     .fetch() 
     .then(function(documents) { 
     cb(null, documents); 
     }) 
    ; 
    } 

    alterDocs(documents, cb) { 
    //some logic 
    } 

    reindexSearch(cb) { 
    //some logic 
    } 

    process() { 
    // console.log(this) returns { id: id } 
    async.waterfall([ 
     this.getDocs, 
     this.alterDocs, 
     this.reindexSearch 
    ]); 
    } 
} 


export default processDocs; 

我以爲跟ES6類的方式來分配公共變量是簡單的引用this並通過構造函數來初始化這些變量的方式正是它的顯示方式在我的班級定義中。

這裏是我如何調用類(在一個單獨的文件):

var Processor = require('./processDocs'); 

var pr = new Processor(id); 
var docs; 
pr.process(); 

這裏的問題,當我從構造console.logthis,我讓我的{ id: id }值預測;但是,每當我註銷thisgetDocsprocess正在運行時,它是空的。但是,當我在瀑布之前註銷this,process()時,我得到了我的原始對象。

這是否有任何理由?

順便說一句,我使用節點:v0.10.33和babel節點4.6.6和我運行babel-node --harmony標誌。在任何人詢問之前,我無法更新到較新的節點版本,因爲主要依賴於卡在v0.10.x

編輯我能夠創建一個解決方法,但它不是很像es6。這個問題似乎與async.waterfall。我不得不使用一個.bind來解決它:

async.waterfall([ 
     this.getDocs.bind(this), 
     this.alterDocs.bind(this), 
     this.reindexSearch.bind(this) 
    ]); 
+0

我不明白你所說的「不是很ES6狀」是什麼意思?方法不是,也不會被自己綁定到實例上。順便說一句,如果你想要真正的ES6代碼,然後廢除'異步'並使用承諾。 – Bergi 2015-03-31 00:46:38

+0

我說的不是'es6-like',因爲我不得不使用'.bind(this)'。那麼你是說如果我從一個類中調用一個方法,那麼'this'將會丟失? 因爲這對我沒有意義。當我使用'pr.process()'時,'this'是正確的,當我直接從'this.process()'調用'this.getDocs'時,它也保留了'this'。這似乎是一個「異步」問題。 此外,如果我想成爲非常類似ES6,我會使用生成器:)承諾是ES5,仍然會導致回調地獄,這是我試圖通過使用'async'來防止。 – antjanus 2015-03-31 00:52:07

+0

爲什麼你認爲你不需要使用'.bind()'?你傳遞給其他地方的函數。你*不是從你的課堂中調用它們*!承諾是適當的解決方案(他們非常多ES6!發電機不是異步功能!):'process(){return this.getDocs()。then(docs => this.alterDocs(docs))。然後changedDocs => his.redindexSearch(alteredDocs)); }' – Bergi 2015-03-31 00:56:55

回答

3

ES6並沒有改變「this」的工作方式,因此它取決於「你在哪裏調用它」的上下文而不是「總是具有相同」的值。這很不直觀,在其他語言中並不常見。

考慮這個例子

class processDocs { 
    constructor(id) { 
    this.id = id; 
    console.log(this) 
    } 

    getDocs(cb) { 
    console.log(this) 
    } 

    alterDocs(documents, cb) { 
    //some logic 
    } 

    reindexSearch(cb) { 
    //some logic 
    } 

    process() { 
    console.log(this) 
    } 
} 

var process = new processDocs(10); 
var docs = process.getDocs(function(){}); 
var processInstance = process.process(); 

var docsAsFunction = process.getDocs; 
docsAsFunction(function(){}); 

輸出是

processDocs {id: 10} 
processDocs {id: 10} 
processDocs {id: 10} 
undefined 

正如你所看到的,最後一個是取消定義,它呼籲「docsAsFunction」,因爲你沒有直接調用該函數從它的類別來看,因此背景是不同的。

你可以閱讀一下例如here

+0

花了我幾個月的時間來得到你在說什麼,但現在我明白了。感謝你的回答! – antjanus 2016-10-05 21:15:08

0

我創建了自己的以下功能。

let bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; //from coffeescript's => operator 

//use in a class's constructor to make the this pointer always refer to the object in which a function resides 
function fixThisPointer(_this, func){ 
    _this[func.name] = bind(_this[func.name], _this); 
} 

function fixThisPointer2(_this, funcNameArray){ 
    for (name of funcNameArray){ 
    _this[name] = bind(_this[name], _this); 
    } 
} 

然後,當我需要的時候,我在構造函數

fixThisPointer(this, foo) 

或者命令

fixThisPointer2(this, ['foo', 'foo2', 'foo3']) 
+0

我將不得不看看更像es6的處理方式貝吉談到的承諾。 – 2015-04-17 20:51:13

0

您可以使用類中箭頭的功能,因爲他們的汽車使用此命令綁定這個。你可以寫你的類方法爲:

getDocs = (cb) => { 
    // console.log(this) will not returns null 
    docs 
     .query(qb => { 
     qb.where('id', this.id); 
     }) 
     .fetch() 
     .then(function(documents) { 
     cb(null, documents); 
     }) 
    ; 
} 

看到this MDN article:「箭功能捕捉封閉的上下文的這個值」

+0

我最近看到這種模式變得很普遍。我想知道爲什麼。謝謝! – antjanus 2016-05-29 21:20:03

0

考慮更新的process()身體這樣的:

process() { 
    // console.log(this) returns { id: id } 
    async.waterfall([ 
    (cb)=>{this.getDocs(cb);}, 
    (documents,cb)=>{this.alterDocs(documents,cb);}, 
    (cb)=>{this.reindexSearch(cb);} 
    ]); 
} 

使用箭頭函數可確保類的成員函數被正確的上下文調用。