Распространение объекта по сравнению с Object.assign

Предположим, у меня есть переменная options и я хочу установить значение по умолчанию.

Какова польза / недостаток этих двух альтернатив?

Использование распространения объекта

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

Или используя Object.assign

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

Это коммиссия, которая заставила меня задуматься.

Это не обязательно является исчерпывающим.

Синтаксис распространения

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

Преимущества:

  • Если авторский код для исполнения в средах без встроенной поддержки, вы можете просто скомпилировать этот синтаксис (в отличие от использования polyfill). (Например, с Вавилоном).

  • Менее подробный.

Недостатки:

  • Предложение не стандартизировано. (Подумайте, что вы будете делать, если напишете его сейчас, и он не станет стандартизованным.)

  • Литературный, а не динамический.


Object.assign()

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

Преимущества:

  • Стандартизован.

  • Динамический. Пример:

     var sources = [{a: "A"}, {b: "B"}, {c: "C"}]; options = Object.assign.apply(Object, [{}].concat(sources)); 
  • Более подробный.

Недостатки:

  • Если авторский код для выполнения в средах без встроенной поддержки вам нужно полифонировать.

Это коммиссия, которая заставила меня задуматься.

Это напрямую не связано с тем, что вы просите. Этот код не использовал Object.assign() , он использовал код пользователя ( object-assign ), который делает то же самое. Они, похоже, компилируют этот код с Babel (и связывают его с Webpack), о чем я говорил: синтаксис, который вы можете просто компилировать. Они, по-видимому, предпочли, чтобы включить object-assign в качестве зависимости, которая войдет в их сборку.

Для ссылочного объекта rest / распространение завершается в ECMAScript 2018 как этап 4. Предложение можно найти здесь .

По большей части сбрасывание и распространение объектов работают одинаково, ключевым отличием является то, что спред определяет свойства, в то время как Object.assign () устанавливает их . Это означает, что Object.assign () запускает сеттеры.

Стоит помнить, что помимо этого, объект rest / spread 1: 1 сопоставляется с Object.assign () и действует по-разному с распределением массива (итерируемого). Например, при распространении массива нулевые значения распространяются. Однако, используя значения распространения объектов, значения null молчаливо распространяются на ничего.

Пример массива (Iterable)

 const x = [1, 2, null , 3]; const y = [...x, 4, 5]; console.log(y); // [1, 2, null, 3, 4, 5]; 

Пример распространения объекта

 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} 

Оператор распространения объектов (…) не работает в браузерах, потому что он еще не является частью какой-либо спецификации ES, просто предложение. Единственный вариант – скомпилировать его с Babel (или что-то подобное).

Как вы можете видеть, это просто синтаксический сахар над Object.assign ({}).

Насколько я вижу, это важные отличия.

  • Object.assign работает в большинстве браузеров (без компиляции)
  • ... для объектов не стандартизировано
  • ... защищает вас от случайного мутирования объекта
  • ... будет полифонировать Object.assign в браузерах без него
  • ... требуется меньше кода для выражения той же идеи

Как Object.assign() другие, в этот момент написания 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 с расширенным объектом, в браузерах и в экосистеме с помощью инструментов.

спекуляция

  • https://github.com/tc39/proposal-object-rest-spread
  • Эта языковая функция – это предложение этапа 4 , что означает, что оно было объединено в спецификации языка ES, но еще не широко реализовано.

Браузеры: в Chrome, в SF, Firefox скоро (ver 60, IIUC)

  • Поддержка браузера для «распространенных свойств», поставляемых в Chrome 60 , включая этот сценарий.
  • Поддержка этого сценария НЕ работает в текущем Firefox (59), но DOES работает в моем Firefox Developer Edition. Поэтому я считаю, что он будет поставляться в Firefox 60.
  • Safari: не проверено, но Kangax говорит, что он работает в Desktop Safari 11.1, но не SF 11
  • iOS Safari: не teseted, но Kangax говорит, что он работает в iOS 11.3, но не в iOS 11
  • не в Edge

