Переполнение стека в наследовании JavaScript - PullRequest
1 голос
/ 09 августа 2009

у меня ниже прога

Object.prototype.inherit = function(baseConstructor) {
  this.prototype = (baseConstructor.prototype);
  this.prototype.constructor = this;
};
Object.prototype.method = function(name, func) {
  this.prototype[name] = func;
};

function StrangeArray(){}
StrangeArray.inherit(Array);
StrangeArray.method("push", function(value) {
  Array.prototype.push.call(this, value);
});

var strange = new StrangeArray();
strange.push(4);
alert(strange);

и когда это происходит, я получаю переполнение стека? почему?

Ответы [ 3 ]

6 голосов
/ 09 августа 2009

Вы устанавливаете StrangeArray.prototype на Array.prototype. Позже вы добавляете метод push к StrangeArray.prototype (который теперь совпадает с Array.prototype). Таким образом, вы эффективно устанавливаете Array.prototype.push. Ваш push метод вызывает Array.prototype.push - т.е. сам. Так что в итоге он просто вызывает себя несколько раз, и вы получаете переполнение стека.

2 голосов
/ 09 августа 2009

Джон прав. Вот способ это исправить. Вместо того, чтобы устанавливать StrangeArray.prototype в Array.prototype, это позволит вам установить StrangeArray.prototype в новый экземпляр Array, чтобы он наследовал свойства Array.prototype (без вызова конструктора Array).

Object.prototype.inherit = function(baseConstructor) {
  var tmp = Function();
  tmp.prototype = baseConstructor.prototype;
  this.prototype = new tmp();
  this.prototype.constructor = this;
};

Edit:

this.prototype = new baseConstructor();

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

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

Я не очень хорош в объяснении этого материала. Я рекомендую сайт Крокфорда, а также эти две статьи о наследовании Javascript .

1 голос
/ 09 августа 2009

На самом деле вам нужно только установить фактический прототип объекта в новый экземпляр baseConstructor:

Object.prototype.inherit = function(baseConstructor) {
  this.prototype = new baseConstructor();
};

Я также предлагаю вам взглянуть на эту Prototypal Inheritance технику, которую я нашел очень чистой.

...