15

我在阅读 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 + "!");
    }
});

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

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

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

尽管解释说“重新打开用于向实例添加属性和方法。”,但我认为上面显示的两个示例都在谈论如何创建类方法或将属性添加到类本身,而不是实例。

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

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

提前致谢!

4

2 回答 2

16

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

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

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

这种解释对任何人都没有帮助,而且似乎是一个递归问题(即引用没有尽头......一个对象是一个类的实例,它是一个对象......(重复))。

我更喜欢用以下方式推理:

当人们编写代码时,他们经常描述类和实例。类是一种东西。Fruit 就是一个类的例子。我们在这里不是在谈论特定的事物,而是在谈论整个“类别”的事物(因此得名)。

请注意,这不是真正的课程。只有当它是“活的”和“在计算机的内存中”时,它才是真实的。在那之前,它是一个类的描述。通常,当人们编写代码时,他们会在文本文件中写入文本,而这只是对计算机内部真实代码的描述,当计算机将其解释或编译成机器代码时会发生这种情况。

当您意识到一个类实际上本身也是一个描述时,就会出现棘手的问题。它是对一系列潜在真实对象的描述。

在计算机中,当您创建“一个苹果”时,这就是一个实例。它也是一个对象。它的类是 Apple,它在计算机中也是一个真实的活体。当我们谈论苹果时,这是一个想法。它不存在于现实中,但要让计算机使用某种东西,它必须让它存在于现实中,所以“Apple”是一个具体的、真实的对象,尽管它也是一个抽象。

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

问题是,我们有继承......这带来了抽象的想法......所以在我们的水果模型中,你面前有一个特定的苹果,它也是一个水果,而水果也是一个食物. 实际上,食物实际上并不作为一个东西或一组东西存在,除非我们说“这个食物,这个苹果”,或者“世界上所有的食物”,或者“你妈妈的千层面”,那么它就是一个抽象的概念...

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

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

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

所以现在希望我们能够理解你的苹果是一个对象,一个实例(苹果、水果、食物和对象)、一个苹果、一个水果、一个食物和一个对象,但它不是一个类.

所以...如果您向一个类添加一个实例方法,那么它在该类上将不可用,但在该类的所有实例上都可用。如果您添加一个类方法,它将在该类(和子类)上可用。因此,如果您向 Apple 添加一个实例方法,那么所有 Apple 实例都将能够运行该方法。但是,如果你只为你的苹果添加一个方法,那么只有你的苹果会有那个方法。我的苹果不会。如果您向 Apple 添加一个类方法,那么只有 Apple 类能够运行该方法(您也可以方便地通过其所有实例访问该方法)。类方法适用于不改变特定实例的事物。实例方法适用于确实会改变的事物实例(一般)。属性/属性也是如此。您不会在 Apple 类上创建一个名为“Apple colour”的类方法,因为这听起来像是与特定的Apple(即实例)有关。希望这能把事情弄清楚一点:)

于 2014-05-02T05:29:36.380 回答
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();
于 2012-12-25T02:13:02.053 回答