2010-02-18 18 views
12

soy bastante novato en javascript, y dedico algo de tiempo tratando de crear objetos de espacio de nombres en js.Clase anidada en javascript, herencia de métodos privados

Ahora, eso es lo que estoy tratando de hacer:

MainObject = function() { 

    var privateVariable = "i'm private"; 

    var privateMethod = function() { 
     // doSomething 
    } 

    this.publicMethod = function() { 
     // doPublicSomething 
    } 
} 

MainObject.prototype.nested = function() { 

    this.publicNestedMethod = function() { 

     // that's not working at all 
     this.privateMethod(privateVariable); 

    } 
} 

MyObject = new MainObject(); 

MyObject.publicMethod(); 
MyObject.publicNestedMethod(); 

Me trataron de incluir la clase anidada dentro de la primera, pero no está funcionando también si trato:

this.nested = function() { 

    var mainObject = this; 

    return { 
     publicNestedMethod = function() { 
      mainObject.privateMethod();    
     } 
    } 
}(); 

Alguien puede ayudarme por favor? voy a perder mi mente en esto.

Phaedra.

Respuesta

14

Los cierres son una característica léxica, no semántica. Si el objeto está fuera del alcance léxico de otro, ya no se puede "anidar" y acceder a las variables locales del primero. En el código de su función/clase anidada, no hay tal cosa como this.privateMethod, porque privateMethod es nunca hecho para ser una propiedad de MainObject. Es simplemente una variable local dentro de una función.

No hay elementos como "propiedades privadas", "métodos privados" o "miembros privados" en JavaScript. Diablos, no hay tal cosa como una "clase". A algunas personas les gusta emular a los miembros privados que usan variables locales como se indicó anteriormente, pero al hacerlo resultan en casos como este, donde la discrepancia entre los dos conceptos viene y los muerde uno detrás.

Para concluir, es una mala idea escribir código Java, con todas sus técnicas OO en JS, así como es una mala idea escribir código C, con todos sus punteros y búferes ilimitados, en C#. Claro, en ambos casos puedes hacerlo, pero no podrás apreciar y explotar las características del idioma de esta manera.

Y ahora que he terminado con la queja, se puede hacer algo como esto para conseguir "espacio de nombres" funciones:

MainObject = function() { 
    var privateVariable = "I'm private"; 

    var privateMethod = function() { 
     alert('Private'); 
    } 

    this.publicMethod = function() { 
     alert('Public'); 
    } 

    this.nested = { 
     publicNestedMethod: function() { 
     privateMethod(); 
     } 
    }; 

    // or 

    this.nested = (function() { 
     var nestedPrivate = 5; 

     return { 
     publicNestedMethod: function() { 
      alert(nestedPrivate); 
      privateMethod(); 
     } 
     }; 
    })(); 
} 

MyObject = new MainObject(); 

MyObject.publicMethod(); 
MyObject.nested.publicNestedMethod();​ 
+0

lo que si: this.nested = function() { var privateNested = function() {} retorno { } }(); – Phaedra

+0

