Javascript-прототип наследования: проблема, когда родитель и потомок получают один и тот же объект в качестве аргумента? - PullRequest
3 голосов
/ 07 апреля 2011

Я пытаюсь заставить прототипное наследование работать следующим образом:

// Parent constructor
function Parent(obj) {
    this.id = obj.id || 0;
    this.name = obj.name || "";
};

// Child constructor
function Child(obj) {
    Parent.call(this,obj);
    this.type = obj.type || "";
}

Child.prototype = new Parent;

Кажется, учебник ... но передача obj как родителю, так и ребенку, кажется, вызывает проблемы;Parent говорит, что obj не определено, когда ребенок пытается создать прототип с помощью Child.prototype = new Parent;.Единственный способ, которым я могу обойти это, - это уродливый хак:

// 'Hacked' Parent constructor
function Parent(obj) {
    if (obj) {
        this.id = obj.id || 0;
        this.name = obj.name || "";
    }
};

Конечно, есть лучший способ, но я нигде не могу найти ответ.Пожалуйста, помогите !!

Ответы [ 2 ]

5 голосов
/ 07 апреля 2011

Child.prototype = new Parent; создает нового Родителя без каких-либо параметров и возвращает его прототип, присваивая его Child.prototype. Этот подход работает хорошо, но проблема в том, что он работает только с родителями с 0 параметрами (new Parent является эквивалентом new Parent() в этом контексте).

Для конструкторов Parent с параметрами я предлагаю определить функцию наследования для обработки вашего наследования.

Исправление, которое я предложил ранее, было исправлением Child.prototype = Parent.prototype;. Это будет работать, но теперь Child.prototype является ссылкой на Parent.prototype, а не объектом. Другими словами, если вы добавите метод hello к Child, то Parent также получит этот метод. Плохие времена!

Лучшее решение этой проблемы - определить функцию inherits следующим образом:

function inherit(parentPrototype) {
  function F() {};
  F.prototype = parentPrototype;
  return new F;
}

То, что мы здесь делаем, немного отличается от простого назначения Parent.prototype Ребенку. Мы создаем новую функцию с прототипом родителя и возвращаем новый экземпляр функции F. Итак, когда вы добавляете методы в Child, вы фактически добавляете их в прототип F функция.

Чтобы создать объект Child сейчас, вы должны сделать:

function Child() {};
Child.prototype = inherit(Parent.prototype); // returns an instance of F

Затем вы можете добавлять методы к Ребенку, не затрагивая Родителя.

0 голосов
/ 07 апреля 2011

Это немного приятнее на вид:

function Parent(obj) {
    if (!obj) {return;}
    this.id = obj.id || 0;
    this.name = obj.name || "";
}

Ваш стиль наследования больше соответствует "классическому" образцу.

Вы также можете сделать это:

Child.prototype = Parent.prototype;

... но любые последующие добавления к Child.prototype также окажутся в родительском прототипе (и наоборот).

Возможно, именно поэтому этот тип поведения часто переносится, чтобы возвращать объект напрямую, когда это необходимо, таким образом, что вы не можете так же легко перезаписать Parent (хотя вы можете это сделать через obj.constructor.prototype):

Object.create = function (o) {
    function F() {}
    F.prototype = o;
    return new F();
};
...