2010-05-07 12 views
107

Digamos que tengo el siguiente javascript:¿Cómo puede un objeto Javascript referirse a valores en sí mismo?

var obj = { 
key1 : "it ", 
key2 : key1 + " works!" 
}; 
alert(obj.key2); 

Este errores con "key1 no está definido". He intentado

this.key1 
this[key1] 
obj.key1 
obj[key1] 
this["key1"] 
obj["key1"] 

y parece que nunca están definidos.

¿Cómo puedo hacer que key2 haga referencia al valor de key1?

+0

muy antigua de Firefox (He intentado Firefox 4 y le da una advertencia pero acepta it) le permiten usar # N = y # N # para referirse a objetos existentes en la misma expresión, pero esto no funciona para las primitivas; solo tienes que duplicarlos. – Neil

+1

En realidad, hay una solución cursi, puede colocar el primitivo en la caja y luego referirse al valor en caja con la variable aguda: 'var obj = {key1: # 1 = (new String (" it ")), key2: # 1 # + "funciona" }; alerta (obj.key2) ' – Neil

+0

key2 se define dentro del objeto mientras se está definiendo el objeto. Por lo tanto, aún no hay una clave1 cuando se está definiendo key2. Solo después de la asignación existe la clave1. Estás haciendo referencia a algo que aún no existe. –

Respuesta

122

Quizás pueda pensar en eliminar el atributo de una función. Me refiero a algo como esto:

var obj = { 
key1 : "it ", 
key2 : function() {return this.key1 + " works!";} 
}; 

alert(obj.key2()); 
+4

funciona solo si tiene un 'obj' plano, como el de su ejemplo. No funcionará si tiene claves anidadas. – Green

+1

@Green Verdadero, pero siempre se puede asignar a una función vinculada inmediatamente después de la creación del objeto. 'var obj = {...}; obj.nested.func = function() {...} .bind (obj); ' – Thor84no

+4

En ES6 puede reemplazar' key2: function() {...} 'con' get key2() {...} 'y luego no necesita usar corchetes al llamarlo:' alert (obj.key2); ' – JoeRocc

5

Esto no es JSON. JSON fue diseñado para ser simple; Permitir expresiones arbitrarias no es simple.

En JavaScript completo, no creo que puedas hacer esto directamente. No puede consultar this hasta que el objeto llamado obj esté completamente construido. Entonces necesitas una solución, esa persona con más JavaScript-fu de lo que yo proporcionaré.

34

No puede hacer referencia a una propiedad de un objeto antes de haber inicializado ese objeto; usa una variable externa.

var key1 = "it"; 
var obj = { 
    key1 : key1, 
    key2 : key1 + " works!" 
}; 

Además, esto no es un "objeto JSON"; es un objeto Javascript JSON es un método para representar un objeto con una cadena (que resulta ser un código de JavaScript válido).

14

Eso no es un objeto JSON, que es un objeto Javascript creado a través de la notación literal del objeto. (JSON es una notación textual para el intercambio de datos (more). Si usted está tratando con código JavaScript de origen, y no se trata de una cadena , usted no está tratando con JSON.)

No hay manera en el Inicializador de objetos para referirse a otra tecla del objeto que se está inicializando, porque no hay forma de obtener una referencia al objeto que se está creando hasta que finalice el inicializador. (No existe una palabra clave similar a this o algo así)

19

Debido a que la sentencia que define obj no ha terminado, key1 no existe todavía. Considere esta solución:

var obj = { key1: "it" }; 
obj.key2 = obj.key1 + ' ' + 'works!'; 
// obj.key2 is now 'it works!' 
+0

buena solución, tiene sentido que el objeto no haya terminado su fase de ejecución, por lo que llamar a una clave dentro de él sería indefinido. Los objetos son funciones, por lo que las claves dentro no se definen en la memoria hasta que la fase de ejecución haya finalizado. – Pixelomo

38

Esto se puede lograr mediante el uso de la función constructora en lugar de literal

var o = new function() { 
    this.foo = "it"; 
    this.bar = this.foo + " works" 
} 

alert(o.bar) 
7

También puede hacer referencia a la obj una vez que están dentro de la función en lugar de this.

var obj = { 
    key1: "it", 
    key2: function(){return obj.key1 + " works!"} 
}; 
alert(obj.key2()); 
+0

Creo que esta respuesta es superior a la "mejor respuesta". obj.key1 siempre es 'it', mientras que this.key1 puede tener otro valor dependiendo de dónde se invoque la función obj.key2. p.ej. setTimeout (obj.key2, 100); esto se refiere al objeto ventana. –

15

Una alternativa sería utilizar un método getter/setter.

Por ejemplo, si sólo se preocupan por la lectura del valor calculado:

var book = {} 

Object.defineProperties(book,{ 
    key1: { value: "it", enumerable: true }, 
    key2: { 
     enumerable: true, 
     get: function(){ 
      return this.key1 + " works!"; 
     } 
    } 
}); 

console.log(book.key2); //prints "it works!" 

El código anterior, sin embargo, no se le permitirá definir otro valor para clave2.

Por lo tanto, las cosas se vuelven un poco más complicadas si también desea redefinir el valor de key2. Siempre será un valor calculado. Lo más probable es que eso es lo que quieres.

Sin embargo, si desea poder redefinir el valor de key2, necesitará un lugar para almacenar en caché su valor independientemente del cálculo.

Algo como esto:

var book = { _key2: " works!" } 

Object.defineProperties(book,{ 
    key1: { value: "it", enumerable: true}, 
    _key2: { enumerable: false}, 
    key2: { 
     enumerable: true, 
     get: function(){ 
      return this.key1 + this._key2; 
     }, 
     set: function(newValue){ 
      this._key2 = newValue; 
     } 
    } 
}); 

console.log(book.key2); //it works! 

book.key2 = " doesn't work!"; 
console.log(book.key2); //it doesn't work! 

for(var key in book){ 
    //prints both key1 and key2, but not _key2 
    console.log(key + ":" + book[key]); 
} 

Otra alternativa interesante es el uso de un objeto de auto-inicialización:

versiones
var obj = ({ 
    x: "it", 
    init: function(){ 
    this.y = this.x + " works!"; 
    return this; 
    } 
}).init(); 

console.log(obj.y); //it works! 
+0

Me gusta el objeto de inicialización automática. Gracias – suther

Cuestiones relacionadas