Идея наследования Javascript (часть 2) - PullRequest
8 голосов
/ 31 июля 2010

Хорошо, моя первая попытка объяснить, что я делал, с треском провалилась. Я в основном копирую Object.create () Крокфорда, за исключением частных переменных.

Если вы посмотрите на принятый ответ здесь Как наследовать от класса в javascript? , вы увидите Object.create как последний шаблон, который, я думаю, лучше соответствует прототипной природе Javascript (объекты объекты beget) вместо эмуляции классического наследования (классы объектов beget).

Если вы посмотрите статью Википедии о программировании на основе прототипов (http://en.wikipedia.org/wiki/Prototype-based_programming),, вы увидите больше того, что я имею в виду.

Недостаток Object.create () заключается в том, что нет поддержки для закрытых членов. Вот что я предлагаю:

Function.prototype.from = function(obj) {
    function F() {this.parent = Object(obj);}
    F.prototype = obj;
    var out = new F();
    this.apply(out);
    return out;
};

Затем вы создаете объекты следующим образом:

// Create an object
var a = function() {
    var private_property = 'blue';
    this.public_property = 7;

    this.public_method = function() {
        alert(this.public_property + ' ' + private_property);
    }
}.from(null); // .from() works too, but .from(null) is more revealing


// Create a new object using 'a' as the prototype
var b = function() {
    var private_property = 'red';
    this.public_property = 8;
}.from(a);


// See the results
a.public_method(); // Alerts '7 blue'
b.public_method(); // Alerts '8 blue' - Parent methods use parent private variables

a.public_method = function() { alert('rabbit'); };

a.public_method(); // Alerts 'rabbit'
b.public_method(); // Alerts 'rabbit'

b.public_method = function() { alert('dog'); };

a.public_method(); // Alerts 'rabbit'
b.public_method(); // Alerts 'dog' - Parent method is overwritten

Способ, которым я сделал функцию "from", заключается в том, что когда родительский объект меняет свои методы, если вы хотите предотвратить изменение в дочернем экземпляре, вы можете указать:

this.public_method = this.parent.public_method;

в дочернем экземпляре.

Обратите внимание, что объекты, созданные ex nihilo, не наследуются от Object (hasOwnProperty и т. Д.). Вы должны явно указать это как .from (Object).

Преимущества этого шаблона:

  1. Память не тратится впустую для каждого нового экземпляра
  2. Придерживается истинного шаблона наследования прототипа
  3. У вас есть доступ к родительскому объекту с помощью this.parent (this .__ proto__ зависит от браузера)
  4. Закрытые переменные теперь существуют

Есть один существенный недостаток этого метода, о котором я могу подумать: синтаксис 'function ()' может ввести людей в заблуждение, полагая, что функция назначается переменной вместо объекта.

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

1 Ответ

1 голос
/ 31 июля 2010

Во-первых, как уже упоминалось, подход Function.prototype - это действительно боль.Почему бы не реализовать то же самое, как это:

Object.createChild = function(obj, constructor) {
    function F() { this.parent = Object(obj); }
    F.prototype = obj;
    var out = new F();
    if (typeof constructor == 'function') {
        constructor.apply(out);
    }
    return out;
};

Затем используйте

var a = Object.createChild(null, function () { /*...*/ });
var b = Object.createChild(a, function () { /*...*/ });

с теми же результатами, что и выше.Бонус: Вы можете опустить аргумент constructor, например:

var c = Object.createChild(anything);

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

var x = f.from(a);
var y = f.from(a);

с одной и той же комбинацией f - a снова и снова.И да, вы экономите несколько байтов памяти по сравнению с классовым подходом, но, если честно, кого это волнует?

Тем не менее, все это действительно хорошая идея в теории.

...