배경
config
객체를 인수로 취하는 함수가 있습니다. 함수 내에도 default
객체가 있습니다. 이러한 각 개체에는 기본적으로 함수 내의 나머지 코드에 대한 설정으로 작동하는 속성이 포함되어 있습니다. config
객체 내의 모든 설정을 지정할 필요가 없도록하기 위해 jQuery의 extend
메서드를 사용 settings
하여 default
객체에 지정되지 않은 경우 객체의 기본값으로 새 객체를 채 웁니다 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};
문제
이것은 훌륭하게 작동하지만 jQuery 없이도이 기능을 재현하고 싶습니다. 평범한 자바 스크립트로 이것을 수행하는 똑같이 우아한 (또는 가까운) 수단이 있습니까?
편집 : 중복되지 않은 사유
이 질문은 ” 어떻게 두 JavaScript 객체의 속성을 동적으로 병합 할 수 있습니까? “질문과 중복되지 않습니다 . 이 질문은 단순히 두 개의 개별 객체의 모든 키와 값을 포함하는 객체를 생성하려는 반면, 두 객체가 일부 키를 공유하지만 모든 키를 공유하고 어떤 객체가 우선 순위를 가질 경우이를 수행하는 방법을 구체적으로 설명하고 싶습니다 ( 중복 키가있는 경우 결과 개체에 대해 기본값). 그리고 더 구체적으로, 나는 이것을 달성하기 위해 jQuery의 방법을 사용하고 jQuery없이 그렇게 할 수있는 다른 방법을 찾고 싶었다. 두 질문에 대한 많은 답변이 겹치지 만 그렇다고 질문 자체가 동일하다는 의미는 아닙니다.
답변
코드에서 결과를 얻으려면 다음을 수행하십시오.
function extend(a, b){
for(var key in b)
if(b.hasOwnProperty(key))
a[key] = b[key];
return a;
}
사용한 방법에 따라 기본 개체가 수정됩니다. 원하지 않으면
$.extend({}, default, config)
jQuery의 기능을 모방하는보다 강력한 솔루션은 다음과 같습니다.
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];
}
답변
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"}
하나 이상의 소스 개체에서 모든 열거 가능한 고유 속성의 값을 대상 개체로 복사하고 대상 개체를 반환합니다.
Object.assign(target, ...sources)
IE를 제외한 모든 데스크톱 브라우저에서 작동합니다 (Edge 포함). 모바일 지원이 완화되었습니다.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign 에서 직접 확인하십시오.
딥 카피 정보
그러나 Object.assign에는 jQuery의 extend 메소드에있는 딥 옵션이 없습니다.
참고 : 일반적으로 유사한 효과를 위해 JSON을 사용할 수 있습니다.
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"}
답변
답변
이것은 jQuery 종속성을 제거하려고 시도하면서 내놓은 딥 카피와 약간 다른 접근 방식입니다. 대부분 작게 설계되었으므로 예상되는 모든 기능이 없을 수도 있습니다. ES5와 완전히 호환되어야합니다 ( Object.keys 사용으로 인해 IE9부터 시작 ) :
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;
}
다섯 번째 줄이 정확히 무엇을하는지 궁금 할 것입니다. obj2.key가 객체 리터럴이면 (즉, 일반 유형이 아닌 경우) 우리는 그것에 대해 재귀 적으로 extend를 호출합니다. 해당 이름의 속성이 obj1에 아직 존재하지 않는 경우 먼저 빈 객체로 초기화합니다. 그렇지 않으면 단순히 obj1.key를 obj2.key로 설정합니다.
여기에서 작동하는 일반적인 사례를 증명해야하는 몇 가지 mocha / chai 테스트가 있습니다.
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',
});
});
이 구현에 대한 피드백이나 의견에 만족합니다. 미리 감사드립니다!
답변
for
문을 사용하여 Object의 속성을 반복 할 수 있습니다 .
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;
}
답변
내 일반 forEachIn을 사용하고 첫 번째 개체를 엉망으로 만들지 않는이 코드를 선호합니다.
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;
}
정말로 물건을 첫 번째 객체에 병합하고 싶다면 다음을 수행 할 수 있습니다.
obj1 = extend(obj1, obj2);
답변
순수한 자바 스크립트로 개발할 때 많은 도움이됩니다.
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;
}