Инструменты: Узел 8.7, TS 2.1

  • Поддержка NodeJS поддерживается с 8.7 (через Kangax). Подтверждено на 9.8, когда я тестировал локально.
  • ТипScript поддерживает его с 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) и в узле (8.7+).

Зачем отвечать?

Я пишу это через 2,5 года после первоначального вопроса. Но у меня был такой же вопрос, и именно здесь меня послал Google. Я раб миссии SO для улучшения длинного хвоста.

Так как это расширение синтаксиса «массив распространения», мне было очень сложно работать с Google, и его трудно найти в таблицах совместимости. Самое близкое, что я мог найти, это «свойство распространения» Kangax , но этот тест не имеет двух спредов в одном выражении (а не в слиянии). Кроме того, имя на страницах с предложениями / черновиками / страницами браузера использует «распространение свойств», но мне кажется, что это был «первый принцип», к которому сообщество пришло после предложений использовать синтаксис распространения для «слияния объектов». (Который мог бы объяснить, почему так сложно Google.) Поэтому я документирую свое открытие здесь, чтобы другие могли просматривать, обновлять и компилировать ссылки об этой конкретной функции. Надеюсь, он поймает. Пожалуйста, помогите распространить новости о его посадке в спецификации и в браузерах.

Наконец, я бы добавил эту информацию в качестве комментария, но я не мог редактировать их, не нарушая оригинальные намерения авторов. В частности, я не могу отредактировать комментарий @ ChillyPenguin, не потеряв его намерения исправить @RichardSchulte. Но спустя годы Ричард оказался прав (на мой взгляд). Поэтому я пишу этот ответ вместо этого, надеясь, что он в конечном итоге наберет старые ответы (может потребоваться годы, но в конце концов это длинный хвостовой эффект).

ПРИМЕЧАНИЕ. Спред – это не просто синтаксический сахар вокруг объекта Object.assign. Они действуют по-разному за кулисами.

Object.assign применяет сеттеры к новому объекту, Spread does not. Кроме того, объект должен быть итерируемым.

Копировать Используйте это, если вам нужно значение объекта так, как оно есть в данный момент, и вы не хотите, чтобы это значение отражало любые изменения, сделанные другими владельцами объекта.

Используйте его для создания мелкой копии хорошей практики объекта, чтобы всегда устанавливать неизменяемые свойства для копирования – поскольку измененные версии могут передаваться в неизменяемые свойства, копия гарантирует, что вы всегда будете иметь дело с неизменяемым объектом

Назначение Assign несколько противоположно копированию. Assign генерирует сеттер, который напрямую присваивает значение переменной экземпляра, а не копирует или удерживает ее. При вызове getter свойства assign он возвращает ссылку на фактические данные.

Теперь это часть ES6, поэтому стандартизирована и также документирована на MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator

Это очень удобно использовать и имеет большой смысл наряду с деструкцией объекта.

Одно из оставшихся преимуществ, перечисленных выше, – это динамические возможности Object.assign (), однако это так же просто, как распространение массива внутри литерального объекта. В скомпилированном выводе Babel он использует точно то, что демонстрируется с Object.assign ()

Поэтому правильным ответом было бы использовать распространение объектов, поскольку оно теперь стандартизировано, широко используется (см. Реакцию, сокращение и т. Д.), Прост в использовании и имеет все функции Object.assign ()

  • es6 Карта и сложность набора, реализация v8
  • Ошибка отправителя Google Chromecast, если расширение Chromecast не установлено или использует инкогнито
  • Две компоненты, связывающие Vuejs
  • Реагировать на фокус на ввод после рендера
  • Как очистить все параметры в раскрывающемся списке?
  • Изменение флажка jQuery и событие click
  • В чем разница между «let» и «const» ECMAScript 6?
  • Почему setState в реале Async вместо Sync?
  • Как сделать setState внутри обратного вызова: ReactJS
  • Как фильтровать (ключ, значение) с помощью ng-repeat в AngularJs?
  • Как получить позицию столбца каретки (не пикселей) в текстовом поле, в символах, с самого начала?
  • Давайте будем гением компьютера.