programing

오브젝트 범위와Object.assign(Object.assign)

copysource 2022. 10. 21. 22:19
반응형

오브젝트 범위와Object.assign(Object.assign)

내가 ㅇㅇㅇㅇㅇㅇㅇ가 하자.options기본값을 설정합니다.

이 두 가지 대안의 장점/단점은 무엇입니까?

개체 범위 사용

options = {...optionsDefault, ...options};

또는 Object.assign을 사용합니다.

options = Object.assign({}, optionsDefault, options);

이것이 나를 궁금하게 만든 약속이다.

이것이 반드시 모든 것을 망라하는 것은 아니다.

구문 확산

options = {...optionsDefault, ...options};

장점:

  • 네이티브 지원이 없는 환경에서 실행할 코드를 작성하는 경우 이 구문을 (폴리필을 사용하는 것이 아니라) 컴파일할 수 있습니다.(예를 들어 바벨과 함께)

  • 장황하지 않다.

단점:

  • 이 답변이 처음 작성되었을 때, 이것은 표준이 아닌 제안서였습니다.제안서를 사용할 때는 지금 코드를 작성해도 표준화되지 않거나 표준화로 넘어갈 때 변경되지 않을 경우 어떻게 해야 할지 고려합니다.이후 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);
    

단점:

  • 좀 더 장황하게.
  • 네이티브 지원이 없는 환경에서 실행할 코드를 작성하는 경우 폴리필이 필요합니다.

이것이 나를 궁금하게 만든 약속이다.

그건 당신이 묻는 것과 직접적으로 관련이 없어요.그그 wasn that that that that that that that that가 사용되지 않았습니다.Object.assign() , , , , , , , )를 object-assign도 같은 도 같은 기능을 합니다.그들은 그 코드를 Babel로 컴파일하고 있는 것 같습니다(그리고 Webpack으로 번들하고 있습니다).이데올로기 때문에은 그것을 꼭 시켜야 하는 보다 더 것 같다.object-assign★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

참조 물체의 휴식/확장은 ECMAScript 2018에서 4단계로 확정되었다.제안서는 여기에서 찾을 수 있습니다.

대부분의 부품 오브젝트 할당과 확산 작업은 동일한 방식으로 이루어집니다.중요한 차이점은 Object.assign()이 속성을 설정하는 동안 확산이 속성을 정의한다는 것입니다.이는 Object.assign()이 세터를 트리거함을 의미합니다.

이 외에도 오브젝트 rest/spread 1:1은 Object.assign()에 매핑되어 어레이(반복 가능) 확산에 대해 다르게 동작한다는 점에 유의하십시오.예를 들어 어레이를 확산하는 경우 null 값은 확산됩니다.단, 오브젝트 스프레드 늘 값을 사용하면 사일런트하게 됩니다.

배열(Itherable) 확산 예시

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()의 동작 방식과 일치하며 둘 다 오류 없이 늘 값을 자동으로 제외합니다.

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.

편집: 저는 실제로 제 예가 오해를 불러일으킨다는 것을 깨달았습니다.는 을(를) 한다.Object.assign첫 번째 매개 변수를 빈 개체로 설정합니다.를 에러의 첫로 하고 .Object.assign두 개가 동일하지 않도록 합니다.의 첫 .Object.assign실제로 수정되어 반환되기 때문에 프로토타입이 유지됩니다.이치

const error = new Error();
error instanceof Error // true

const errorExtendedUsingSpread = {
  ...error,
  ...{
    someValue: true
  }
};
errorExtendedUsingSpread instanceof Error; // false

// What the spread operator desugars into
const errorExtendedUsingImmutableObjectAssign = Object.assign({}, error, {
    someValue: true
});
errorExtendedUsingImmutableObjectAssign instanceof Error; // false

// The error object is modified and returned here so it keeps its prototypes
const errorExtendedUsingAssign = Object.assign(error, {
  someValue: true
});
errorExtendedUsingAssign instanceof Error; // true

참고 항목: https://github.com/tc39/proposal-object-rest-spread/blob/master/Spread.md

메모: Object.assign에 따라 퍼지는 것은 구문설탕뿐만이 아닙니다.그들은 배후에서 훨씬 다르게 행동한다.

Object.assign은 세터를 새 개체에 적용하지만 스프레드는 적용하지 않습니다.또한 오브젝트는 반복 가능해야 합니다.

