Цепочка прототипов в Javascript не обновляется

Я пытаюсь понять прототипное наследование в Javascript, но не могу применить его к следующему случаю. Любая помощь будет оценена по достоинству.

Я определяю конструктор следующим образом:

var base = function() {
    var priv = "private"; // Private
    var publ = "public";  // Public through a getter/setter (below)

    // The object to return
    var f = {};

    f.publ = function (new_val) {
        if (!arguments.length) {
          return publ;
        }
        publ = new_val;
        return f;
    };

    return f;
};

С помощью этого конструктора я могу создавать объекты, вызывая base();. Эти объекты имеют публичный метод (publ).

Теперь, следуя той же структуре, я хотел бы иметь новый конструктор, который создает объекты, наследуемые от объектов, созданных «базовым конструктором», определенным выше:

var myclass = function () {

  // Other parameters defined here

  var f = function () {
      // publ is inherited
      console.log(f.publ());
  };

  // Trying to set the prototype of f to the object created by "base()"
  f.prototype = base();

  // Other methods defined here

  return f;
};

С помощью f.prototype = base(); я хочу, чтобы f наследовал все методы, определенные в объекте, возвращаемом base(), но попытка вызвать f.publ жалуется, потому что f не имеет метода publ

Любая помощь в понимании того, что происходит, будет приветствоваться

M;


person emepyc    schedule 09.02.2014    source источник
comment
Для прототипного наследования в javascript требуется оператор new или Object.create. Вы не используете здесь ни того, ни другого.   -  person Eric    schedule 09.02.2014
comment
Это не похоже на конструктор. Вы бы использовали конструктор с new. Это больше похоже на шаблон модуля.   -  person elclanrs    schedule 09.02.2014
comment
Как отмечалось в нескольких комментариях, используйте Object.create для настройки части наследования прототипа и выполните Parent.call(this,args) в Child (это позаботится о наследовании элементов instace от Parent). Подробнее здесь stackoverflow.com/a/16063711/1641941   -  person HMR    schedule 09.02.2014


Ответы (1)


Наиболее распространенный способ прототипного наследования выглядит следующим образом:

function Base() {
    var priv = "private";
    this.publ = "public";
}

Теперь вы можете создавать экземпляры Base с помощью new Base. Далее мы создаем MyClass:

MyClass.prototype = new Base;

function MyClass() {
    alert(this.publ);
}

Наконец, вы можете создать экземпляр MyClass с помощью new MyClass следующим образом:

var a = new MyClass; // alerts "public"

Посмотрите демонстрацию сами: http://jsfiddle.net/b3QyE/


Наследование прототипов в JavaScript может немного сбивать с толку, поскольку оно ориентировано на конструктор, а не на прототип, поэтому я предпочитаю использовать следующую служебную функцию для создания "классов":

function defclass(base, body) {
    var uber = base.prototype;
    var prototype = Object.create(uber);
    var constructor = (body.call(prototype, uber), prototype.constructor);
    constructor.prototype = prototype;
    return constructor;
}

Используя defclass, теперь вы можете реструктурировать свой код следующим образом:

var Base = defclass(Object, function () {
    this.constructor = function () {
        var priv = "private";
        this.publ = "public";
    };
});

var MyClass = defclass(Base, function (uber) {
    this.constructor = function () {
        uber.constructor.call(this);
        alert(this.publ);
    };
});

Это намного читабельнее и понятнее. Все инкапсулировано в рамках одной функции, и ничто не висит на месте. Кроме того, вам не нужно понимать наследование прототипов, чтобы использовать его. См. обновленную демонстрацию: http://jsfiddle.net/b3QyE/2/.

Если вы заметили, что мы вызываем функцию конструктора класса Base из конструктора MyClass. Это позволяет вам инициализировать экземпляр с помощью конструктора класса Base. Вы можете вызвать любой метод класса Base через uber.


Чтобы узнать больше о прототипном наследовании, взгляните на следующие ответы:

  1. Наследование JavaScript и свойство конструктора
  2. Как добиться права псевдоклассического наследования в объявлении класса?
  3. Преимущества прототипного наследования по сравнению с классическим?
person Aadit M Shah    schedule 09.02.2014
comment
Примечание: лучший способ установить наследование — использовать Object.create(Parent.prototype), а не new Parent. stackoverflow.com/a/17393153/218196 edit: А вот что вы делаете в своем defclass функция :D - person Felix Kling; 09.02.2014
comment
Вы цитируете Крокфорда, человека, который до сих пор не смог написать статью или презентацию, в которой правильно используется то, что он сам называет псевдоклассическим наследованием. прототип, чтобы они могли сами решить, как его использовать или не использовать. - person HMR; 09.02.2014
comment
@HMR Может быть, кому-то, кто плохо знаком с JavaScript, больше пошло бы на пользу изучение Haskell. Серьезно, изучение Haskell делает вас лучшим программистом на JavaScript. - person Aadit M Shah; 09.02.2014