简体   繁体   English

对古典和原型继承的困惑Javascript

[英]Confusion over Classical and Prototypal Inheritance Javascript

// Prototye Inheritance // Prototye继承

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());

// Classical Inheritance //经典继承

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())

Can anyone tell me on how the second one is classical and the first one is prototypal . 任何人都可以告诉我第二个是经典的,第一个是原型 I was watching the http://www.objectplayground.com/ and i am totally confused as in both the cases we use Object.create() and as well as prototype object. 我正在观看http://www.objectplayground.com/ ,我完全感到困惑,因为在我们使用Object.create()prototype对象的情况下。

First, to get it straight, Javascript only has prototypal inheritance. 首先,为了实现它,Javascript只有原型继承。 What you can do is simulate "classical" inheritance. 你能做的是模拟 “经典”继承。 The difference between the two boils down to the syntax with which objects are instantiated - "classical" inheritance uses the more familiar constructor functions and "new" operator, which hide the inherent prototypal nature of Javascript's object creation and inheritance properties. 两者之间的区别归结为实例化对象的语法 - “经典”继承使用更熟悉的构造函数和“新”运算符,这隐藏了Javascript的对象创建和继承属性的固有原型性质。

Let's break down both cases a bit. 让我们分解一下这两种情况。

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

The prototype here is explicitly created, along with a "constructor" (or more properly named, initializing function). 这里的原型是明确创建的,还有一个“构造函数”(或更恰当命名的初始化函数)。

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

Now, creating objects is slightly clunky here. 现在,在这里创建对象有点笨拙。 First you need to call Object.create(), and then you need to call the initializer function. 首先,您需要调用Object.create(),然后您需要调用初始化函数。 This doesn't have to be the case though - here's a different sample prototype which does both in one swoop: 虽然这不是必须的 - 这里是一个不同的样本原型,它一举两得:

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);

Simulating "classical" inheritance relies on letting developers use the more familiar constructor functions and "new" operator to create their objects, but since it it just masking the prototypal inheritance of Javascript, it remains essentially the same thing. 模拟 “经典”继承依赖于让开发人员使用更熟悉的构造函数和“新”运算符来创建他们的对象,但由于它只是掩盖了Javascript的原型继承,它基本上是相同的。

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

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

This isn't much different from the prototypal inheritance one, except the Answer is decoupled from the now implicitly created prototype object(Which can be accessed via the Answer.prototype property) 这与原型继承没有太大的不同,除了Answer与现在隐式创建的原型对象(可以通过Answer.prototype属性访问)分离

var lifeAnswer = new Answer(100);

Practically, sugar for var lifeAnswer = Object.create(Answer.prototype); // Call Answer on the newly created object to initialize some values, eg with Answer.call(lifeAnswer, 100); 实际上, var lifeAnswer = Object.create(Answer.prototype); // Call Answer on the newly created object to initialize some values, eg with Answer.call(lifeAnswer, 100); var lifeAnswer = Object.create(Answer.prototype); // Call Answer on the newly created object to initialize some values, eg with Answer.call(lifeAnswer, 100);

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

firmAnswer.prototype is just the implicitly created prototype, very similar to firmAnswerPrototype in the first case. firmAnswer.prototype只是隐式创建的原型,与第一种情况下的firmAnswerPrototype非常相似。

To answer your specific question, the reason why they use Object.create() here is because inheritance via new quickly becomes very clunky. 为了回答你的具体问题,他们在这里使用Object.create()的原因是因为通过new继承很快变得非常笨重。 You would need to do something like: 您需要执行以下操作:

firmAnswer.prototype = new Answer();

But now you either need Answer to be an empty constructor( function Answer() {} ), or explicitly differentiate between calling it with no arguments(to use for inheritance), and calling it with arguments(to use for instantiating "Answer" objects). 但是现在你要么需要Answer是一个空构造函数( function Answer() {} ),要么明确区分调用它没有参数(用于继承),并用参数调用它(用于实例化“Answer”对象) )。

You have those backwards. 你有那些倒退。 The second one is prototypal because it uses the object's prototype property to inherit. 第二个是prototypal,因为它使用对象的prototype属性来继承。 This block 这个块

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

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

is assigning an instance of Answer to firmAnswer 's prototype. 正在为firmAnswer的原型分配一个Answer实例。 However, it's piss poor code, as it's not actually taking advantage of the inheritance, it's redeclaring the get function. 但是,它的代码很糟糕,因为它实际上没有利用继承,它重新声明了get函数。

I would avoid this code altogether. 我会完全避免这个代码。 Read Crockford's The Good Parts for a good distinction between the two types. 阅读Crockford的The Good Parts,以便区分这两种类型。

EDIT: To give a bit of an explanation (without referencing that code), here's the basic difference. 编辑:为了给出一些解释(没有引用该代码),这是基本的区别。

'Classical' inheritance in Javascript (the way I see it used) is when you override objects properties. Javascript中的“经典”继承(我看到它使用的方式)是当你覆盖对象属性时。 You have an object with a foo and a bar method. 你有一个带有foobar方法的对象。 You then use a library (like jQuery or Prototype) to call an extend method. 然后使用库(如jQuery或Prototype)来调用extend方法。 The method takes two arguments, a base object and a child object. 该方法有两个参数,一个基础对象和一个子对象。 It takes all of the properties of the base object, inserts the properties of the child object (possibly overwriting) and then returns a new object that has a mix of both properties. 它接受基础对象的所有属性,插入子对象的属性(可能覆盖),然后返回具有两个属性混合的新对象。 There's a bit more to it, but that's the gist. 还有一点,但这是要点。 It's just manipulating object properties without the prototype. 它只是在没有原型的情况下操纵对象属性。

Prototypal inheritance uses Javascript's built in prototype. Prototypal继承使用Javascript的内置原型。 A prototype is a chain of objects (essentially). 原型是一系列对象(本质上)。 Let's say you have an object B that inherits from A. To create a C class that inherits from B, we create a function named C and then assign B to the prototype. 假设您有一个继承自A的对象B.要创建一个继承自B的C类,我们创建一个名为C的函数,然后将B分配给原型。 Then, when a property is requested from C, Javascript will do the following: 然后,当从C请求属性时,Javascript将执行以下操作:

Check if the property exists on the instance of C. If not: 检查C实例上是否存在该属性。如果不存在:
Check if the property is on the prototype of B. If not: 检查属性是否在B的原型上。如果不是:
Check if the property is on the prototype of A. If not: 检查属性是否在A的原型上。如果不是:
Throw error. 抛出错误。

Sorry if it's a little vague. 对不起,如果它有点模糊。 I'm trying to simplify it a bit. 我试图简化一下。 There's a lot to the prototype in Javascript. Javascript中的原型有很多。 I would suggest reading some of Crockford's materials. 我建议你阅读一些Crockford的材料。

How is the second one is classical and the first one is prototypal 第二个是经典的,第一个是原型的

Both are using prototypical inheritance, there are no classes in JavaScript. 两者都使用原型继承,JavaScript中没有类。

The second one is called "classical" (sometimes "pseudoclassical") because it uses the class pattern and mimics the conventional class syntax (as known from Java) when objects are created with the new operator. 第二个被称为“经典”(有时是“伪古典”),因为当使用new运算符创建对象时,它使用类模式并模仿传统的类语法(如Java所知)。

The only difference is the .prototype link from the constructor function to the prototype object and the shorter instantiation syntax with only one command instead of two, what happens behind is the same in both approaches. 唯一的区别是从构造函数到原型对象的.prototype链接和只有一个命令而不是两个命令的更短的实例化语法,后面发生的事情在两种方法中是相同的。

As we can see in your example, also the inheritance between two "classes" is a bit different. 正如我们在您的示例中所看到的,两个“类”之间的继承也有所不同。 In both approaches the child prototype object inherits from the parent prototype object, and in both approaches you can call parent ("super") methods by invoking the functions explicitly on the child instance. 在这两种方法中,子原型对象都继承自父原型对象,在这两种方法中,您可以通过在子实例上显式调用函数来调用父(“超级”)方法。 Yet, in the "classical" pattern you need to declare a new constructor function for the child (to reference it), while in your explicit prototypical approach the children are inheriting the parent's .constructor method . 然而,在“经典”模式中,您需要为子项声明一个新的构造函数(以引用它),而在您的显式原型方法中,子项继承父项的.constructor 方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM