tag change javascript jquery object extend

change - JavaScript equivalente al método extendido de jQuery



change title javascript (8)

Posible duplicado:
¿Cómo puedo fusionar las propiedades de dos objetos de JavaScript de forma dinámica?

Fondo

Tengo una función que toma un objeto de config como argumento. Dentro de la función, también tengo un objeto default . Cada uno de esos objetos contiene propiedades que funcionan esencialmente como configuraciones para el resto del código dentro de la función. Para evitar tener que especificar todas las configuraciones dentro del objeto config , utilizo el método extend de jQuery para completar un nuevo objeto, las settings con cualquier valor default objeto default si no se especificaron en el objeto config :

var config = {key1: value1}; var default = {key1: default1, key2: default2, key 3: default 3}; var settings = $.extend(default, config); //resulting properties of settings: settings = {key1: value1, key2: default2, key 3: default 3};

Problema

Esto funciona muy bien, pero me gustaría reproducir esta funcionalidad sin la necesidad de jQuery. ¿Existe un medio igualmente elegante (o cercano) para hacer esto con simple ol ''javascript?

Editar: Justificación no duplicada

Esta pregunta no es un duplicado de la pregunta " ¿Cómo puedo fusionar propiedades de dos objetos JavaScript dinámicamente? ". Mientras que esa pregunta simplemente quiere crear un objeto que contenga todas las claves y valores de dos objetos separados. Específicamente quiero abordar cómo hacer esto en el caso de que ambos objetos compartan algunas, pero no todas, y qué objeto tendrá precedencia ( el valor predeterminado) para el objeto resultante en el caso de que haya claves duplicadas. Y aún más específicamente, quería abordar el uso del método de jQuery para lograr esto y encontrar una forma alternativa de hacerlo sin jQuery. Si bien muchas de las respuestas a ambas preguntas se superponen, eso no significa que las preguntas en sí mismas sean las mismas.


Este es mi enfoque ligeramente diferente con la copia profunda que se me ocurrió al tratar de eliminar una dependencia de jQuery. Está diseñado principalmente para ser pequeño, por lo que podría no tener todas las características que uno espera. Debe ser totalmente compatible con ES5 (a partir de IE9 debido al uso de Object.keys ):

function extend(obj1, obj2) { var keys = Object.keys(obj2); for (var i = 0; i < keys.length; i += 1) { var val = obj2[keys[i]]; obj1[keys[i]] = [''string'', ''number'', ''array'', ''boolean''].indexOf(typeof val) === -1 ? extend(obj1[keys[i]] || {}, val) : val; } return obj1; }

Puede preguntarse qué hace exactamente la quinta línea ... Si obj2.key es un objeto literal (es decir, si no es un tipo ordinario) recurrimos de forma recurrente a extenderlo. Si una propiedad con ese nombre todavía no existe en obj1, primero lo inicializamos en un objeto vacío. De lo contrario, simplemente establecemos obj1.key en obj2.key.

Estas son algunas de mis pruebas de mocha / chai que deberían probar los casos comunes para trabajar aquí:

it(''should extend a given flat object with another flat object'', () => { const obj1 = { prop1: ''val1'', prop2: 42, prop3: true, prop4: 20.16, }; const obj2 = { prop4: 77.123, propNew1: ''newVal1'', propNew2: 71, }; assert.deepEqual(utils.extend(obj1, obj2), { prop1: ''val1'', prop2: 42, prop3: true, prop4: 77.123, propNew1: ''newVal1'', propNew2: 71, }); }); it(''should deep-extend a given flat object with a nested object'', () => { const obj1 = { prop1: ''val1'', prop2: ''val2'', }; const obj2 = { propNew1: ''newVal1'', propNew2: { propNewDeep1: ''newDeepVal1'', propNewDeep2: 42, propNewDeep3: true, propNewDeep4: 20.16, }, }; assert.deepEqual(utils.extend(obj1, obj2), { prop1: ''val1'', prop2: ''val2'', propNew1: ''newVal1'', propNew2: { propNewDeep1: ''newDeepVal1'', propNewDeep2: 42, propNewDeep3: true, propNewDeep4: 20.16, }, }); }); it(''should deep-extend a given nested object with another nested object and deep-overwrite members'', () => { const obj1 = { prop1: ''val1'', prop2: { propDeep1: ''deepVal1'', propDeep2: 42, propDeep3: true, propDeep4: { propDeeper1: ''deeperVal1'', propDeeper2: 777, propDeeper3: ''I will survive'', }, }, prop3: ''lone survivor'', }; const obj2 = { prop1: ''newVal1'', prop2: { propDeep1: ''newDeepVal1'', propDeep2: 84, propDeep3: false, propDeep4: { propDeeper1: ''newDeeperVal1'', propDeeper2: 888, }, }, }; assert.deepEqual(utils.extend(obj1, obj2), { prop1: ''newVal1'', prop2: { propDeep1: ''newDeepVal1'', propDeep2: 84, propDeep3: false, propDeep4: { propDeeper1: ''newDeeperVal1'', propDeeper2: 888, propDeeper3: ''I will survive'', }, }, prop3: ''lone survivor'', }); });