Tendrá que agregar paréntesis alrededor de la función (declaración vs expresión, vea http://yura.thinkweb2.com/named-function-expressions/). Aparte de eso, es exactamente lo que es un cierre: estás encapsulando las variables locales utilizadas en el momento de creación de la función. Editó la respuesta para mostrar un ejemplo. –

+0

Así que eso es lo que estaba buscando, creo. ¿o no? Me faltaba la parethesis .. – Phaedra

0

¿Qué sistema OO le permite heredar métodos privados? Parte de ser privado no es accesible desde otros objetos.

En JS en particular, los "miembros privados" son realmente solo variables locales de la función donde se declaran. JS no tiene las nociones de OO típicas de "clase", "herencia", "público" y "privado", por lo que no puede esperar copiar las técnicas de OOP textualmente de otros lenguajes de OOP.

+0

En Java, si está creando un cass interno, puede acceder a los métodos privados de la clase principal, estoy bastante seguro de esto. Prototipando el objeto anidado, lo estoy agregando a la instancia del objeto principal. Así que esperaba que funcionara como un cierre que me da acceso a las variables del objeto principal. – Phaedra

+0

Recuerde que JavaScript es como Java solo por nombre. Son tan diferentes que no se puede esperar que nada en JS funcione de la misma manera que en Java. Como JS no tiene clases per se, tampoco tiene clases internas. – Gabe

6

utilizando la convención de guión para los métodos de "privado" es una forma razonable de mantener las cosas organizadas

MainObject = function() { 

     this._privateVariable = "i'm private"; 

     this._privateMethod = function() { 
      // doSomething 
     } 

     this.publicMethod = function() { 
      // doPublicSomething 
     } 
} 
0

Es una convención. Puede imitar técnicas de OO Java como miembros privados, pero eso no es recomendable. Puede imitar de esta manera:

MyFunction = function(options){ 
    var private = {}; 
    //to reference MyFunction as a context 
    var that = this; 

    function privateFunctionThatCallPublicMethod(){ 
     that.publicFunction("hello"); 
    } 

    this.publicFunction = function(params){ 
     alert(params + " " + private); 
    } 
    ... 
} 

var instance = new MyFunction({oneOption:'fsdfsad'}); 

Se trata de las mejores marcas de enfoque que encontré para emular las técnicas OO Java ...

Pero hay un problema, es muy ineficiente ... Debe utilizar prototipo en su lugar, porque de lo contrario crearía un objeto por función por instancia de la "clase".

MyFunction = function(options){ 
    this._private = {}; 
} 

MyFunction.prototype._privateFunctionThatCallPublicMethod = function(){ 
    this.publicFunction("hello"); 
} 

MyFunction.prototype.publicFunction = function(params){ 
    alert(params + " " + this._private); 
} 

Al igual que usted piensa miembros privados son (de esta manera) una convención. Además, hay otra cosa que usted debe saber ...

Cuando se pasa una función de un objeto como un parámetro a otra función debe vincular el contexto de la función ...

function bind(fnThis, fn) { 
    return function(){ 
    return fn.apply(fnThis, arguments); 
    }; 
} 

function makeSomething(callback){ 
    callback("hello"); 
} 

var instance = new MyFunction(); 
makeSomething(bind(instance, instance.publicFunction)); 

Esto se debe a que debe vincular "this" como instancia en el cuerpo de la función public, de lo contrario va a ser "ventana" en su lugar.

4

Bueno para proporcionar el beneficio de la herencia de prototipos, donde todas las "subclases" comparten una única instancia del método en el prototipo, sino también proporcionar la función de heredar casos particulares ... me ocurrió:

function Person(name,latentPower){ 
    var privatesForChildren = { password:"xyz" 
           ,latentPower:"invisibility"} 
    this.inherit = function(){ 
     for(v in privatesForChildren){ 
      eval("var " + v + "=privatesForChildren['" + v + "'];"); 
     } 
    } 
    this.name = name; 
    this.revealName = function(){ alert("My name is" + this.name + "."); } 
    this.revealPowers = function(){ alert("I'm normal."); } 
}  
function Mutant(name,latentPower,fuel){ 
    this.inherit.call(this); // Inherit private instance variables 
    var fuel = fuel; 
    this.name = name; 
    this.revealPowers = function(){ 
    alert("I manifest the powers of " + latentPower + " when I " + fuel + "."); 
    } 
} 
Mutant.prototype = new Person; 
Mutant.prototype.constructor = Mutant; 

bob = new Person("Bob","telekenesis"); 
jim = new Mutant("Jim","nausea","eat pizza"); 
buford = new Mutant("Buford","Teflon Man","breathe"); 

jim.revealName(); //Inherited properly from prototype 
bob.revealPowers(); 
jim.revealPowers(); 
buford.revealPowers(); //distinct from Jim's so is an "instance var" 
alert(bob.latentPower); //returns undefined 
alert(buford.latentPower); //returns undefined, so is "private". 

¿Qué tan útil es eso?

Cuestiones relacionadas