2010-07-31 19 views
8

Bien, mi primer intento de intentar explicar lo que estaba haciendo falló miserablemente. Básicamente estoy copiando Crockford's Object.create(), excepto con variables privadas.Idea de herencia de Javascript (parte 2)

Si mira la respuesta aceptada aquí How to inherit from a class in javascript?, verá Object.create como el último patrón, que creo que se ajusta mejor a la naturaleza prototípica de Javascript (objetos engendrar objetos) en lugar de emular la herencia clásica (clases engendrar objetos) .

Si mira el artículo de Wikipedia sobre programación basada en prototipos (http://en.wikipedia.org/wiki/Prototype-based_programming), puede ver más de lo que quiero decir.

El inconveniente con Object.create() es que no hay soporte para miembros privados. Esto es lo que propongo:

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

A continuación, crear objetos como sigue:

// 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 

La forma en que hizo la "de la" función es tal que cuando un objeto padre cambia sus métodos, si desea evitar el cambio en una instancia secundaria, puede especificar:

this.public_method = this.parent.public_method; 

en la instancia hija.

Tenga en cuenta también que los objetos creados ex nihilo no heredan de Object (hasOwnProperty, etc.). Debe especificar esto explícitamente como .from (Object).

beneficios de este patrón:

  1. memoria no se pierde para cada nueva instancia
  2. Se adhiere a un patrón de herencia de prototipos cierto
  3. Usted tiene acceso al objeto principal de utilizar este. padre (este .__ proto__ es específico del navegador)
  4. Las variables privadas ahora existen

Hay un inconveniente importante de este método que puedo pensar: la sintaxis 'function()' puede confundir a las personas al pensar que se asigna una función a la variable en lugar de a un objeto.

Mi pregunta es, ¿hay otros inconvenientes que me falta? (No incluya inconvenientes del patrón prototípico, eso es subjetivo, sino solo de mi implementación).

+2

Debe poner su idea como una publicación de blog. – Corv1nus

+0

Los objetos creados con su función "from()" pasaron un 'null' de hecho heredan de Object. – Pointy

+0

Vaya ... mi primera versión de esta publicación usó \ __ proto \ __ en su lugar y desde (null) no heredó de Object. Tengo que irme ahora, pero lo arreglaré más tarde ... – Nick

Respuesta

1

En primer lugar, como ya se mencionó, el enfoque Function.prototype es realmente un problema. ¿Por qué no aplicar la misma cosa como esta:

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; 
}; 

A continuación, utilice

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

con los mismos resultados que el anterior. de experiencia: Se puede omitir el argumento constructor, así:

var c = Object.createChild(anything); 

En segundo lugar, no sé si hay alguna utilidad para la verdadera herencia de prototipos, como usted lo llama. En la vida real, estoy bastante seguro de que la función del constructor está especialmente diseñada para el objeto que se va a extender (a). Por lo tanto, vas a terminar llamando

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

con el mismo f - combinación a una y otra vez. Y sí, ahorras algunos bytes de memoria en comparación con un enfoque basado en la clase, pero, sinceramente, ¿a quién le importa?

Aún así, todo es una muy buena idea en teoría.

+0

Usted hace algunos buenos puntos. Puedo aceptar que la herencia prototípica es algo más útil en teoría que práctica (de hecho, nunca necesito herencia en mis proyectos, así que solo uso el patrón del módulo), pero mi idea era básicamente una forma de probar y crear prototipos herencia más útil. Obtiene los beneficios de las variables de instancia privadas, así como las capacidades de herencia sin demasiado "pirateo" del lenguaje (como todas las bibliotecas con pseudo-clases). – Nick

+0

Personalmente, me gusta la idea de crear "clases" a partir de objetos. Tu idea es buena para hacer eso, con ligeras modificaciones. Coloca 'constructor' dentro del cuerpo de' F', y devuelve 'F'. Esto es algo similar al [método extendido de ExtJS] (http://www.sencha.com/deploy/dev/docs/?class=Ext&member=extend), que me parece muy útil. – user123444555621