¿Hay alguna manera de establecer el atributo predeterminado de un objeto javascript de manera que:
var emptyObj = {};
// do some magic
emptyObj.nonExistingAttribute // => defaultValue
IE puede ignorarse, Chrome Frame me ha aliviado de ese dolor de cabeza.
javascript
Sandstrom
fuente
fuente
Respuestas:
Desde que hice la pregunta hace varios años, las cosas han progresado muy bien.
Los proxies son parte de ES6. El siguiente ejemplo funciona en Chrome, Firefox, Safari y Edge :
var handler = { get: function(target, name) { return target.hasOwnProperty(name) ? target[name] : 42; } }; var p = new Proxy({}, handler); p.answerToTheUltimateQuestionOfLife; //=> 42
Lea más en la documentación de Mozilla sobre Proxies .
fuente
Object.getEntries
que no se puede llamar a un Proxy :(Object.entries
, puede modificar el controlador para establecer propiedades cuando se accede a ellas. Cambiarreturn target.hasOwnProperty(name) ? target[name] : 42;
aif (!target.hasOwnProperty(name)) target[name] = 42; return target[name];
.No hay una manera de configurar esto en Javascript: regresar
undefined
para propiedades inexistentes es parte de la especificación principal de Javascript. Vea la discusión para esta pregunta similar . Como sugerí allí, un enfoque (aunque realmente no puedo recomendarlo) sería definir unagetProperty
función global :function getProperty(o, prop) { if (o[prop] !== undefined) return o[prop]; else return "my default"; } var o = { foo: 1 }; getProperty(o, 'foo'); // 1 getProperty(o, 'bar'); // "my default"
Pero esto conduciría a un montón de código no estándar que sería difícil de leer para otros y podría tener consecuencias no deseadas en áreas donde esperaría o desearía un valor indefinido. Es mejor comprobarlo sobre la marcha:
var someVar = o.someVar || "my default";
fuente
var someVar = o.someVar || "my default";
tendrá resultados potencialmente inesperados cuando o.someVar se complete pero se evalúe como falso (por ejemplo, nulo, 0, "").someVar = o.someVar === undefined ? o.someVar : "my default";
seria mejor. Normalmente uso||
solo cuando el valor predeterminado también se evalúa comofalse. (e.g.
o.someVar || 0`)null
ofalse
de la misma manera que una propiedad no establecida, en cuyo caso esto cumple una doble función. Sin embargo, la advertencia es justa.someVar = o.someVar === undefined ? "my default" : o.someVar;
, solo un problema menor, pero meUsar desestructuración (nuevo en ES6)
Hay una gran documentación de Mozila , así como una publicación de blog fantástica que explica la sintaxis mejor que yo.
Para responder tu pregunta
var emptyObj = {}; const { nonExistingAttribute = defaultValue } = emptyObj; console.log(nonExistingAttribute); // defaultValue
Ir más lejos
¿Puedo cambiar el nombre de esta variable? ¡Por supuesto!
const { nonExistingAttribute: coolerName = 15} = emptyObj; console.log(coolerName); // 15
¿Qué pasa con los datos anidados? ¡Dale!
var nestedData = { name: 'Awesome Programmer', languages: [ { name: 'javascript', proficiency: 4, } ], country: 'Canada', }; var {name: realName, languages: [{name: languageName}]} = nestedData ; console.log(realName); // Awesome Programmer console.log(languageName); // javascript
fuente
Seguro que esto suena como el uso típico de objetos basados en prototipos:
// define a new type of object var foo = function() {}; // define a default attribute and value that all objects of this type will have foo.prototype.attribute1 = "defaultValue1"; // create a new object of my type var emptyObj = new foo(); console.log(emptyObj.attribute1); // outputs defaultValue1
fuente
attribute1: defaultValue1
está en el prototipo y console.log solo enumera los elementos establecidos en el objeto de nivel superior, no en el prototipo. Pero, el valor está ahí como misconsole.log(emptyObj.attribute1)
programas.JSON.stringify(emptyobj)
. Me vi obligado a crear un método que devuelva todos los atributos en respuesta a este problemami codigo es:
function(s){ s = { top: s.top || 100, // default value or s.top left: s.left || 300, // default value or s.left } alert(s.top) }
fuente
function foo( array $kwargs = array() ) { // Fill in defaults for optional keyworded arguments. $kwargs += array( 'show_user' => true, 'show_links' => false, ); ...
La forma en que lo logro es con la
object.assign
funciónconst defaultProperties = { 'foo': 'bar', 'bar': 'foo' }; const overwriteProperties = { 'foo': 'foo' }; const newObj = Object.assign({}, defaultProperties, overwriteProperties); console.log(defaultProperties); // {"foo": "bar", "bar": "foo"} console.log(overwriteProperties); // { "foo": "foo" }; console.log(newObj); // { "foo": "foo", "bar": "foo" }
fuente
overwriteProperties
la forma correcta es:const newObj = Object.assign({}, defaultProperties, overwriteProperties)
Creo que el enfoque más simple es utilizar
Object.assign
.Si tiene esta clase:
class MyHelper { constructor(options) { this.options = Object.assign({ name: "John", surname: "Doe", birthDate: "1980-08-08" }, options); } }
Puedes usarlo así:
let helper = new MyHelper({ name: "Mark" }); console.log(helper.options.surname); // this will output "Doe"
Documentación (con polyfill): https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
fuente
O puedes probar esto
dict = { 'somekey': 'somevalue' }; val = dict['anotherkey'] || 'anotherval';
fuente
String()
arreglarías eso? Como en:val = dict[String('anotherkey')] || 'anotherval';
d = {x: 1, y: 0}
entoncesd['y'] || 100
y no, erróneamente da 100. Luego pruebe su idea, que esd[String('y')] || 100
: todavía da incorrectamente 100 cuando debería dar 0.La más simple de todas las soluciones:
dict = {'first': 1, 'second': 2, 'third': 3}
Ahora,
dict['last'] || 'Excluded'
devolverá 'Excluido', que es el valor predeterminado.
fuente
dict = {'first': 0, 'second': 1, 'third': 2}
a.b.c.d
. Si no están definidos A, D, C o se golpea un error, pero sólo puede hacerlo(((a || {}).b || {}).c || {}).d) || "default"
Esta me parece la forma más sencilla y legible de hacerlo:
let options = {name:"James"} const default_options = {name:"John", surname:"Doe"} options = Object.assign({}, default_options, options)
Referencia de Object.assign ()
fuente
Ayer vi un artículo que menciona una
Object.__noSuchMethod__
propiedad: JavascriptTips No he tenido la oportunidad de jugar con él, así que no sé sobre la compatibilidad con el navegador, pero ¿tal vez podrías usar eso de alguna manera?fuente
Me sorprende que nadie haya mencionado al operador ternario todavía.
var emptyObj = {a:'123', b:'234', c:0}; var defaultValue = 'defaultValue'; var attr = 'someNonExistAttribute'; emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue;//=> 'defaultValue' attr = 'c'; // => 'c' emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue; // => 0
De esta manera, incluso si el valor de 'c' es 0, seguirá obteniendo el valor correcto.
fuente
Object.withDefault = (defaultValue,o={}) => { return new Proxy(o, { get: (o, k) => (k in o) ? o[k] : defaultValue }); } o = Object.withDefault(42); o.x //=> 42 o.x = 10 o.x //=> 10 o.xx //=> 42
fuente
De hecho, es posible hacerlo
Object.create
. No funcionará para propiedades "no definidas". Pero para los que se les ha dado un valor predeterminado.var defaults = { a: 'test1', b: 'test2' };
Luego, cuando crea su objeto de propiedades, lo hace con
Object.create
properties = Object.create(defaults);
Ahora tendrá dos objetos donde el primer objeto está vacío, pero el prototipo apunta al
defaults
objeto. Probar:console.log('Unchanged', properties); properties.a = 'updated'; console.log('Updated', properties); console.log('Defaults', Object.getPrototypeOf(properties));
fuente
Un enfoque sería tomar un objeto predeterminado y fusionarlo con el objeto de destino. El objeto de destino anularía los valores del objeto predeterminado.
jQuery tiene el
.extend()
método que hace esto. Sin embargo, jQuery no es necesario, ya que hay implementaciones de JS vanilla como las que se pueden encontrar aquí:http://gomakethings.com/vanilla-javascript-version-of-jquery-extend/
fuente
Vine aquí buscando una solución porque el encabezado coincidía con la descripción de mi problema, pero no es lo que estaba buscando, pero obtuve una solución a mi problema (quería tener un valor predeterminado para un atributo que sería dinámico, algo como fecha ).
let Blog = { title : String, image : String, body : String, created: {type: Date, default: Date.now} }
El código anterior fue la solución por la que finalmente me conformé.
fuente