options
변수가 있고 기본값을 설정하고 싶다고 가정 해 봅시다 .
이 두 대안의 장점 / 단점은 무엇입니까?
객체 확산 사용
options = {...optionsDefault, ...options};
또는 Object.assign 사용
options = Object.assign({}, optionsDefault, options);
이것이 나를 놀라게 한 커밋 입니다.
options
변수가 있고 기본값을 설정하고 싶다고 가정 해 봅시다 .
이 두 대안의 장점 / 단점은 무엇입니까?
객체 확산 사용
options = {...optionsDefault, ...options};
또는 Object.assign 사용
options = Object.assign({}, optionsDefault, options);
이것이 나를 놀라게 한 커밋 입니다.
답변:
이것은 반드시 완전한 것은 아닙니다.
options = {...optionsDefault, ...options};
기본 지원이없는 환경에서 실행할 코드를 작성하는 경우, polyfill을 사용하는 대신이 구문을 컴파일 할 수 있습니다. (예를 들어, 바벨과 함께)
덜 장황하다.
이 답변이 처음 쓰여졌을 때 표준화되지 않은 제안 . 제안서를 사용할 때 지금 코드를 작성하고 표준화를 진행함에 따라 표준화되지 않거나 변경되지 않는 경우 수행 할 작업을 고려하십시오. 이후 ES2018에서 표준화되었습니다.
동적이 아닌 리터럴.
Object.assign()
options = Object.assign({}, optionsDefault, options);
표준화.
동적. 예:
var sources = [{a: "A"}, {b: "B"}, {c: "C"}];
options = Object.assign.apply(Object, [{}].concat(sources));
// or
options = Object.assign({}, ...sources);
이것이 나를 놀라게 한 커밋입니다.
그것은 당신이 요구하는 것과 직접 관련이 없습니다. 해당 코드는을 사용하지 않았 으며 동일한 작업을 수행하는 Object.assign()
사용자 코드 ( object-assign
)를 사용하고있었습니다 . 그들은 Babel을 사용하여 코드를 컴파일하고 Webpack과 번들로 묶는 것처럼 보입니다. 그들은 분명히 object-assign
빌드에 들어갈 종속성 으로 포함하는 것을 선호했습니다 .
Object.assign()
. 또는 수동으로 객체 배열과 대상에 수동으로 할당하는 자체 소품을 반복하여 더 자세하게 만들 수 있습니다. : P
ECMAScript 2018에서는 참조 오브젝트 레스트 / 스프레드가 4 단계로 마무리됩니다. 제안은 여기 에서 찾을 수 있습니다 .
대부분의 객체 재설정 및 확산 작업은 동일한 방식으로, 주요 차이점은 spread는 속성을 정의하고 Object.assign ()이 속성을 설정 한다는 것 입니다. 이것은 Object.assign ()이 setter를 트리거한다는 것을 의미합니다.
이것 이외의 오브젝트 레스트 / 스프레드 1 : 1은 Object.assign ()에 매핑되고 배열 (반복 가능) 스프레드에 다르게 작동한다는 것을 기억할 가치가 있습니다. 예를 들어, 배열을 펼칠 때 null 값이 펼칩니다. 그러나 객체 스프레드를 사용하면 null 값이 자동으로 아무 것도 퍼지지 않습니다.
배열 (반복 가능) 스프레드 예
const x = [1, 2, null , 3];
const y = [...x, 4, 5];
const z = null;
console.log(y); // [1, 2, null, 3, 4, 5];
console.log([...z]); // TypeError
개체 확산 예
const x = null;
const y = {a: 1, b: 2};
const z = {...x, ...y};
console.log(z); //{a: 1, b: 2}
이는 Object.assign ()의 작동 방식과 일치하며 오류없이 null 값을 자동으로 제외합니다.
const x = null;
const y = {a: 1, b: 2};
const z = Object.assign({}, x, y);
console.log(z); //{a: 1, b: 2}
Object.assign
세터를 사용한다는 것입니다. Object.assign({set a(v){this.b=v}, b:2}, {a:4}); // {b: 4}
vs.{...{set a(v){this.b=v}, b:2}, ...{a:4}}; // {a: 4, b: 2}
const x = {c: null};
. 어떤 경우에, AFAIK, 우리는 배열과 같은 행동을 보게 될 것입니다 : //{a: 1, b: 2, c: null}
.
스프레드 연산자와 Object.assign
현재 답변에서 언급되지 않은 것의 큰 차이점 은 스프레드 연산자가 소스 객체의 프로토 타입을 대상 객체에 복사하지 않는다는 것입니다. 객체에 속성을 추가하고 객체의 인스턴스를 변경하지 않으려면을 사용해야 Object.assign
합니다. 아래 예제는 이것을 보여 주어야합니다.
const error = new Error();
error instanceof Error // true
const errorExtendedUsingSpread = {
...error,
...{
someValue: true
}
};
errorExtendedUsingSpread instanceof Error; // false
const errorExtendedUsingAssign = Object.assign(error, {
someValue: true
});
errorExtendedUsingAssign instanceof Error; // true
errorExtendedUsingAssign === error
, 그러나 errorExtendedUsingSpread
새로운 객체입니다 (그리고 프로토 타입은 복사되지 않았습니다).
let target = Object.create(source); Object.assign(target, source);
다른 사람들이 언급했듯이,이 글을 쓰는 순간에 Object.assign()
폴리 필이 ...
필요 하고 객체 스프레드 에는 작동하기 위해 약간의 트랜스 필링 (그리고 아마도 폴리 필도 필요)이 필요합니다.
이 코드를 고려하십시오.
// Babel wont touch this really, it will simply fail if Object.assign() is not supported in browser.
const objAss = { message: 'Hello you!' };
const newObjAss = Object.assign(objAss, { dev: true });
console.log(newObjAss);
// Babel will transpile with use to a helper function that first attempts to use Object.assign() and then falls back.
const objSpread = { message: 'Hello you!' };
const newObjSpread = {...objSpread, dev: true };
console.log(newObjSpread);
둘 다 동일한 출력을 생성합니다.
다음은 Babel에서 ES5 로의 출력입니다.
var objAss = { message: 'Hello you!' };
var newObjAss = Object.assign(objAss, { dev: true });
console.log(newObjAss);
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var objSpread = { message: 'Hello you!' };
var newObjSpread = _extends({}, objSpread, { dev: true });
console.log(newObjSpread);
이것은 지금까지 나의 이해입니다. Object.assign()
객체 확산 ...
이 아직없는 곳에서 실제로 표준화되었습니다 . 유일한 문제는 전자에 대한 브라우저 지원과 미래에 대한 브라우저 지원입니다.
도움이 되었기를 바랍니다.
{}
하면 불일치를 수정해야합니다.
객체 스프레드 연산자 (...)는 브라우저에서 작동하지 않습니다. 아직 ES 사양의 일부가 아니며 제안 일뿐입니다. 유일한 옵션은 Babel (또는 이와 유사한 것)로 컴파일하는 것입니다.
보다시피 Object.assign ({})에 대한 구문 설탕 일뿐입니다.
내가 볼 수있는 한, 이것들은 중요한 차이점입니다.
...
개체가 표준화되지 않았습니다...
실수로 오브젝트를 변경하지 않도록 보호...
브라우저없이 Object.assign을 polyfill합니다....
같은 생각을 표현하기 위해 더 적은 코드가 필요하다Object.assign
확산 연산자는 항상 당신에게 새로운 객체를 줄 것 같은.
"스프레드 오브젝트 병합"ES 기능, 브라우저 및 생태계에서 도구를 통해 상태를 요약하고 싶습니다.
var x = { a: 1, b: 2 };
var y = { c: 3, d: 4, a: 5 };
var z = {...x, ...y};
console.log(z); // { a: 5, b: 2, c: 3, d: 4 }
다시 :이 샘플을 작성할 때이 샘플은 Chrome (60+), Firefox Developer Edition (Firefox 60의 미리보기) 및 노드 (8.7+)에서 변환없이 작동합니다.
나는 원래 질문 후 2.5 년 을 쓰고 있습니다. 그러나 나는 똑같은 질문을했고 이것이 Google이 보낸 곳입니다. 나는 긴 꼬리를 향상시키는 SO의 사명의 노예입니다.
이것이 "배열 확산"구문의 확장이기 때문에 Google에 매우 어려워 호환성 테이블에서 찾기가 어렵다는 것을 알았습니다. 내가 찾을 수있는 가장 가까운 것은 Kangax "속성 확산"입니다 이지만,이 테스트에는 같은 식으로 두 개의 스프레드가 없습니다 (병합 아님). 또한 제안서 / 초안 / 브라우저 상태 페이지의 이름은 모두 "속성 스프레드"를 사용하지만 커뮤니티가 제안서 다음에 "개체 병합"에 대한 스프레드 구문을 사용하기 위해 도착한 "첫 번째 주체"인 것 같습니다. (Google이 왜 그렇게 어려운지 설명 할 수 있습니다.) 따라서 다른 사람들이이 특정 기능에 대한 링크를보고 업데이트하고 컴파일 할 수 있도록 여기에 찾은 결과를 문서화합니다. 나는 그것이 붙잡기를 바란다. 사양 및 브라우저에 상륙한다는 소식을 알리십시오.
마지막으로이 정보를 주석으로 추가했지만 저자의 원래 의도를 깨뜨리지 않고는 정보를 편집 할 수 없었습니다. 특히 @RichardSchulte를 수정하려는 의도를 잃지 않으면 @ChillyPenguin의 의견을 편집 할 수 없습니다. 그러나 몇 년 후 Richard는 (내 의견으로는) 옳았습니다. 그래서 나는이 답변을 씁니다. 오래된 답변에 결국 견인력을 갖기를 기대합니다 (몇 년이 걸릴 수 있지만 결국 긴 꼬리 효과가 있습니다).
참고 : 확산은 Object.assign 주위의 구문 설탕이 아닙니다. 그들은 배후에서 크게 다르게 작동합니다.
Object.assign은 setter를 새 객체에 적용하지만 Spread는 적용하지 않습니다. 또한 객체는 반복 가능해야합니다.
복사이 시점에서 개체의 값이 필요하고 해당 값이 개체의 다른 소유자가 변경 한 내용을 반영하지 않게하려면이 옵션을 사용하십시오.
변경 불가능한 버전은 변경 불가능한 속성으로 전달 될 수 있으므로 복사는 항상 변경 불가능한 오브젝트를 처리 할 수 있도록하기 위해 항상 변경 불가능한 특성을 복사하도록 오브젝트의 단순 사본을 작성하는 데 사용하십시오.
할당 할당은 복사와 반대입니다. Assign은 값을 복사하거나 유지하지 않고 인스턴스 변수에 직접 값을 지정하는 setter를 생성합니다. assign 속성의 getter를 호출하면 실제 데이터에 대한 참조가 반환됩니다.
다른 답변은 오래되었으므로 좋은 답변을 얻을 수 없습니다.
아래 예제는 객체 리터럴을위한 것으로, 서로 보완 할 수있는 방법과 서로 보완 할 수없는 방법 (따라서 차이)에 도움이됩니다.
var obj1 = { a: 1, b: { b1: 1, b2: 'b2value', b3: 'b3value' } };
// overwrite parts of b key
var obj2 = {
b: {
...obj1.b,
b1: 2
}
};
var res2 = Object.assign({}, obj1, obj2); // b2,b3 keys still exist
document.write('res2: ', JSON.stringify (res2), '<br>');
// Output:
// res2: {"a":1,"b":{"b1":2,"b2":"b2value","b3":"b3value"}} // NOTE: b2,b3 still exists
// overwrite whole of b key
var obj3 = {
b: {
b1: 2
}
};
var res3 = Object.assign({}, obj1, obj3); // b2,b3 keys are lost
document.write('res3: ', JSON.stringify (res3), '<br>');
// Output:
// res3: {"a":1,"b":{"b1":2}} // NOTE: b2,b3 values are lost
배열 및 객체에 대한 몇 가지 더 작은 예제 :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
이것은 현재 ES6의 일부이므로 표준화되어 있으며 MDN에도 문서화되어 있습니다. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator
사용하는 것이 매우 편리하고 객체 파괴와 함께 많은 의미가 있습니다.
위에 나열된 나머지 장점 중 하나는 Object.assign ()의 동적 기능이지만, 리터럴 객체 내부에 배열을 확산시키는 것만 큼 쉽습니다. 컴파일 된 babel 출력에서 Object.assign ()으로 보여지는 것을 정확하게 사용합니다.
정답은 이제 표준화되고 널리 사용되며 (반응, 리덕스 등 참조) 사용하기 쉽고 Object.assign ()의 모든 기능을 가지고 있기 때문에 객체 확산을 사용하는 것입니다.
Object.assign을 사용해야 할 때이 간단한 예제를 추가하고 싶습니다.
class SomeClass {
constructor() {
this.someValue = 'some value';
}
someMethod() {
console.log('some action');
}
}
const objectAssign = Object.assign(new SomeClass(), {});
objectAssign.someValue; // ok
objectAssign.someMethod(); // ok
const spread = {...new SomeClass()};
spread.someValue; // ok
spread.someMethod(); // there is no methods of SomeClass!
JavaScript를 사용할 때는 명확하지 않습니다. 그러나 TypeScript를 사용하면 일부 클래스의 인스턴스를 만들고 싶다면 더 쉽습니다.
const spread: SomeClass = {...new SomeClass()} // Error