2013-05-19 4 views
5

Я пытался справиться с OO JavaScript и создал простой пример.OO JavaScript call parent method

function BasePage(name) { 
    this.init(name); 
} 

BasePage.prototype = { 
    init: function(name) { 
     this.name = name; 
    }, 
    getName: function() { 
     return this.name; 
    } 
} 

function FaqPage (name, faq) { 
    this.init(name, faq); 
} 

FaqPage.prototype = new BasePage(); 

FaqPage.prototype = { 
    init: function(name, faq) { 
     BasePage.prototype.init.call(this, name); 
     this.faq = faq; 
    }, 
    getFaq: function() { 
     return this.faq; 
    } 
} 

var faqPage = new FaqPage('Faq Page', 'Faq'); 

var text = faqPage.getName() + ' ' + faqPage.getFaq(); 
$('body').text(text); 

Результат выполнения этого приводит следующее сообщение:

Uncaught TypeError: Object #<Object> has no method 'getName'

То, что я хотел бы знать, как я могу вызвать метод getName() в супер класс без переопределения и назвать его в подклассе?

Также, если мой, если вы считаете, что этот подход плох/хорош.

ответ

1

Я чувствую вашу боль. Как отмечали другие getName, это undefined, потому что вы переопределяете prototype от FaqPage. Поэтому я не буду повторять это объяснение.

Это, как говорится, я согласен с тем, что полезно инкапсулировать методы prototype в одном объеме. Возможно, для этой цели вы должны использовать библиотеку JavaScript. Самый маленький из них - augment.На самом деле это только 17 линий длиной:

Function.prototype.augment = function (body) { 
    var base = this.prototype; 
    var prototype = Object.create(base); 
    body.apply(prototype, Array.from(arguments, 1).concat(base)); 
    if (!Object.ownPropertyOf(prototype, "constructor")) return prototype; 
    var constructor = prototype.constructor; 
    constructor.prototype = prototype; 
    return constructor; 
}; 

(function funct() { 
    var bind = funct.bind; 
    var bindable = Function.bindable = bind.bind(bind); 
    var callable = Function.callable = bindable(funct.call); 
    Object.ownPropertyOf = callable(funct.hasOwnProperty); 
    Array.from = callable([].slice); 
}()); 

Вот как ваш код будет выглядеть, если вы использовали augment:

var BasePage = Object.augment(function() { 
    this.constructor = function (name) { 
     this.name = name; 
    }; 

    this.getName = function() { 
     return this.name; 
    }; 
}); 

var FaqPage = BasePage.augment(function (base) { 
    this.constructor = function (name, faq) { 
     base.constructor.call(this, name); 
     this.faq = faq; 
    }; 

    this.getFaq = function() { 
     return this.faq; 
    }; 
}); 

Затем вы можете использовать его как обычно:

var faqPage = new FaqPage("Faq Page", "Faq"); 
var text = faqPage.getName() + " " + faqPage.getFaq(); 
$("body").text(text); 

Надеюсь, это поможет.

+0

С уважением, Aadit, я вижу, что Augment хорошо работает в тесте, который вы делали, но что произошло в Chrome? График показал нулевые операции? – Stokedout

+0

@ Stokedout - контрольные точки должны быть взяты с солью. Без сомнения, «увеличение» происходит быстро. Однако большинство программистов JavaScript - любители, которые пишут неаккуратный код. Чтобы компенсировать это, большинство движков JavaScript, таких как V8, сильно оптимизируют его. В результате даже плохой код работает невероятно быстро (иногда даже быстрее, чем хороший код, потому что плохие шаблоны дизайна хорошо оптимизированы). Однако это не повод для написания плохого кода. Хороший код не только быстрый, но и читаемый, выразительный, и легко понять и поддерживать; и «аугмент» поражает все эти моменты. Это действительно быстро в Chrome 26. Замедление в 27. –

+0

Прохладный спасибо, мои причины для перехода на OO JS - это то, о чем вы только что упоминали. Я не могу идти в ногу с релизами Chrome и не могу дождаться, когда вы запустите выпуски IE ;-). Один заключительный комментарий о вышеуказанном коде. Если я использую конструктор, то, конечно, init - это дублирование одной и той же вещи? – Stokedout

6

Эта ошибка возникает из-за того, что вы установили прототип FaqPage в качестве экземпляра BasePage, ваша следующая строка сразу же перезаписывает это. Таким образом, FaqPage не наследует от BasePage. Добавить свойства/методы FaqPage «s прототипа вместо определения его во второй раз:

FaqPage.prototype.init = function(name, faq) { 
    BasePage.prototype.init.call(this, name); 
    this.faq = faq; 
} 
FaqPage.prototype.getFaq = function() { 
    return this.faq; 
} 
+0

Спасибо, у меня было чувство, что это будет причиной. Это единственный способ/рекомендуемый способ добавления методов в OO JS? Для меня, исходящего из C#, кажется уродливым неспособность группировать методы класса в одном {scope} – Stokedout

+0

Я знаю, что вы имеете в виду, но да, это рекомендуемый способ. Он может расти на вас. Имейте в виду, что вы также можете размещать методы на «BasePage». – sh0ber

2

Первая строка является правильной, вы создаете прототип от базового объекта.

FaqPage.prototype = new BasePage(); 

Но затем переопределить его, так что есть не наследует базовый объект больше

FaqPage.prototype = { 
    init: function(name, faq) { 
     BasePage.prototype.init.call(this, name); 
     this.faq = faq; 
    }, 
    getFaq: function() { 
     return this.faq; 
    } 
} 

Вместо определения весь прототип, переопределить только отдельные функции:

FaqPage.prototype.init = function(name, faq) { 
    BasePage.prototype.init.call(this, name); 
    this.faq = faq; 
}; 

FaqPage.prototype.getFaq = function() { 
    return this.faq; 
}; 
1

Если наследование это то, что вам нужно, это не очень просто сделать на JavaScript, насколько я знаю. Я использовал этот фрагмент Джона Ресига, и он работает как шарм. http://ejohn.org/blog/simple-javascript-inheritance/

В вашем случае это, как он будет работать,

BasePage

var BasePage = Class.extend({ 
    init: function(name){ 
    this.name = name; 
    }, 
getName: function(){ 
    return this.name; 
} 
}); 

FaqPage класс наследующий BasePage

var FaqPage = BasePage.extend({ 
    init: function(name, faq){ 
    this._super(name); 
    this.faq = faq; 
    }, 
    getFaq: function() { 
    return this.faq; 
    } 
}); 

А потом

var faqPage = new FaqPage('Faq Page', 'Faq'); 
var text = faqPage.getName() + ' ' + faqPage.getFaq(); 
$('body').text(text); 

Конечно, для этого вам нужно будет включить код реализации на связанную мной страницу.

Вот скрипка, http://jsfiddle.net/c8yjY/

+0

Код Джона Ресига немного устарел. Там есть много лучших библиотек ООП: http://jsperf.com/oop-benchmark/127 Пожалуйста, прочитайте мой ответ выше. –