ember 中我们用 extend
来扩展一个类, 它的工作机制非常类似 prototype. 开发中我几次碰到下面这个问题,
才开始重视这个知识点, 因为平常 ember
很好用太容易忽略这些小问题了.
{% highlight javascript %} var Post = Ember.Object.extend({ comments: [] }
var good1 = Post.create({comments: []}); var good2 = Post.create({comments: []});
var bad1 = Post.create(); var bad2 = Post.create();
var comment = Comment.create()
good1.get(‘comments’).pushObject(comment); // good2.get(‘comments’) is []
bad1.get(‘comments’).pushObject(comment); // bad2.get(‘comments’) is [comment] {% endhighlight %}
如上述, Post 类有个 comments
属性, 如果你往 good 1 和 2 里面加评论, 没有问题.
但如果你往 bad 1 和 2 里面加评论, 它们的评论会同时出现在两个 post 里面!
原因是创建 bad post 时, 没有传入 comments 属性, 所以它们是共享类的 comments 属性的; 可以简单把这种情况下创建的 post 的 comments 是 prototype 的.
解决方法有两个:
- create 时传入 comments.
- 在 init 方法里面 set comments.
下面是 extend 的源码, 可以看到它用到了 reopen, 有兴趣的可以研究下.
{% highlight javascript %} extend: function extend() { var Class = makeCtor(); var proto; Class.ClassMixin = Mixin.create(this.ClassMixin); Class.PrototypeMixin = Mixin.create(this.PrototypeMixin);
Class.ClassMixin.ownerConstructor = Class;
Class.PrototypeMixin.ownerConstructor = Class;
reopen.apply(Class.PrototypeMixin, arguments);
Class.superclass = this;
Class.__super__ = this.prototype;
proto = Class.prototype = o_create(this.prototype);
proto.constructor = Class;
generateGuid(proto);
meta(proto).proto = proto; // this will disable observers on prototype
Class.ClassMixin.apply(Class);
return Class;
} {% endhighlight %}