2014-01-11 2 views
1

При чтении https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call для раздела «Использование вызов цепи конструкторами для объекта»:Javascript Прототип Наследование и Chaining конструкты для объекта

function Product(name, price) { 
    this.name = name; 
    this.price = price; 

    if (price < 0) 
    throw RangeError('Cannot create product "' + name + '" with a negative price'); 
    return this; 
} 

function Food(name, price) { 
    Product.call(this, name, price); 
    this.category = 'food'; 
} 
Food.prototype = Object.create(Product.prototype); 

function Toy(name, price) { 
    Product.call(this, name, price); 
    this.category = 'toy'; 
} 
Toy.prototype = Object.create(Product.prototype); 

var cheese = new Food('feta', 5); 
var fun = new Toy('robot', 40); 

Я прочитал, что прототип объект на самом деле является сам объект, который указывает к ячейкам памяти свойств конструктора.

В function Food(name, price) он наследует свойства Изделия конструктора с Product.call(this). Что делает Food.prototype = Object.create(Product.prototype);? Является ли это добавлением еще одного прототипа в Food (если это возможно, у вас есть 2 прототипа)? Или это дополнение к прототипу Продовольствия с теми же образцами прототипа Продукта (который он уже унаследовал, поэтому для меня не имеет смысла эфир)?

+1

'Food.prototype = Object.create (Product.prototype) 'как' extends' на других языках. 'Product.call (this)' как 'super'. – elclanrs

ответ

1

Позвольте коду говорить сами за себя. Object.create в основном делает это:

Object.create = function (o) { 
    //Object.create equals an anonymous function that accepts one parameter, 'o'. 

    function F() {}; 
    //Create a new function called 'F' which is just an empty object. 

    F.prototype = o; 
    //the prototype of the 'F' function should point to the 
    //parameter of the anonymous function. 

    return new F(); 
    //create a new constructor function based off of the 'F' function. 
    }; 

Надеюсь, это поможет. Cheers

+1

Я не думаю, что этот полипол действительно помогает понять прототипическое наследование. Объяснение этого в обратном направлении ('new' в терминах' Object.create' и 'call') намного проще :-) – Bergi

1

Food.prototype = Object.create(Product.prototype) как extends на других языках. Product.call(this) это как super. С помощником и следующими конвенциями это помогает увидеть это соотношение:

Function.prototype.inherits = function(parent) { 
    this.prototype = Object.create(parent.prototype); // inherit parent's prototype 
    this.prototype.constructor = this; // point to the right constructor 
}; 

// A "class" 
var Product = (function(){ 
    // constructor 
    function Product(name, price) { 
    this.name = name; 
    this.price = price; 
    } 
    return Product; 
}()); 

var Food = (function(_super){ 
    Food.inherits(Product); // inherit Product's prototype methods 
    function Food(name, price) { 
    // call "super" to inherit instance properties 
    _super.call(this, name, price); 
    this.category = 'food'; 
    } 
}(Product)); // the parent class AKA "super" 

Это не 100% эквивалентно, но это должно дать вам общее представление о том, как работает наследование в JS по сравнению с другими языками. Он может выглядеть довольно похожим, как вы видите.

4

Суть проблемы камеры подытоживается как «зачем вам вообще устанавливать прототипы»? Другими словами, почему этого недостаточно для вызова конструктора базового класса, а не для установки прототипа?

Фокус в том, что вы могли бы не установить прототип функции дочернего класса! Ваш тривиальный пример будет работать без него. Закомментируйте строку, и вы увидите, что код работает и без этой линии:

Food.prototype = Object.create(Product.prototype); 

Это происходит потому, что все ваши свойства объектов устанавливаются в конструкторах и приковав конструкторы (вызов конструктора базового класса) вы имеют все свойства, установленные для экземпляров дочерних классов.

Рассмотрим однако это:

function Base() { 
    this.BaseClassMethod = function() {} 
} 

против

function Base() { 
} 

Base.prototype.BaseClassMethod = function() {} 

Как вы можете видеть, нет полей, но метод. Семантически оба фрагмента определяют функцию-конструктор, которая создает экземпляры, имеющие единственный метод BaseClassMethod. Однако в первом фрагменте есть новая дополнительная функция, созданная для каждого созданного экземпляра класса, тогда как во втором фрагменте определение метода является общим.

Этот очень простой пример показывает, что одна и та же семантика может быть достигнута различными способами, которые имеют разные профили - в приведенном выше примере это по меньшей мере различный объем памяти.

Еще одно различие между этими двумя, что в последнем случае, эта функция может быть переопределена где-то в будущем, и новая версия влияет все ранее созданные экземпляры в то время как в первом фрагменте, что вы можете сделать, это изменить определение в определенных случаях, но не легко «во всех ранее созданных экземплярах».

Независимо от того, является ли это вашей целью, это еще одна история. Вы можете свободно выбирать между этими двумя способами назначения методов классам.

И там лежит ответ на ваш вопрос: без установки цепи прототипов, методы, определенные в базовом классе прототипа (последний сниппет) бы не наследоваться, если только называется конструктор базового класса из класса ребенка конструктора.

Другими словами, вызов как конструктора базового класса, так и установки цепи прототипа делает ваше наследование независимым о методах определения в базовом классе.

1

В функции Food (имя, цена) он наследует свойства продукта конструктора с Product.call (это).

Не совсем. Он применяет конструктор продукта к новому экземпляру Food, выполняя его код, например. отрицательная проверка цены.

«побочный продукт» - это то, что конструктор создает специфичные для экземпляра свойства объекта, да.

Что такое Food.prototype = Object.create (Product.prototype); делать? Является ли это добавлением еще одного прототипа в Food (если это возможно, у вас есть 2 прототипа)?

Точно. Это цепочки прототипы. Экземпляры Food, которые создаются new Food, наследуют свойства (включая методы) от Food.prototype, которые (по этому утверждению) наследуют свойства от Product.prototype.

Вы не можете видеть большую часть этого пользователя в настоящее время, так как у ваших объектов-прототипов пока нет методов. Добавить некоторый (возможно, «выходной» метод?) И проверить результаты.

0

Простая библиотека минималистичный наследование: (2К уменьшенная) https://github.com/haroldiedema/joii

Это в основном позволяет сделать следующее (и более):

// First (bottom level) 
var Person = new Class(function() { 
    this.name = "Unknown Person"; 
}); 

// Employee, extend on Person & apply the Role property. 
var Employee = new Class({ extends: Person }, function() { 
    this.name = 'Unknown Employee'; 
    this.role = 'Employee'; 

    this.getValue = function() { 
     return "Hello World"; 
    } 
}); 

// 3rd level, extend on Employee. Modify existing properties. 
var Manager = new Class({ extends: Employee }, function() { 

    // Overwrite the value of 'role'. 
    this.role = this.role + ': Manager'; 

    // Class constructor to apply the given 'name' value. 
    this.__construct = function(name) { 
     this.name = name; 
    } 

    // Parent inheritance & override 
    this.getValue = function() { 
     return this.parent.getValue().toUpperCase(); 
    } 
}); 

// And to use the final result: 
var myManager = new Manager("John Smith"); 
console.log(myManager.name); // John Smith 
console.log(myManager.role); // Manager 

console.log(myManager.getValue()); // HELLO WORLD 
Смежные вопросы