Оригинальная ссылкаона и компания barbarian.com/object-arthas…
в 2018 годуObject Rest/Spread ProposalДостигstage 4, что означает, что в будущем он будет включен в стандарт ECMAScript. Он также был добавлен в Node LTS. Вы можете использовать его, начиная с Node.js 8, так что вы можете начать использовать его с уверенностью.
Object Spread также можно назвать распределителем объектов, который описан ниже с помощью Object Spread.
$ node -v
v8.9.4
$ node
> const obj = { foo: 1, bar: 1 };
undefined
> ({ ...obj, baz: 1 });
{ foo: 1, bar: 1, baz: 1 }
Object Spread и Object.assign функционально схожи. Какой из них вы должны использовать? Как оказалось, ответ гораздо сложнее, чем вы думаете.
Введение в распространение объектов
Основная идея оператора Object Spread заключается в использовании собственных свойств существующего объекта для создания нового простого объекта. так{...obj}создать иobjобъекты с одинаковыми свойствами. дляОбычные старые объекты JavaScript, вы на самом деле создаетеobjкопировать.
const obj = { foo: 'bar' };
const clone = { ...obj }; // `{ foo: 'bar' }`
obj.foo = 'baz';
clone.foo; // 'bar'
Как и object .assign(), оператор распространения объекта не копирует унаследованные свойства или свойства класса. Но он будет копировать ES6symbolsАтрибуты.
class BaseClass {
foo() { return 1; }
}
class MyClass extends BaseClass {
bar() { return 2; }
}
const obj = new MyClass();
obj.baz = function() { return 3; };
obj[Symbol.for('test')] = 4;
// Does _not_ copy any properties from `MyClass` or `BaseClass`
const clone = { ...obj };
console.log(clone); // { baz: [Function], [Symbol(test)]: 4 }
console.log(clone.constructor.name); // Object
console.log(clone instanceof MyClass); // false
Другие свойства также можно смешивать с помощью оператора распространения объекта.
Проблемы с порядком: оператор распространения объекта перезапишет свойства, определенные до него.
const obj = { a: 'a', b: 'b', c: 'c' };
{ a: 1, b: null, c: void 0, ...obj }; // { a: 'a', b: 'b', c: 'c' }
{ a: 1, b: null, ...obj, c: void 0 }; // { a: 'a', b: 'b', c: undefined }
{ a: 1, ...obj, b: null, c: void 0 }; // { a: 'a', b: null, c: undefined }
{ ...obj, a: 1, b: null, c: void 0 }; // { a: 1, b: null, c: undefined }
Отличие от Object.assign()
Для приведенного выше примераObject.assign()Функции в основном взаимозаменяемы с оператором распространения объекта. Фактически,object spread specконкретно определенный{... obj}ЭквивалентноObject.assign({},obj).
const obj = { a: 'a', b: 'b', c: 'c' };
Object.assign({ a: 1, b: null, c: void 0 }, obj); // { a: 'a', b: 'b', c: 'c' }
Object.assign({ a: 1, b: null }, obj, { c: void 0 }); // { a: 'a', b: 'b', c: undefined }
Object.assign({ a: 1 }, obj, { b: null, c: void 0 }); // { a: 'a', b: null, c: undefined }
Object.assign({}, obj, { a: 1, b: null, c: void 0 }); // { a: 1, b: null, c: undefined }
Так почему бы вам использовать тот или иной? Ключевое отличие состоит в том, что оператор распространения объекта всегда дает вам POJO (обычный объект JavaScript). а такжеObject.assign()Функция изменяет свой первый переданный объектobj:
class MyClass {
set val(v) {
console.log('Setter called', v);
return v;
}
}
const obj = new MyClass();
Object.assign(obj, { val: 42 }); // Prints "Setter called 42"
другими словами,Object.assign()Объект изменен, поэтому он может запускатьES6 setter. Если вы предпочитаете использоватьimmutableметод, то вам лучше подойдет оператор распространения объекта. использоватьObject.assign(), вы должны убедиться, что пустой объект всегда{}Передается как первый параметр.
2019.02.12 Дополнительное примечание: когда Object использует Object.defineProperty для изменения метода set, поскольку вызов Object.assign вызовет метод setter, который вызовет непредвиденные ошибки.
Как производительность? Вот несколько простых тестов. Если вы передаете пустой объект в качестве первого аргументаObject.assign(), похоже, что распространение объектов будет быстрее, но в остальном они взаимозаменяемы.
Ниже приведено использованиеObject.assign()и эталон для назначения на месте:
const Benchmark = require('benchmark');
const suite = new Benchmark.Suite;
const obj = { foo: 1, bar: 2 };
suite.
add('Object spread', function() {
({ baz: 3, ...obj });
}).
add('Object.assign()', function() {
Object.assign({ baz: 3 }, obj);
}).
on('cycle', function(event) {
console.log(String(event.target));
}).
on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').map('name'));
}).
run({ 'async': true });
В этом случае они аналогичны:
Object spread x 3,170,111 ops/sec +-1.50% (90 runs sampled)
Object.assign() x 3,290,165 ops/sec +-1.86% (88 runs sampled)
Fastest is Object.assign()
Однако однажды кObject.assign()Введите пустой параметр объекта, и оператор распространения объекта будет работать быстрее
suite.
add('Object spread', function() {
({ baz: 3, ...obj });
}).
add('Object.assign()', function() {
Object.assign({}, obj, { baz: 3 });
})
Вот результат:
Object spread x 3,065,831 ops/sec +-2.12% (85 runs sampled)
Object.assign() x 2,461,926 ops/sec +-1.52% (88 runs sampled)
Fastest is Object spread
Конфигурация ESLint
По умолчанию ESLint находится на уровне разбораОператоры rest/spread объекта запрещеныВам нужно установить параметр parserOptions.ecmaVersion в .eslintrc.yml как минимум на 9, иначе вы получите ошибку синтаксического анализа.
parserOptions:
# Otherwise object spread causes 'Parsing error: Unexpected token ..'
ecmaVersion: 9
ESLint добавляетновые правилаPrefer-object-spread, что заставляет вас использовать оператор Object Spread вместоObject.assign(). Чтобы включить это правило, используйте:
parserOptions:
ecmaVersion: 9
rules:
prefer-object-spread: error
Теперь, если вы используетеobject .assign()Вместо распространения объекта ESLint сообщит об ошибке.
Use an object spread instead of `Object.assign` eg: `{ ...foo }` prefer-object-spread
наконец
Операторы rest/spread объекта синтаксически более лаконичны иObject.assign()Обеспечивает преимущество в производительности. Если вы используете Node.js 8 или более позднюю версию, попробуйте эти новые операторы для более чистого кода.