2010-07-31 2 views
8

Итак, моя первая попытка попытаться объяснить, что я делаю, провалилась с треском. Я в основном копирую Object.create(), но с частными переменными.Идея наследования Javascript (часть 2)

Если вы посмотрите на принятый здесь ответ How to inherit from a class in javascript?, вы увидите Object.create как последний шаблон, который, как мне кажется, лучше подходит для прототипа Javascript (объекты забудут объекты) вместо эмуляции классического наследования (классы забудут объекты) ,

Если вы посмотрите статью Википедии о программировании на основе прототипа (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 

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

this.public_method = this.parent.public_method; 

в случае с ребенком.

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

Преимущество этой модели:

  1. память не впустую для каждого нового экземпляра
  2. Он придерживается истинного прототипного шаблона наследования
  3. Вы имеете доступ к родительскому объекту, используя это. parent (этот .__ proto__ специфичен для браузера)
  4. Частные переменные в настоящее время существуют

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

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

+2

Вы должны выразить свою идею как сообщение в блоге. – Corv1nus

+0

Объекты, созданные с помощью функции «from()», переданной «null», действительно наследуются от Object. – Pointy

+0

К сожалению, моя первая версия этого сообщения использовала \ __ proto \ __ вместо этого и из (null) не наследовала от Object. Мне нужно идти, но я исправлю это позже ... – Nick

ответ

1

Во-первых, как уже упоминалось, подход 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 снова и снова. И да, вы сохраняете несколько байтов памяти по сравнению с подходом, основанным на классе, но, честно говоря, кто это волнует?

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

+0

Вы делаете хорошие моменты. Я могу согласиться с тем, что прототипное наследование является чем-то более полезным в теории, чем практикой (на самом деле мне никогда не нужно наследование в моих проектах, поэтому я просто использую шаблон модуля), но моя идея была в основном способом попробовать и прототипировать наследование более полезно. Вы получаете преимущества частных переменных экземпляра, а также возможности наследования без чрезмерного «взлома» языка (как и все библиотеки с псевдоклассами). – Nick

+0

Лично мне нравится идея создания «классов» из объектов. Ваша идея хороша в этом, с небольшими изменениями. Поместите 'constructor' внутри тела' F' и верните 'F'. Это несколько похоже на [ExtJS 'метод расширения] (http://www.sencha.com/deploy/dev/docs/?class=Ext&member=extend), который я считаю очень полезным. – user123444555621

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