2015-02-04 2 views
3

Я новичок в объектно-ориентированном программировании с помощью javascript. И пытаюсь реализовать основы, которые мы знаем из других языков программирования.JavaScript-вызов родительской функции из дочернего объекта

У меня есть два класса, один родитель и один ребенок. У родителя есть некоторые частные функции и некоторые публичные функции. Ребенок наследует родительский класс.

И я хочу получить доступ к родительской публичной функции из дочернего объекта. То, что я пытаюсь сделать:

function SuperClass { 
    //Constructor implementation of this class 

    //public functions 
    return { 
     parentPublicFunction: function() { 
      //Public function implementation 
     } 
    } 
    function privateFunction() { 
     //Private function implementation. 
    } 
} 

//Inheriting 
childClass.prototype = Object.create(SuperClass.prototype); 
childClass.prototype.constructor = childClass; 
childClass.prototype.parent = SuperClass.prototype; 
function childClass { 
    //Call to super constructor 
    this.parent.constructor.call(this, arguments); 

    //Public function for childClass. 
    return { 
     childPublicFunction: function() { 
      //function implementation 
     } 
    } 
} 

var childObj = new childClass(); 
childObj.parentPublicFunction(); 

Я получаю эту ошибку при запуске этого:

Uncaught TypeError: undefined is not a function

Могу ли я делать то, что является неправильным.? Заранее спасибо!

+1

Переместить parentPublicFunction в прототип. – lujcon

+1

@lujcon: Это само по себе не решит проблему. –

ответ

5

Поскольку вы возвращаете свои собственные объекты из функций конструктора, вам нужно сделать немного больше сантехники.

//Call to super constructor 
this.parent.constructor.call(this, arguments); 

возвращает публичный API из SuperClass, но вы ничего с результатом не делает. Вы должны были бы объединить его в общественное API ребенка:

//Call to super constructor 
var parentAPI = this.parent.constructor.call(this, arguments); 

//Public function for childClass. 
return Object.assign(parentAPI, { 
    childPublicFunction: function() { 
     //function implementation 
    } 
}); 

Присвоение childClass.prototype на самом деле не имеет значения в вашем случае, так как объект вы возвращаетесь из конструкторов не наследует от него в любом случае. То есть childObj не будет обладать свойствами, которые вы назначили прототипу (например, parent). Есть еще больше вещей, которые вы упускаете, возвращая свой собственный объект, например, возможность использовать instanceOf (childObj instanceOf childClass будет false).

Чтобы сделать все это, вам необходимо назначить методы this внутри конструктора (вместо возврата объекта). Дополнительную информацию об этом стиле ООП можно найти в MDN documentation.


Примечание: Это условность, чтобы начать имена функций конструктора с заглавной буквы, т.е. ChildClass.

+0

Теперь что делает 'Object.assign'? Почему мы передаем пустой объект, 'parentAPI' и другие функции? –

+0

[MDN - 'Object.assign'] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) ... также имеет полипол для браузеров, которые не Пока не поддерживаю его. Он делает то, что я описал в тексте, он «объединяет» два объекта. Конечно, вы можете использовать любую другую функцию, которая делает что-то эквивалентное. Собственно, передача пустого объекта не требуется, будет обновляться. –

+0

«' childObj' не будет обладать никакими свойствами, которые вы назначили прототипу (например, родительский) ». Как это реализовать? –

7

JavaScript OOP не работает как Java или C#, не ожидайте этого, и не пытайтесь это сделать. Единственное, что может возникнуть в результате этого, - это недоразумения. Вместо того, чтобы пытаться заставить ваши старые парадигмы на языке, который создан совершенно по-другому, скорее узнайте, как работает OOP JavaScript.