Me gustaría recibir comentarios o comentarios sobre esta implementación. ¡Gracias por adelantado!


Me ayuda mucho cuando desarrollo con javascript puro.

function extends(defaults, selfConfig){ selfConfig = JSON.parse(JSON.stringify(defaults)); for (var item in config) { if (config.hasOwnProperty(item)) { selfConfig[item] = config[item]; } } return selfConfig; }


Para obtener el resultado en tu código, harías:

function extend(a, b){ for(var key in b) if(b.hasOwnProperty(key)) a[key] = b[key]; return a; }

Tenga en cuenta que la forma en que utilizó ampliar extenderá el objeto predeterminado. Si no quieres eso, usa

$.extend({}, default, config)

Una solución más robusta que imita la funcionalidad de jQuery sería la siguiente:

function extend(){ for(var i=1; i<arguments.length; i++) for(var key in arguments[i]) if(arguments[i].hasOwnProperty(key)) arguments[0][key] = arguments[i][key]; return arguments[0]; }


Prefiero este código que usa mi genérico forEachIn, y no destruye el primer objeto:

function forEachIn(obj, fn) { var index = 0; for (var key in obj) { if (obj.hasOwnProperty(key)) { fn(obj[key], key, index++); } } } function extend() { var result = {}; for (var i = 0; i < arguments.length; i++) { forEachIn(arguments[i], function(obj, key) { result[key] = obj; }); } return result; }

Si realmente desea fusionar cosas en el primer objeto, puede hacer:

obj1 = extend(obj1, obj2);


Puede recorrer las propiedades de Object usando la instrucción for .

var settings = extend(default, config); function extend(a, b){ var c = {}; for(var p in a) c[p] = (b[p] == null) ? a[p] : b[p]; return c; }


Puede usar el operador extendido ECMA 2015 ...

var config = {key1: value1}; var default = {key1: default1, key2: default2, key 3: default 3}; var settings = {...default, ...config} //resulting properties of settings: settings = {key1: value1, key2: default2, key 3: default 3};

Soporte BabelJS para navegadores antiguos


Puedes usar Object.assign.

var defaults = {key1: "default1", key2: "default2", key3: "defaults3"}; var config = {key1: "value1"}; var settings = Object.assign({}, defaults, config); // values in config override values in defaults console.log(settings); // Object {key1: "value1", key2: "default2", key3: "defaults3"}

Copia los valores de todas las propiedades enumerables de uno o más objetos de origen en un objeto de destino y devuelve el objeto de destino.

Object.assign(target, ...sources)

Funciona en todos los navegadores de escritorio excepto IE (pero incluye Edge). Ha mitigado el soporte móvil.

Véalo usted mismo aquí: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Sobre la copia profunda

Sin embargo, Object.assign no tiene la opción profunda que tiene el método extend de jQuery.

Nota: en general, puede usar JSON para un efecto similar aunque

var config = {key1: "value1"}; var defaults = {key1: "default1", key2: "default2", keyDeep: { kd1: "default3", kd2: "default4" }}; var settings = JSON.parse(JSON.stringify(Object.assign({}, defaults, config))); console.log(settings.keyDeep); // Object {kd1: "default3", kd2: "default4"}


El enfoque de Ivan Kuckir también se puede adaptar para crear un nuevo prototipo de objeto:

Object.prototype.extend = function(b){ for(var key in b) if(b.hasOwnProperty(key)) this[key] = b[key]; return this; } var settings = default.extend(config);