3

// 原型继承

var AnswerPrototype = {
    constructor: function(value){
        this._val = value;
    },
    get: function(){
        return this._val;   
    }
}

var lifeAnswer = Object.create(AnswerPrototype);
lifeAnswer.constructor(100);
alert(lifeAnswer.get());

var desertAnswer = Object.create(AnswerPrototype);
desertAnswer.constructor(200);
alert(desertAnswer.get());

var firmAnswerProtoype = Object.create(AnswerPrototype);
firmAnswerProtoype.get = function(){
     return AnswerPrototype.get.call(this);   
}

var luckyAnswer = Object.create(firmAnswerProtoype);
luckyAnswer.constructor(1);
alert(luckyAnswer.get());

var magicAnswer = Object.create(firmAnswerProtoype);
magicAnswer.constructor(2);
alert(magicAnswer.get());

// 经典继承

function Answer(value){
    this._val = value;
}

Answer.prototype.get = function(){
     return this._val;   
}

var lifeAnswer = new Answer(100);
alert(lifeAnswer.get());

var desertAnswer = new Answer(200);
alert(desertAnswer.get());

function firmAnswer(value){
     return Answer.call(this,value);   
}

firmAnswer.prototype = Object.create(Answer);
firmAnswer.prototype.constructor = firmAnswer;

firmAnswer.prototype.get = function(){
    return Answer.prototype.get.call(this);   
}

var luckyAnswer = new firmAnswer(20);
alert(luckyAnswer.get())

谁能告诉我第二个是经典的,第一个是原型的。我在看http://www.objectplayground.com/Object.create()并且在我们使用和prototype对象的情况下我都感到非常困惑。

4

3 回答 3

2

首先,直截了当地说,Javascript 只有原型继承。您可以做的是模拟“经典”继承。两者之间的区别归结为实例化对象的语法——“经典”继承使用更熟悉的构造函数和“new”运算符,它们隐藏了 Javascript 对象创建和继承属性的固有原型性质。

让我们稍微分解一下这两种情况。

var AnswerPrototype = {
   constructor: function(value){
      this._val = value;
   },
   get: function(){
      return this._val;   
   }
}

这里的原型是显式创建的,还有一个“构造函数”(或更恰当地命名为初始化函数)。

var lifeAnswer = Object.create(AnswerPrototype);
lifeAnswer.constructor(100);
alert(lifeAnswer.get());

现在,在这里创建对象有点笨拙。首先你需要调用 Object.create(),然后你需要调用初始化函数。但这不一定是这种情况 - 这是一个不同的示例原型,它一举两得:

var AnswerPrototype = {
   create: function(value){
      var obj = Object.create(AnswerPrototype);
      obj._val = value;
      return obj;
   },
   get: function(){
      return this._val;   
   }
}
var lifeAnswer = AnswerPrototype.create(100);

模拟“经典”继承依赖于让开发人员使用更熟悉的构造函数和“new”运算符来创建他们的对象,但由于它只是掩盖了 Javascript 的原型继承,所以它本质上保持不变。

function Answer(value){
    this._val = value;
}

Answer.prototype.get = function(){
     return this._val;   
}

这与原型继承没有太大区别,除了 Answer 与现在隐式创建的原型对象分离(可以通过 Answer.prototype 属性访问)

var lifeAnswer = new Answer(100);

实际上,糖为var lifeAnswer = Object.create(Answer.prototype); // Call Answer on the newly created object to initialize some values, e.g. with Answer.call(lifeAnswer, 100);

firmAnswer.prototype = Object.create(Answer);
firmAnswer.prototype.constructor = firmAnswer;

FirmAnswer.prototype 只是隐式创建的原型,与第一种情况下的firmAnswerPrototype 非常相似。

为了回答您的具体问题,他们在这里使用 Object.create() 的原因是因为通过继承new很快变得非常笨重。您需要执行以下操作:

firmAnswer.prototype = new Answer();

但是现在你要么需要Answer成为一个空的构造函数(function Answer() {}),要么明确区分不带参数调用它(用于继承)和带参数调用它(用于实例化“Answer”对象)。

于 2013-08-14T12:38:45.107 回答
1

你有那些倒退。第二个是原型,因为它使用对象的prototype属性来继承。这块

firmAnswer.prototype = Object.create(Answer);
firmAnswer.prototype.constructor = firmAnswer;

firmAnswer.prototype.get = function(){
    return Answer.prototype.get.call(this);   
}

正在分配AnswertofirmAnswer的原型的实例。然而,这是糟糕的代码,因为它实际上并没有利用继承,而是重新声明了get函数。

我会完全避免这段代码。阅读 Crockford 的 The Good Parts 可以很好地区分这两种类型。

编辑:给出一点解释(不参考该代码),这是基本的区别。

Javascript中的“经典”继承(我看到它使用的方式)是当您覆盖对象属性时。你有一个带有 afoo和一个bar方法的对象。然后,您可以使用库(如 jQuery 或 Prototype)来调用extend方法。该方法有两个参数,一个基础对象和一个子对象。它获取基础对象的所有属性,插入子对象的属性(可能覆盖),然后返回一个混合了这两个属性的新对象。它还有更多内容,但这就是要点。它只是在没有原型的情况下操作对象属性。

原型继承使用 Javascript 的内置原型。原型是一个对象链(本质上)。假设您有一个从 A 继承的对象 B。要创建从 B 继承的 C 类,我们创建一个名为 C 的函数,然后将 B 分配给原型。然后,当从 C 请求一个属性时,Javascript 将执行以下操作:

检查该属性是否在C的实例上。如果不存在:
检查该属性是否在B的原型上。如果不:
检查该属性是否在A的原型上。如果不:
抛出错误。

对不起,如果它有点模糊。我试图简化一点。Javascript 中有很多原型。我建议阅读Crockford 的一些资料。

于 2013-08-14T12:27:15.470 回答
1

第二个是经典的,第一个是原型的

两者都使用原型继承,JavaScript 中没有类。

第二个被称为“经典”(有时是“伪经典”),因为它使用类模式并在使用new运算符创建对象时模仿传统的类语法(从 Java 中知道)。

唯一的区别是.prototype从构造函数到原型对象的链接和更短的实例化语法,只有一个命令而不是两个,后面发生的事情在两种方法中都是相同的。

正如我们在您的示例中看到的那样,两个“类”之间的继承也有些不同。在这两种方法中,子原型对象都继承自父原型对象,并且在这两种方法中,您都可以通过在子实例上显式调用函数来调用父(“超级”)方法。然而,在“经典”模式中,您需要为子级声明一个新的构造函数(以引用它),而在您的显式原型方法中,子级继承父级的.constructor 方法

于 2013-08-14T12:37:45.880 回答