복사 현재 개체의 값이 필요하고 이 값이 개체의 다른 소유자가 변경한 내용을 반영하지 않으려면 이 옵션을 사용합니다.

오브젝트 베스트 프랙티스의 얕은 카피를 작성하기 위해서 사용합니다.복사할 불변의 속성을 항상 설정할 수 있습니다.변동 가능한 버전을 불변의 속성에 전달할 수 있기 때문에 복사를 통해 항상 불변의 오브젝트를 처리할 수 있습니다.

Assign은 복사와 약간 반대입니다.Assign은 값을 복사하거나 유지하는 대신 인스턴스 변수에 직접 할당하는 세터를 생성합니다.할당 속성의 getter를 호출하면 실제 데이터에 대한 참조가 반환됩니다.

툴을 통해 브라우저 및 에코시스템에서 "개체 확산" ES 기능의 상태를 요약하고 싶습니다.

사양

브라우저: Chrome, SF, 곧 Firefox (ver 60, IIUC)

  • 이 시나리오를 포함한 Chrome 60에 탑재된 "확산 속성"에 대한 브라우저 지원.
  • 이 시나리오에 대한 지원은 현재 Firefox(59)에서는 사용할 수 없지만 Firefox Developer Edition에서는 사용할 수 있습니다.파이어폭스 60으로 배송될 것 같습니다.
  • Safari: 테스트되지 않았지만 Kangax는 Desktop Safari 11.1에서는 동작하지만 SF 11에서는 동작하지 않는다고 합니다.
  • iOS Safari: 테제트는 없지만 Kangax는 iOS 11.3에서는 동작하지만 iOS 11에서는 동작하지 않는다고 말합니다.
  • 엣지 없음

도구: Node 8.7, TS 2.1

  • NodeJS는 8.7 이후(Kangax 경유) 지원되고 있습니다.현지 테스트 결과 9.8에 확인되었습니다.
  • TypeScript는 2.1부터 지원, 현재 2.8

링크

코드 샘플(호환성 테스트로 이중화)

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 미리보기) 및 Node(8.7+)에서 변환 없이 작동합니다.

왜 대답하는가?

처음 질문한 지 2.5년 만에 쓰는 글입니다.하지만 저는 똑같은 질문을 했습니다. 그리고 이것이 구글이 저에게 보낸 것입니다.나는 긴 꼬리를 개량하는 SO의 임무의 노예이다.

