Прототипическое наследование, зачем нам нужно Object.create? [Дубликат]

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

Однако вам следует избегать нескольких подключений от одного и того же сценария, независимо от одного API или другого. Поскольку это будет обременять ваш сервер базы данных и исчерпывать его ресурсы. Итак, хотя технически вы можете, вы не должны смешивать разные расширения в своем коде, за исключением короткого периода рефакторинга.

48
задан Felix Kling 13 July 2013 в 10:15
поделиться

4 ответа

В следующем я предполагаю, что вас интересует только то, почему Object.create является предпочтительным для настройки наследования.

Чтобы понять преимущества, давайте сначала проясним, что такое «класс» в JavaScript. У вас есть две части:

  1. Функция конструктора. Эта функция содержит всю логику для создания экземпляра «класса», то есть конкретного кода.
  2. Объект прототипа. Это объект, наследуемый экземпляром.

Наследование устанавливает отношение is-a , например, Dog - a Animal. Как это выражается в терминах функции-конструктора и объекта-прототипа?

Очевидно, что собака должна иметь те же методы, что и животное, то есть объект Dog prototype должен каким-то образом включать методы из прототипа Animal . Существует несколько способов сделать это. Вы часто увидите это:

Dog.prototype = new Animal();

Это работает, потому что экземпляр Animal наследуется от объекта Animal прототипа . Но это также означает, что каждая собака наследует от один специфический экземпляр Animal . Кажется, это немного странно. Может ли конкретный код экземпляра запускаться только в функции конструктора ? Внезапно экземпляр специфический код и прототип методы кажутся смешанными.

Мы фактически не хотим запускать экземпляр Animal в этот момент, нам нужны только все методы из объекта Animal prototype . Это позволяет нам Object.create:

Dog.prototype = Object.create(Animal.prototype);

Здесь мы , а не , создаем новый экземпляр Animal, получаем только прототипы. Конкретный код экземпляра экземпляра выполняется точно там, где он должен быть, внутри конструктора:

function Dog() { 
   Animal.call(this, 'Dog'); 
}

Самое большое преимущество заключается в том, что Object.create всегда будет Работа. Использование new Animal() работает только в том случае, если конструктор не ожидает никаких аргументов. Представьте, если конструктор выглядел так:

function Animal(name) { 
    this.name = name.toLowerCase();
}

Вам всегда нужно передать строку в Animal, иначе вы получите сообщение об ошибке. Что вы пройдете, когда будете делать Dog.prototype = new Animal(??);? На самом деле не имеет значения, какую строку вы передаете, если передать что-то , которое, надеюсь, покажет вам, что это плохой дизайн.


Некоторые говорят, что Dog.prototype = Animal.prototype; также может работать. Итак, теперь я полностью смущен

Все, что «добавляет» свойства от Animal.prototype до Dog.prototype, «будет работать». Но решения имеют разное качество. В этом случае у вас будет проблема, что любой метод, который вы добавите в Dog.prototype, также будет добавлен в Animal.prototype.

Пример:

Dog.prototype.bark = function() {
    alert('bark');
};

Поскольку Dog.prototype === Animal.prototype , все экземпляры Animal теперь имеют метод bark, что, конечно же, не то, что вы хотите.

Object.create (и даже new Animal) добавляют один уровень косвенности к наследованию, создавая новый объект, который наследует от Animal.prototype, и этот новый объект становится Dog.prototype.

< hr>

Наследование в ES6

ES6 вводит новый синтаксис для создания функций-конструкторов и методов прототипа, который выглядит следующим образом:

class Dog extends Animal {

  bark() {
    alert('bark');
  }

}

Это более удобно, чем то, что я объясняется выше, но, как оказалось, extends также использует внутренний эквивалент Object.create для настройки наследования. См. Шаги 2 и 3 в черновике ES6 . Это означает, что использование Object.create(SuperClass.prototype) является «более правильным» подходом в ES5.

111
ответ дан Aerovistae 21 August 2018 в 20:12
поделиться
  • 1
    +1 для "работает только в том случае, если конструктор не ожидает никаких аргументов & quot; – user123444555621 30 June 2013 в 19:00
  • 2
    Хорошее объяснение - хорошая работа. Но. Если Animal действительно нуждается в чем-то, установленном в конструкторе, можно утверждать, разрешает ли Object.create создавать полузапеченный Animal - это плюс или минус. Лично я чувствую, что это минус. Я все еще не уверен, что Object.create () настолько замечателен. – user949300 27 January 2015 в 00:17
  • 3
    Обычно я просто передаю и переменную options в свой конструктор, который затем расширяется. Тогда, если бы я хотел new Animal(), но с параметрами, это выглядело бы как new Animal({ species: 'dog', sound: 'bark' }). С этим, однако, если вы не используете jQuery, вам нужно создать собственную функцию расширения. – Banning 6 March 2016 в 21:56
  • 4
    Является ли хорошей практикой для нас, чтобы новые разработчики JavaScript продолжали глубоко погружаться в создание и обмен объектными прототипами с Object.Create в ES6? Особенно, если мы хотим быть правдой в деле делегирования объектов? Феликс, каково ваше мнение? – klewis 2 March 2018 в 16:55

