2012-07-29 41 views
5

我试图回答这个问题:emberjs: add routes after app initialize()玩Ember.Object.reopen(),为什么我有这些结果?

我开始Ember.Object.reopen(玩),了解它是如何工作的,也许发现回答前一个问题的一种方式。

我觉得有点纳闷,不明白这段代码的行为:

的jsfiddle:http://jsfiddle.net/Sly7/FpJwT/

<script type="text/x-handlebars"> 
    <div>{{App.myObj.value}}</div> 
    <div>{{App.myObj2.value}}</div> 
    <div>{{App.myObj3.value}}</div> 
</script> 
App = Em.Application.create({}); 

App.MyObject = Em.Object.extend({value: 'initial'}); 

App.set('myObj', App.MyObject.create()); 

Em.run.later(function(){ 
    App.get('myObj').reopen({ 
    value: "reopenOnInstance"   
    }); // the template is not updated, 'initial' is still diplayed, but 
    console.log(App.get('myObj').get('value')); // print 'reopenOnInstance' 

    App.MyObject.reopen({ 
    value: "reopenOnClass"  
    }); 
    App.set('myObj2',App.MyObject.create()); // the template is updated and 
    console.log(App.get('myObj2').get('value')); //print 'reopenOnClass' 

    App.myObj3 = App.MyObject.create(); // the template is not updated but 
    console.log(App.myObj3.get('value')); // print 'reopenOnClass' 

    Em.run.later(function(){ 
    App.get('myObj').set('value', "setWithSetter"); // the template is updated and 
    console.log(App.get('myObj').get('value')); // print 'setWithSetter' 

    App.get('myObj2').set('value', "setWithSetter"); // the template is updated and 
    console.log(App.get('myObj2').get('value')); // print 'setWithSetter' 

    App.myObj3.set('value', "setWithSetter"); // the template is not updated but 
    console.log(App.myObj3.get('value')); // print 'setWithSetter' 

    }, 2000); 
},2000); 

如果有人能解释这是怎么回事,特别是为什么模板有时不会更新,有时会更新,以及在调用类和实例时调用reopen有什么区别。

回答

5

不是100%肯定,但我会尽力回答你的问题。

首先让我们看看“myObj3”。烬getter/setter方法触发模板中的更新(它们触发内部事件,导致每个属性/观察者知道发生的事情)。只需手动设置值即可更新值,但不会触发这些事件,因此UI中没有任何更改。有点像当你使用可变列表你使用pushObject来确保UI更新。

现在让我们看看你的“重新打开”。当你在类上重新打开时,它会像你期望的那样工作并更新基类。当你重新打开一个实例时,它实际上是在创建一个混合并将它放在对象的顶部。这意味着当您执行“获取”余烬时,会对该对象的mixin &迭代以返回值。它发现mixin并获取对象之前的值;实际上你可以用“return'foo'+ this._super()”替换实例上的方法来取代'foo initial'(想象你的对象具有像洋葱一样的图层)。如果你的对象之上有一组mixin,那么如果你直接设置了一些东西(但“get”可以很好地工作),你将很难找到正确的值。这导致了一般规则,即应始终使用“set”而不是直接引用。

备注:您可以调用“getPath”而不是“get”,并且可以使用相对或绝对路径。比如App.getPath('myObj2.value'),它将使代码更易于管理。也去“setPath”。

最后:因为你确实改变了值(它在那里),但是更新ui的触发器从未被触发,因为你从未在“myObj3”对象上调用set。

编辑:在最新版本的烬它看起来像一个实例重新打开确实对对象(如果该密钥已存在)合并。如果您添加新内容,mixin只会包装。

+0

这一切都有道理。非常感谢你给我启迪。所以如果我理解的很好,重新打开一个像我这样做的实例,与'App.get('myObj')。value ='reopenOnInstance''有同样的行为吧? 我知道了getPath,方法,现在使用最新的ember,get具有相同的行为,您可以执行'obj.get('otherObj.someProperty')'。 – 2012-08-04 08:06:31

+0

请参阅编辑。这意味着你是正确的,直接设置值就像重新打开实例一样。但是如果你有一些绑定到那个值的东西(比如UI),Ember会抛出一个错误,因为没有使用“set”(使用[fiddler](http://jsfiddle.net/scispear/n5B5d/)来查看错误)。 – SciSpear 2012-08-04 13:22:54

+0

再次感谢您的编辑:)。我认为现在答案是完整的,因为我没有更多的事情要阐明。 – 2012-08-04 17:36:34

相关问题