Javascript: как правильно расширить класс

поиск по интернету я всегда натыкаюсь на этот подход расширения классов Javascript

function extend(Child, Parent) {
    var F = function() { }
    F.prototype = Parent.prototype
    Child.prototype = new F()
    Child.prototype.constructor = Child
    Child.superclass = Parent.prototype
}

но чем это отличается от этого?

  function extend(Child, Parent) {
    var p = new Parent()
    Child.prototype = p
    Child.prototype.constructor = Child
    Child.superclass = p
  }

этот последний также работает идеально. Так почему я должен использовать этот extra var F = function() { } двигаться дальше?

3 ответов


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

вот почему они используют функцию "прокси", которая позволяет получить новый объект, который наследуется от Parent() фактически не вызывая Parent().


вот простой пример:

function Person(name, age) {
    if (name === undefined)
        throw "A name is required";
    this.name = name + "";
    this.age = age;
}

если Person является родителем, он выдаст ошибку, потому что не было name прошло.


первым примером является (как cookie monster, упомянутый в комментарии) прокладка для следующего фрагмента кода, который может быть проще понять.:

function extend(Child, Parent) {
  Child.prototype = Object.create(Parent.prototype);
  Child.prototype.constructor = Child;
  Child.superclass = Parent.prototype;
}

В принципе, эта реализация делает объект, который наследуют все дочерние экземпляры (Child.prototype) наследуется от объекта, который наследуют все родительские экземпляры (Parent.прототип.) Интуитивно это наиболее точное представление наследования классов, которое предоставляет JavaScript.

второй реализация extends имеет недостатки, поскольку все дочерние экземпляры наследуются от конкретного родительского экземпляра. Если между родительскими экземплярами существуют значительные различия (например, из-за параметров, переданных конструктору), дочерние экземпляры не могут точно представлять это, поскольку все они наследуются от родительского экземпляра, созданного путем вызова родительского конструктора без аргументов.

вот пример того, что может сделать первая реализация и вторая не могу:

function Parent(name, age) {
  this.name = name;
  this.age = age;
}
Parent.prototype.greet = function() { return 'I am parent ' + this.name; }

function Child(name){
  Parent.call(this, name, 20); // notice the call to the superclass
}
extend(Child, Parent);
Parent.prototype.greet = function() { return 'I am child ' + this.name + ' and i\'m ' + this.age; }

var c = new Child('Tom');
console.log(c.greet()); // I am child Tom and i'm 20

в качестве sidenote в дочернем конструкторе я вызвал родительский конструктор. Это на самом деле довольно распространено при работе с классическим наследованием, так что это еще один момент для первой реализации. На самом деле это не требуется, Дочерний конструктор может безопасно игнорировать вызов родительского конструктора, но имейте в виду, что этот вызов в основном гарантирует, что новый созданный объект является допустимым родительским экземпляром, прежде чем быть дочерним экземпляром. В моем примере, если вы если не вызывать родительский конструктор, свойства name и age не будут установлены на дочернем экземпляре, поэтому метод greet вернет I am child undefined and i'm undefined, далеко от того, что вы ожидали бы.


стоит изучить различные способы расширения и добавления битов к объекту в JavaScript.

использование конструкторов (функция (глобальная) { суперкласс функция() { }

    var p = SuperClass.prototype;

    p.doSomething = function() {
        console.log('do something (super)')
    };

    function OtherClass() {
      SuperClass.call(this); 
    }

    OtherClass.prototype = new SuperClass();

    Window.OtherClass = OtherClass;
}(window));

var o = new OtherClass();

использование объекта.create (no double instantiation) - не поддерживается во всех браузерах.

(function (global) {
    // SuperClass - superclass
    function SuperClass() {

    }

    var p = SuperClass.prototype;

    p.doSomething = function() {
        console.log('do something (super)')
    };

    function OtherClass() {
      SuperClass.call(this); 
    }

    OtherClass.prototype = Object.create(SuperClass.prototype);

    Window.OtherClass = OtherClass;
}(window));

Функциональные Миксины: Когда вы хотите смешать общий набор методов / свойств в объект.

var mixin = function () {
    this.methodA = function () {

    };

    this.methodA = function () {

    };

    return this;
}

var object = function () {
    this.methodB = function () {

    }
}

mixin.call(object.prototype);

очень хорошее объяснение деталей все методы:

http://javascriptweblog.wordpress.com/2011/05/31/a-fresh-look-at-javascript-mixins/