2012-04-14 78 views
2

我試圖在服務器端JavaScript(Node)中將數據庫中的數據建模爲「類」。 目前,我只是在適當的地方使用傳統構造函數模式和原型方法,並將構造函數暴露爲整個module.exports。事實上,這是服務器端對於問題的核心並不重要,但我想我會提供它作爲參考。在原型方法中修改內部函數的實例變量

的代碼的問題區域看起來是這樣的:

User.prototype.populate = function() { 
    var that = this;  
    db.collection("Users").findOne({email : that.email}, function(err, doc){ 
     if(!err) { 
      that.firstName = doc.firstName; 
      that.lastName = doc.lastName; 
      that.password = doc.password; 
     } 
     console.log(that); //expected result 
    }); 
    console.log(that); //maintains initial values 
}; 

每當我調用這個函數,一旦findOne()完成更改對象不存在。我意識到this的範圍更改爲具有新函數範圍的全局對象,因此我保留其參考文獻that。如果console.log(that)來自匿名函數內,數據將按照預期顯示在其屬性中。但是,如果我在功能完成後記錄了that,它將保持它在函數開始時的狀態。

這裏發生了什麼事以及我如何才能按預期更改實例變量?

回答

2

「不過,如果我登錄,一旦功能已經完成,...」

通過這個我假設你正在做這樣的事情...

var user = new User 

user.populate(); 

console.log(user); 

如果是這樣,console.log將在異步回調到.findOne()被調用之前很長時間運行。

需要在回調中調用依賴於對findOne的響應的任何代碼。


編輯:你的更新是從上面我舉的例子有點不同,但道理是一樣的。

將回調傳遞給findOne方法的全部原因是它會執行異步活動。如果沒有,這個回調沒有任何理由。您只需在撥打findOne之後直接放置內部代碼,就像您使用console.log()一樣。

但是因爲它是異步,後續代碼不會等待執行。這就是爲什麼你要在控制檯中獲取未填充的對象。

如果您爲每個console.log()添加一個標籤,您會發現它們的執行順序不正確。


var that = this;  
db.collection("Users").findOne({email : that.email}, function(err, doc){ 
    if(!err) { 
     that.firstName = doc.firstName; 
     that.lastName = doc.lastName; 
     that.password = doc.password; 
    } 
    console.log("inside the callback", that); // this happens Last!!! 
}); 

console.log("outside the callback", that); // this happens First!!! 

所以很清楚,一旦你觀察員console.log的順序調用空單的回調裏面的人之前發生的事情。


編輯:你也可以有你的.populate()方法會收到.findOne回調內部調用的回調。

User.prototype.createNickName = function() { 
    this.nickname = this.firstName.slice(0,3) + '_' + this.lastName.slice(0,3); 
}; 

    // >>>------------------------------v----receive a function argument... 
User.prototype.populate = function(callback_func) { 
    var that = this;  
    db.collection("Users").findOne({email : that.email}, function(err, doc){ 
     if(!err) { 
      that.firstName = doc.firstName; 
      that.lastName = doc.lastName; 
      that.password = doc.password; 
     } 

      // all users will have the "createNickName()" method invoked 
     that.createNickName(); 

      // ...and invoke it in the callback. 
     callback_func.call(that); 

      // By using .call(), I'm setting the "this" value 
      // of callback_func to whatever is passed as the first argument 
    }); 
}; 

// this user wants to log the firstName property in all caps 
var user1 = new User; 

user1.populate(function() { 
    console.log(this.firstName.toUpperCase()); 
}); 


    // this user wants to log the the whole name 
var user2 = new User; 

user2.populate(function() { 
    console.log(this.firstName + ' ' + this.lastName); 
}); 


    // this user wants to verify that the password is sufficiently secure 
var user3 = new User; 

user3.populate(function() { 
    console.log(verify_password(this.password)); 
}); 
+0

這是正確的。雖然這發生在外部調用user.populate()以及populate()方法本身內(但不在findOne()的範圍內)。我已更新帖子以反映我的意思。 – DuxPrime 2012-04-14 01:33:59

+0

@ user574930:刷新瀏覽器。我已經更新了我的答案。 – 2012-04-14 01:34:50

+0

有了這些知識,那麼我將如何能夠實現我正在尋找的效果,我可以簡單地調用populate()方法並知道對象的屬性將得到更新? – DuxPrime 2012-04-14 01:37:48