이것은 "array spread" 구문의 확장이기 때문에 구글 검색은 매우 어렵고 호환성 표에서도 찾기 어렵다는 것을 알았습니다.가장 가까운 것은 Kangax "property spread"입니다만, 그 테스트에서는, 같은 식에 2개의 spread가 없습니다(머지가 아닙니다.또한 제안서/초안/브라우저 상태 페이지의 이름은 모두 "property spread"를 사용하지만, 그것은 커뮤니티가 "object merge"를 위한 확산 구문을 사용하는 제안 이후 처음 도착한 "pirst principle"인 것처럼 보입니다.(그래서 구글 검색이 어려운 이유일 수 있습니다.)다른 사용자가 이 특정 기능에 대한 링크를 표시, 업데이트 및 컴파일할 수 있도록 검색 결과를 여기에 기록합니다.잘 맞았으면 좋겠다.스펙이나 브라우저에 착지 소식을 전해주세요.

마지막으로 이 내용을 코멘트로 추가했을 텐데, 저자의 본래 취지를 어기지 않고는 편집할 수 없었습니다.구체적으로 @Chilly Penguin의 코멘트를 편집하려면 @Richard Schulte를 수정해야 합니다.하지만 수년 후 리처드가 옳다는 것이 밝혀졌다.그래서 나는 이 답을 대신 쓰고, 그것이 결국 오래된 답들에 대한 관심을 끌기를 바란다(몇 년이 걸릴지 모르지만, 결국 그것이 긴 꼬리 효과의 전부이다).

이 에도 다른 언급했듯이, 이 을 쓰는 이 순간에는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()표준화되어 가 퍼지면 이 됩니다.여기서 오브젝트가 퍼지면..., 대한 입니다.유일한 문제는 전자와 미래, 후자에 대한 브라우저 지원입니다.

여기서 코드 재생

이게 도움이 됐으면 좋겠다.

그 둘 사이에는 큰 차이가 있고 매우 심각한 결과를 초래한다.가장 많이 투표된 질문들은 심지어 이것조차 다루지 않고, 오브젝트 확산에 대한 정보는 2022년에 더 이상 관련이 없다.

차이점은 가 개체를 인플레이스 상태로 변경하는 반면 ...확산 연산자()는 개체를 생성하므로 개체 참조의 동일성이 깨집니다.

우선 그 효과를 살펴본 후 이 근본적인 차이를 이해하는 것이 얼마나 중요한지에 대한 실제 사례를 제시하겠습니다.

먼저 Object.assign을 사용합니다.

// Let's create a new object, that contains a child object;
const parentObject = { childObject: { hello: 'world '} };

// Let's get a reference to the child object;
const childObject = parentObject.childObject;

// Let's change the child object using Object.assign, adding a new `foo` key with `bar` value;
Object.assign(parentObject.childObject, { foo: 'bar' });

// childObject is still the same object in memory, it was changed IN PLACE.
parentObject.childObject === childObject
// true

이제 확산 연산자를 사용한 동일한 연습입니다.

// Let's create a new object, that contains a child object;
const parentObject = { childObject: { hello: 'world '} };

// Let's get a reference to the child object;
const childObject = parentObject.childObject;

// Let's change the child object using the spread operator;
parentObject.childObject = {
  ...parentObject.childObject,
  foo: 'bar',
}

// They are not the same object in memory anymore!
parentObject.childObject === childObject;
// false

있는지 알 수 있습니다.parentObject.childObject = {...} 해서 '어울리지 않다'의하고 있습니다.childObject를 누르다parentObject새로운 물건의 문자 그대로를 표현하고, 오래된 물건에 의해 구성되고 있다는 사실.childObject콘텐츠는 무관합니다.로운운물물물물물

그리고 이것이 실제와 무관하다고 가정한다면, 이것을 이해하는 것이 얼마나 중요한지에 대한 실제적인 시나리오를 보여 드리겠습니다.

매우 큰 Vue.js 어플리케이션에서는 입력 필드에 고객 이름을 입력할 때 매우 느리다는 것을 알게 되었습니다.

디버깅을 실시한 , 그에 입력된 각 홀을 알 수 있었습니다.computed재검출할 속성.

이러한 컴퓨터 기능에서는 고객의 이름이 전혀 사용되지 않았기 때문에 이것은 예상하지 못했던 것입니다.다른 고객 데이터(예: 연령, 성별)만 사용되었습니다.무슨 일 있었어?고객의 이름이 변경되었을 때 vue는 왜 모든 계산된 함수를 재평가했습니까?

Vuex 스토어에서 이 기능을 제공하고 있습니다.

mutations: {
  setCustomer(state, payload) {
    // payload being { name: 'Bob' }
    state.customer = { ...state.customer, ...payload };
  }

그리고 우리의 계산은 다음과 같습니다.

veryExpensiveComputed() {
   const customerAge = this.$store.state.customer.age;
}

자, 이제 그만!고객 이름이 변경되었을 때 Vuex 변환은 실제로 완전히 새로운 객체로 변경되고 있었습니다.계산된 객체가 고객의 연령을 취득하기 위해 해당 객체에 의존했기 때문에 Vue는 매우 구체적인 객체 인스턴스를 의존관계로 간주하여 새로운 객체로 변경되었을 때(실패한 경우===오브젝트 동등성 테스트) Vue는 계산 함수를 재실행할 때라고 판단했습니다.

해결 방법?Object.assign을 사용하여 이전 개체를 폐기하지 않고 그대로 변경합니다.

mutations: {
  setCustomer(state, payload) {
    // payload being same as above: { name: 'Bob' }
    Object.assign(state.customer, payload);
  }

BTW, Vue2에 있는 경우 Object.assign을 사용하면 안 됩니다.Vue 2는 이러한 오브젝트 변경을 직접 추적할 수 없지만 Vue를 사용하는 경우에만 동일한 논리가 적용됩니다.Object.assign 대신 설정:

mutations: {
  setCustomer(state, payload) {
    Object.keys(payload).forEach(key => {
      Vue.set(state.customer, key, payload[key])
    })
  }

오브젝트 확산 연산자(...)는 아직 ES 사양의 일부가 아니라 제안서이기 때문에 브라우저에서 작동하지 않습니다.유일한 옵션은 Babel(또는 유사한 것)로 컴파일하는 것입니다.

보시는 것처럼 Object.assign({}) 위에 구문설탕이 있을 뿐입니다.

제가 볼 때, 이것들이 중요한 차이점입니다.

  • Object.assign은 대부분의 브라우저에서 기능합니다(컴파일하지 않음).
  • ... 않다.
  • ...를 실수로 하지 않도록 합니다.
  • ... Object in it 。Object.assign polyfill입니다.
  • ... 필요한

다른 답변은 오래되어 좋은 답변을 얻을 수 없습니다.
다음 예는 오브젝트 리터럴에 대한 것으로, 양쪽이 서로 보완할 수 있는 방법과 서로 보완할 수 없는 방법(따라서 차이점)에 대해 설명합니다.

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_syntaxhttpsdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/

Object.assign대상 객체가 상수이고 동시에 여러 속성을 설정할 때 필요합니다.

예를 들어 다음과 같습니다.

const target = { data: "Test", loading: true }

다음으로 소스로부터의 모든 속성을 가진 타깃을 변환해야 한다고 가정합니다.

const source = { data: null, loading: false, ...etc }

Object.assign(target, source) // Now target is updated
target = { ...target, ...source) // Error: cant assign to constant

하고 있기 하면 obj를 사용하십시오.Object.assign하기 위해빈 타겟 합니다.

이는 ES6의 일부이므로 표준화되었으며 MDN에서도 문서화되어 있습니다.https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator

이것은 매우 사용하기 편리하고 오브젝트 파괴와 함께 매우 의미가 있습니다.

위에 나열된 유일한 장점은 Object.assign()의 동적 기능입니다.그러나 이것은 리터럴 오브젝트 내에서 어레이를 펼치는 것만큼이나 간단합니다.컴파일된 babel 출력에서는 Object.assign()에서 설명된 내용을 그대로 사용합니다.

따라서 현재 표준화되고 널리 사용되고 있으며(react, redux 등 참조), 사용하기 쉽고 Object.assign()의 모든 기능을 갖추고 있기 때문에 개체 확산을 사용하는 것이 정답입니다.

(1) 객체의 얕은 복사본을 만들고 (2) 여러 객체를 하나의 객체로 병합하는 방법은 2014년부터 2018년까지 크게 발전했습니다.

아래에 개략적으로 설명한 접근법이 사용 가능하게 되었고 다양한 시기에 널리 사용되게 되었다.이 답변은 몇 가지 역사적 관점을 제공하며, 포괄적이지 않습니다.

  • 구문의 ""를 할 수 .for-in프프등등등등다다

    var mergedOptions = {}
    for (var key in defaultOptions) {
      mergedOptions[key] = defaultOptions[key]
    }
    for (var key in options) {
      mergedOptions[key] = options[key]
    }
    
    options = mergedOptions
    

2006

  • jQuery 1.0에는 다음이 있습니다.

    options = $.extend({}, defaultOptions, options)
    

2010

2014

2015

  • Object.assign는 Chrome(45), Firefox(34) 및 Node.js(4)에서 지원됩니다.오래된 런타임에는 폴리필이 필요합니다.

    options = Object.assign({}, defaultOptions, options)
    
  • 오브젝트 레스트/스프레드 프로퍼티 제안이 2단계에 도달합니다.

2016

  • 오브젝트 레스트/스프레드 속성 구문은 ES2016에 포함되지 않았지만 제안서는 3단계에 도달합니다.

2017

  • 개체 휴지/확산 속성 구문은 ES2017에 포함되지 않았지만 Chrome(60), Firefox(55) 및 Node.js(8.3)에서 사용할 수 있습니다.그러나 오래된 런타임에 대해서는 약간의 전사가 필요합니다.

    options = { ...defaultOptions, ...options }
    

2018

  • Object Rest/Spread Properties 제안은 4단계에 도달하고 구문은 ES2018 표준에 포함되어 있습니다.

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

확산 연산자는 배열을 함수의 개별 인수로 분산합니다.

let iterableObjB = [1,2,3,4]
function (...iterableObjB)  //turned into
function (1,2,3,4)

identity라는 함수를 만듭니다.이 함수는 어떤 파라미터를 지정해도 반환됩니다.

identity = (arg) => arg

심플한 어레이.

arr = [1, 2, 3]

아이덴티티에 전화를 걸면 무슨 일이 일어날지 알 수 있어요

언급URL : https://stackoverflow.com/questions/32925460/object-spread-vs-object-assign

반응형