敲除:上下文在 observable.subscribe 中的指令之前更改

Knockout : context changed before the instruction in observable.subscribe

我正在尝试将我的模型与我的 ViewModel 分开,因为我需要两个不同 ViewModel 中的模型。所以我试过了:

var ConversationManager = {
    conversations: ko.observableArray([
        {id: 3, receiver:'Toto'}
    ])
};

function ConversationDialogViewModel(){
    var self = this;

    ConversationManager.conversations.subscribe(function(context){
        console.log('Before :', context); // context.test == true ???

        for(var i = 0; i < context.length; i++){
            if(context[i].id % 2 == 0 && !context[i].test){
                console.log('Insertion Called');
                context[i].test = true;
            }
        }
        console.log('After :', context);
    });

    ConversationManager.conversations.push({id: 4, receiver:'Jean'});
    ConversationManager.conversations.push({id: 5, receiver:'Paul'});
    ConversationManager.conversations.push({id: 6, receiver:'Bleu'});
}

不知何故,在第一个 console.log 中,当我在浏览器中按下 "Jean" 时,变量 "test" 存在并且甚至在我实际告诉 JS 之前就已正确设置为 true做吧。这怎么可能? 而且,我是否正确地分离了我的关注点?

来自the documentation

If you want to be notified of the value of an observable before it is about to be changed, you can subscribe to the beforeChange event.

你可以这样试试:

ConversationManager.conversations.subscribe(function(context){
    // ...
}, null, "beforeChange");

当控制台引用一个对象时(您可以在其中单击箭头打开它并查看其内容),它仍然是一个引用,而不是及时的快照。当您修改 context 时,无论您在调试器中查看哪个引用都没有关系,它们都是相同的。如果你想在某个时刻看到它,你需要将它转换成静态的(或放入断点)。

var ConversationManager = {
    conversations: ko.observableArray([
        {id: 3, receiver:'Toto'}
    ])
};

function ConversationDialogViewModel(){
    var self = this;

    ConversationManager.conversations.subscribe(function(context){
        console.log('Before :', JSON.stringify(context)); // context.test == true ???

        for(var i = 0; i < context.length; i++){
            if(context[i].id % 2 == 0 && !context[i].test){
                console.log('Insertion Called');
                context[i].test = true;
            }
        }
        console.log('After :', JSON.stringify(context));
    });

    ConversationManager.conversations.push({id: 4, receiver:'Jean'});
    ConversationManager.conversations.push({id: 5, receiver:'Paul'});
    ConversationManager.conversations.push({id: 6, receiver:'Bleu'});
}

new ConversationDialogViewModel();
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>