Ember.js中reopen()和reopenClass()之间的区别

时间:2012-12-24 22:55:41

标签: javascript ember.js

我在阅读emberjs.com上的文档时感到困惑 http://emberjs.com/documentation/#toc_reopening-classes-and-instances

在上面的页面中,它解释如下。

Person.reopen({
    // override `say` to add an ! at the end
    say: function(thing) {
    this._super(thing + "!");
    }
});
  

如您所见,重新打开用于向实例添加属性和方法。但是当您需要创建类方法或将属性添加到类本身时,您可以使用reopenClass。

Person.reopenClass({
    createMan: function() {
    return Person.create({isMan: true})
    }
});

Person.createMan().get('isMan') // true

虽然解释说“reopen用于向实例添加属性和方法。”,我认为上面显示的两个示例都讨论了如何创建类方法或将属性添加到类本身,而不是实例。

我误解了它的内容吗? 我不是一个经验丰富的程序员,所以我可能会被误解......

如果我被误解,请说明何时使用reopen和reopenClass。

提前致谢!

2 个答案:

答案 0 :(得分:17)

文档并没有很好地解释这一点,但 是一个非常棘手的主题。

顺便说一句,它现在住在: http://emberjs.com/guides/object-model/reopening-classes-and-instances/

谈论面向对象编程的一个问题是,它经常被解释如下: - 对象是对象。对象是类的实例。 - 类是对象。 - 实例是对象,并且有一个类。

这个解释根本不能帮助任何人,而且似乎是一个递归问题(即引用没有结束......一个对象是一个实例作为对象的类......(重复))。

我更倾向于以下列方式推理:

当人们编写代码时,他们经常描述类和实例。类是一种东西。水果是一个阶级的例子。我们在这里不是在谈论一件特别的事情,我们谈论的是一个整体的课程"事物(因此得名)。

请注意,它不是真正的课程。只有在它生活的时候它才真实。并且"在计算机的记忆中"。在那之前,它是对课程的描述。通常当人们编写代码时,他们会在文本文件中编写文本,而这只是计算机内部实际代码的描述,当计算机将其解释或编译为机器代码时。

当你意识到一个类实际上它本身就是一个描述时,会发现棘手的一点。它是对一系列潜在真实物体的描述。

在计算机中,当你创建一个苹果"时,它就是一个实例。它也是一个对象。它的类是Apple,它在计算机中也是一个真实的实时对象。当我们谈论Apple时,这是一个想法。它在现实中并不存在,但是对于计算机来说,它必须使它存在于现实中,所以" Apple"是一个具体的,真实的对象,即使它也是一个抽象。

我认为最后一点是人们对物体感到困惑的原因。类是抽象,但为了使计算机能够对它们进行交谈和推理,它们必须是真实的。所以,我们决定..."类意味着抽象,实例意味着真实" ...

麻烦的是,我们有继承......这带来了抽象的的想法......所以在我们的水果模型中,你面前有特定的苹果,这是也是水果,水果也是食物。实际上,食物实际上不是作为一种东西或一组东西存在,除非我们说“这种食物,这种苹果"或者世界上所有的食物"”,或者"你妈妈的烤宽面条"然后它是一个抽象的想法......

所以,在我们面向对象的计算机中,我们说"定义Food是一种Object,现在定义Fruit是一种Food,现在定义Apple是一种Fruit,现在定义这个apple ,这是一种Apple"。

现在意味着:    - 对象是Food的类,Food是Object的一个实例,Food也是一个类!    - 食物是水果的类,水果是食物的一个例子,水果本身也是一个类!    - Fruit是Apple的课程,Apple是Fruit的一个实例,Apple也是一个类!    - Apple是你的苹果课程,你的苹果是Apple的一个实例(因此也是Fruit,Food和Object!)。但是,它不是一个类,它只是一个对象。

为了推理你的苹果,我们说它是一个对象(注意小写的o),它也是一个苹果,一个水果和一种食物,而且......这里和#39;是踢球者..它也是一个对象。

所以现在希望我们能够理解你的苹果是一个物体,一个实例(苹果,水果,食物和物体),一个苹果,一个水果,一个食物和一个物体,但它不是一个班级。

所以...如果你向一个类中添加一个实例方法,那么它就不会在该类上可用,但它可以在所有实例上使用类。如果添加一个类方法,它将在该类(和子类)上可用。因此,如果向Apple添加实例方法,那么apple的所有实例都将能够运行该方法。但是,如果你只为你的苹果添加方法,那么只有你的苹果会有这种方法。我的苹果赢了。如果向Apple添加一个类方法,那么只有Apple类才能运行该方法(方便的是,您也可以通过它的所有实例访问)。类方法适用于不会更改特殊实例的内容。实例方法适用于改变特殊实例(通常)的事物。属性/属性也是如此。你不会在Apple类上创建一个名为" Apple color"因为这听起来像是与特定的苹果(即实例)有关。希望能稍微澄清一下:)

答案 1 :(得分:1)

在我尝试使用reopen()和reopenClass()之后,我发现了它们之间的区别。

以下是我的实验结果。

var Person = Ember.Object.extend({

    name:"",
    alive:true,
    sayHi:function(){
        alert("hi");
    }

});

Person.reopenClass({
    age:30,

    sayHo:function(){
    alert("ho");
}   

});

Person.reopen({
height:180,
sayYo:function(){
    alert("yo");
}
})

var person = Person.create({
    name:"Tom"
});


//person.reopenClass();//error!!

person.reopen({
    sayWhat:function(){
        alert("what!?");
    },

    weight:100

});

console.log(Person.alive);//undefined
console.log(Person.age);//30
console.log(Person.height);//undefined
console.log(Person.weight);//undefined

console.log(person.alive);//true
console.log(person.name);//Tom
console.log(person.height);//180
console.log(person.weight);//100

person.sayHi();//it works

//person.sayHo();//it doesn't work
Person.sayHo();//it works

person.sayYo();//it works
//Person.sayYo();//it doesn't work

//Person.sayWhat();//it doesn't work
person.sayWhat();