¿Hay alguna manera de hacer que algo como lo siguiente funcione en JavaScript?
var foo = {
a: 5,
b: 6,
c: this.a + this.b // Doesn't work
};
En la forma actual, este código obviamente arroja un error de referencia, ya this
que no hace referencia foo
. Pero, ¿ hay alguna forma de tener valores en las propiedades de un objeto literal que dependen de otras propiedades declaradas anteriormente?
javascript
object-literal
kpozin
fuente
fuente
foo.a
ofoo.b
se cambian, el valor defoo.c
también cambiará en sincronismo. Esto puede o no ser lo que se requiere.this
une al objeto anidado más profundo. Por ejemplo:... x: { get c () { /*this is x, not foo*/ } } ...
foo
se declara como una variable yc
solo se evaluará en el momento en que se invoca, el usofoo
internoc
funcionará, en lugar dethis
(tenga cuidado)Podrías hacer algo como:
Esto sería una especie de inicialización única del objeto.
Tenga en cuenta que en realidad está asignando el valor de retorno de
init()
afoo
, por lo tanto, debe hacerloreturn this
.fuente
delete this.init
antesreturn this
para quefoo
no se contamineinit()
llamada se agregó directamente al literal para mantener una sola expresión. Pero, por supuesto, puede llamar a la función por separado de lo que desea.Falta la respuesta simple y obvia, así que para completar:
No. Todas las soluciones aquí difieren hasta que se crea el objeto (de varias maneras) y luego asignan la tercera propiedad. La forma más simple es simplemente hacer esto:
Todos los demás son formas más indirectas de hacer lo mismo. (Felix's es particularmente inteligente, pero requiere crear y destruir una función temporal, agregar complejidad; y deja una propiedad adicional en el objeto o [si tiene
delete
esa propiedad] afecta el rendimiento de los accesos de propiedad posteriores en ese objeto).Si necesita que todo esté dentro de una expresión, puede hacerlo sin la propiedad temporal:
O, por supuesto, si necesita hacer esto más de una vez:
entonces donde necesitas usarlo:
fuente
this
solo está disponible para los métodos de dicho objeto, y no hay otro tipo de propiedades. ¿Alguna idea de dónde podría encontrar eso? ¡Gracias!delete
es un 10% más rápido y gecko:delete
es solo un 1% más lento.Simplemente instancia una función anónima:
fuente
new Point(x, y)
excepto que la función no tiene nombre para su reutilización.var foo = function() { this.…; return this; }.call({});
que es sintácticamente no muy diferente pero semánticamente sano.new
palabra clave.Ahora en ES6 puede crear propiedades en caché perezosas. En el primer uso, la propiedad se evalúa una vez para convertirse en una propiedad estática normal. Resultado: la segunda vez que se omite la sobrecarga de la función matemática.
La magia está en el captador.
En la flecha, el captador
this
recoge el alcance léxico circundante .fuente
Object.defineProperty(foo, 'c', {get:function() {...}})
para definirlas. Esto se hace fácilmente de una manera discreta en una fábrica como esta. Por supuesto, si puede usar elget
azúcar, es más legible, pero la capacidad ha estado allí.Algún cierre debería ocuparse de esto;
Todas las variables declaradas
foo
son privadasfoo
, como cabría esperar con cualquier declaración de función y, dado que están todas dentro del alcance, todas tienen acceso entre sí sin necesidad de hacer referenciathis
, tal como cabría esperar con una función. La diferencia es que esta función devuelve un objeto que expone las variables privadas y asigna ese objetofoo
. Al final, devuelve solo la interfaz que desea exponer como un objeto con lareturn {}
instrucción.La función se ejecuta al final con lo
()
que hace que se evalúe todo el objeto foo, todas las variables dentro de las instancias y el objeto de retorno agregado como propiedades defoo()
.fuente
Podrías hacerlo así
Ese método me ha resultado útil cuando tuve que referirme al objeto en el que se declaró originalmente una función. El siguiente es un ejemplo mínimo de cómo lo usé:
Al definir self como el objeto que contiene la función de impresión, permite que la función haga referencia a ese objeto. Esto significa que no tendrá que 'vincular' la función de impresión a un objeto si necesita pasarla a otro lugar.
Si, en cambio, lo usa
this
como se ilustra a continuaciónLuego, el siguiente código registrará 0, 1, 2 y luego dará un error
Al utilizar el método self, garantiza que print siempre devolverá el mismo objeto, independientemente del contexto en el que se ejecute la función. El código anterior se ejecutará bien y registrará 0, 1, 2 y 3 cuando use la versión propia de
createMyObject()
.fuente
Para completar, en ES6 tenemos clases (admitidas en el momento de escribir esto solo por los navegadores más recientes, pero disponibles en Babel, TypeScript y otros transpiladores)
fuente
Puede hacerlo utilizando el patrón del módulo. Al igual que:
Con este patrón, puede crear instancias de varios objetos foo según sus necesidades.
http://jsfiddle.net/jPNxY/1/
fuente
}();
, se ejecutaría automáticamente y devolvería un objeto, no una función. Además,foo.c
es una función, por lo que escribir en él activa esa función y fallará la próxima invocación a través defooObject.c()
. Tal vez este violín esté más cerca de lo que está buscando (también es un singleton, no diseñado para ser instanciado).Hay varias maneras de lograr esto; esto es lo que usaría:
fuente
solo por el pensamiento: coloque las propiedades del objeto fuera de una línea de tiempo:
Hay mejores respuestas arriba también . Así es como modifiqué el código de ejemplo con el que cuestionaste.
ACTUALIZAR:
fuente
var foo = { get a(){return 5}, get b(){return 6}, get c(){return this.a + this.b} }
por lo que ahora sólo se puede hacerfoo.c
en lugar defoo.c()
:) (No dude en pegar esto en su respuesta de modo de formatear es mejor!)Crear una nueva función en su objeto literal e invocar a un constructor parece una desviación radical del problema original, y es innecesario.
No puede hacer referencia a una propiedad hermana durante la inicialización literal del objeto.
La solución más simple para propiedades calculadas sigue (sin montón, sin funciones, sin constructor):
fuente
Las otras respuestas publicadas aquí son mejores, pero aquí hay una alternativa que:
init()
o código fuera del objeto literalFunciones anónimas de ejecución automática y almacenamiento de ventanas
El pedido está garantizado (
bar
antesbaz
).Contamina,
window
por supuesto, pero no puedo imaginar a alguien escribiendo un guión que requierawindow.temp
ser persistente. QuizástempMyApp
si eres paranoico.También es feo pero ocasionalmente útil. Un ejemplo es cuando está utilizando una API con condiciones de inicialización rígidas y no tiene ganas de refactorizar, por lo que el alcance es correcto.
Y está seco, por supuesto.
fuente
La clave de todo esto es ALCANCE .
Debe encapsular el "padre" (objeto padre) de la propiedad que desea definir como su propio objeto instanciado, y luego puede hacer referencias a las propiedades de los hermanos utilizando la palabra clave
this
Es muy, muy importante recordar que si te refieres
this
sin hacerlo primero,this
se referirá al alcance externo ... que será elwindow
objeto.fuente
si su objeto está escrito como una función que devuelve un objeto, Y usted usa 'métodos' de atributos de objeto ES6, entonces es posible:
fuente
Yo uso el siguiente código como alternativa, y funciona. Y la variable también puede ser matriz. (@ Fausto R.)
fuente
Aquí hay una forma ordenada de ES6:
Lo uso para hacer algo como esto:
fuente
¿Qué tal esta solución? Esto también funcionará con objetos anidados con matriz
fuente
Lanzar una opción ya que no vi este escenario exacto cubierto. Si no desea
c
actualizar cuándoa
ob
actualizar, entonces un ES6 IIFE funciona bien.Para mis necesidades, tengo un objeto que se relaciona con una matriz que terminará siendo utilizada en un bucle, por lo que solo quiero calcular una configuración común una vez, así que esto es lo que tengo:
Como necesito establecer una propiedad para
indexOfSelectedTier
y necesito usar ese valor al establecer lahasUpperTierSelection
propiedad, calculo primero ese valor y lo paso como parámetro al IIFEfuente
Otro enfoque sería declarar el objeto primero antes de asignarle propiedades:
Con eso, puede usar el nombre de la variable del objeto para acceder a los valores ya asignados.
Lo mejor para el
config.js
archivo.fuente
foo
que apunta al objeto en cuestión.Esto es casi idéntico a la respuesta de @ slicedtoad, pero no utiliza una función.
fuente
Aquí usamos expresiones de clase para obtener la interfaz literal del objeto anidado que desearíamos. Esto es lo mejor en mi humilde opinión para poder hacer referencia a las propiedades de un objeto durante la creación.
Lo principal a tener en cuenta es que al usar esta solución, tiene exactamente la misma interfaz que habría tenido de un objeto literal. Y la sintaxis está bastante cerca de un objeto literal en sí mismo (en comparación con el uso de una función, etc.).
Compara lo siguiente
Solución que he propuesto
Solución si los literales de objetos hubieran sido suficientes
Otro ejemplo
Aquí en esta clase, puede combinar múltiples rutas relativas entre sí, lo que no es posible con un objeto literal.
fuente
Si desea utilizar JS nativo, las otras respuestas proporcionan buenas soluciones.
Pero si está dispuesto a escribir objetos de autorreferencia como:
Escribí una biblioteca npm llamada self-referenced-object que admite esa sintaxis y devuelve un objeto nativo.
fuente
b
valor de la propiedad debe ser:${this.a + this.a}
. En segundo lugar, pero menos importante, querrás devolver un número, no una cadena, usando algo comoparseInt
. Por último y MÁS importante, cuando probé este ejemplo, simplemente no funciona, por la misma razón que el OP pregunta. Losthis
retornos no están definidos cuando se usa su propia declaración de objeto. @ alex-e-leon