JavaScript является объектно-ориентированным, но это не значит, что он имеет классы. По крайней мере, не так, как большинство разработчиков, пришедших с Java или подобных языков, думают о классах. У него также нет классического наследования. Тем не менее, все они могут быть «фальшивыми» или имитируемыми (именно это вы и пытаетесь сделать). Проблема с этим заключается в том, что разработчики, выходящие из Java или похожих, видят код, который выглядит как классы и классическое наследование, поэтому они считают, что это классы с классическим наследованием, и ожидают, что он будет вести себя как таковой, тогда как он может полностью работать другой.

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

Во-вторых, JavaScript использует прототипы для обработки наследования между объектами (а не классами), и если вы хотите сделать прототипное наследование (какое из них предлагает ваш код), вы не можете вернуть новый анонимный объект из функция SuperClass. Позвольте мне немного проиллюстрировать, что здесь происходит.

Когда вы называете SuperClass функции (либо из функции childClass, или из любого другого места), используя new ключевое слово, как в var inst = new SuperClass();, то, что эффективно происходит это следующим образом:

  1. JavaScript создает новый пустой объект, прототип которого равен prototype -property о функции, которую вы вызываете. В коде это будет var temp = Object.create(SuperClass.prototype);.
  2. JavaScript вызывает вашу функцию с этим объектом как объект this. В коде это будет SuperClass.call(temp, <arguments>).
  3. Если функция возвращает что-либо, значение inst установлено в это значение, иначе оно установлено в значение temp.

Теперь в вашей SuperClass функции вы выполните следующие действия:

//Constructor implementation of this class 

//public functions 
return { 
    parentPublicFunction: function() { 
     //Public function implementation 
    } 
} 
function privateFunction() { 
    //Private function implementation. 
} 

Что здесь происходит, что ваш метод SuperClass получить диалоги вызываются с this, который является экземпляром SuperClass, то есть. он имеет SuperClass.prototype в своей прототипной цепочке. Это означало бы, что если вы, например, сделали this instanceof SuperClass, вы бы получили true, как и следовало ожидать. Затем вы идете и возвращаете новый анонимный объект, у которого есть свойство с именем parentPublicFunction (которое просто является функцией, но может быть чем угодно). Этот новый объект, который вы возвращаете, не является экземпляром SuperClass. Он не имеет SuperClass.prototype в его собственности. Вы создали ситуацию, когда я делаю (new SuperClass()) instanceof SuperClass, вы получаете false. Другими словами, экземпляр, который вы возвращаете из функции конструктора SuperClass, не реализует ваш «класс». Это, вероятно, совсем не то, что вы намеревались, что является одной из причин, по которым вы не можете просто переложить классические принципы наследования на JavaScript и ожидать, что все будет работать одинаково.

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

Прежде всего, я буду называть его ChildClass вместо childClass. Любая функция в JavaScript, которую вы ожидаете, вызовет людей с помощью new, должна начинаться с верхнего регистра. Любую функцию, которую вы не ожидаете вызывать с new, следует начинать с нижнего регистра. В JavaScript нет способа узнать, должна ли функция быть вызвана с или без new, поэтому это используется для обозначения.

Теперь ChildClass.prototype устанавливается как экземпляр SuperClass, а это означает, что любые методы в прототипе SuperClass «s будет вызывать из экземпляра ChildClass. И любой экземпляр ChildClass также является экземпляром SuperClass (как и следовало ожидать).Однако, как уже объяснялось, прототип SuperClass пуст, поэтому его не наследует. Таким образом, единственное, что дает ChildClass, состоит в том, что a instanceof ChildClass подразумевает, что a instanceof SuperClass. Однако, как и в случае с SuperClass, вы возвращаете анонимный объект от ChildClass, что также приводит к тому, что (new ChildClass()) instanceof ChildClass является ложным.

И в этом, ложь (большинство) ваших проблем. Решение состоит в том, чтобы узнать, как работает ООП в JavaScript и обнимает это при выполнении JavaScript, вместо того, чтобы пытаться склонить его к тому, как вы предполагаете, что нужно работать.

Смежные вопросы