Давайте будем понимать это только с кодом;

A.prototype = B.prototype;

function B() {console.log("I am B");this.b1= 30;}
    B.prototype.b2 = 40;

    function A() {console.log("I am A");this.a1= 10;}
    A.prototype.a2 = 20;

    A.prototype = B.prototype;

    A.prototype.constructor = A; 

    var a = new A;
    var b = new B;

    console.log(a);//A {a1: 10, b2: 40}
    console.log(b);//B {b1: 30, b2: 40}

    console.log(A.prototype.constructor);//A
    console.log(B.prototype.constructor);//A
    console.log(A.prototype);//A {b2: 40}
    console.log(B.prototype);//A {b2: 40}
    console.log(a.constructor === A); //true
    console.log(b.constructor === A); //true

console.log(a.a2);//undefined

enter image description here [/g0]

A .prototype = Object.create (B.prototype);

function B() {console.log("I am B");this.b1= 30;}
B.prototype.b2 = 40;

function A() {console.log("I am A");this.a1= 10;}
A.prototype.a2 = 20;

A.prototype = Object.create(B.prototype);

A.prototype.constructor = A; 

var a = new A;
var b = new B;

console.log(a);//A {a1: 10, constructor: function, b2: 40}
console.log(b);//B {b1: 30, b2: 40} 

console.log(A.prototype.constructor);//A
console.log(B.prototype.constructor);//B
console.log(A.prototype);//A {constructor: function, b2: 40}
console.log(B.prototype);//B {b2: 40}
console.log(a.constructor === A); //true
console.log(b.constructor === B); //true
console.log(a.a2);//undefined

enter image description here [/g1]

5
ответ дан Amit Kumar Gupta 21 August 2018 в 20:12
поделиться

Я немного проиллюстрирую разницу:

Вот что в основном происходит, когда вы пишете new Animal():

    //creating a new object
    var res = {};

    //setting the internal [[prototype]] property to the prototype of Animal
    if (typeof Animal.prototype === "object" && Animal.prototype !== null) {
        res.__proto__ = Animal.prototype;
    }

    //calling Animal with the new created object as this
    var ret = Animal.apply(res, arguments);

    //returning the result of the Animal call if it is an object
    if (typeof ret === "object" && ret !== null) {
        return ret;
    }

    //otherise return the new created object
    return res;

И вот что в принципе происходит с Object.create:

    //creating a new object
    var res = {};

    //setting the internal [[prototype]] property to the prototype of Animal
    if (typeof Animal.prototype !== "object") {
        throw "....";
    }
    res.__proto__ = Animal.prototype;

    //return the new created object
    return res;

Таким образом, он делает то же самое, но не вызывает функцию Animal, а также всегда возвращает новый созданный объект. В вашем случае вы получаете два разных объекта. С помощью первого метода вы получите:

Dog.prototype = {
    name: undefined,
    __proto__: Animal.prototype
};

и со вторым методом:

Dog.prototype = {
    __proto__: Animal.prototype
};

Вам действительно не нужно иметь свойство name в вашем прототип, потому что вы уже назначили его вашему экземпляру Dog с помощью Animal.call(this, 'Dog');.

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

7
ответ дан basilikum 21 August 2018 в 20:12
поделиться

Во-первых, запуск конструктора Animal может иметь нежелательные побочные эффекты. Рассмотрим это:

var Animal = function(name) {
    this.name = name;
    Animal.instances.push(this);
};
Animal.instances = [];

Эта версия будет отслеживать все созданные экземпляры. Вы не хотите, чтобы ваш Dog.prototype был записан там.

Во-вторых, Dog.prototype = Animal.prototype - плохая идея, поскольку это означало бы, что bark станет методом Animal.

9
ответ дан user123444555621 21 August 2018 в 20:12
поделиться
  • 1
    Если этот конструктор Animal имеет нежелательные побочные эффекты, это проблема с дизайном или кодом, а не с технологией наследования. – user949300 27 January 2015 в 03:09
Другие вопросы по тегам:

Похожие вопросы: