Плохой вариант использования Object.assign() - Простой пример

Я читаю документы MDN на Object.assign() и наткнулся на одну фразу, которую я не понимаю:

Метод Object.assign() копирует только перечисляемые и собственные свойства из исходного объекта в целевой объект. Он использует [[Get]] для источника и [[Set]] для цели, поэтому он будет вызывать методы получения и установки. Поэтому он присваивает свойства вместо простого копирования или определения новых свойств. Это может сделать его непригодным для слияния новых свойств в прототип, если источники слияния содержат геттеры. Для копирования определений свойств, включая их перечислимость, в прототипы следует использовать Object.getOwnPropertyDescriptor() и Object.defineProperty().

Особенно эта строка:

Это может сделать его непригодным для слияния новых свойств в прототип, если источники слияния содержат геттеры.

Я не совсем уверен, что хороший пример для защиты от использования Object.assign,

1 ответ

Решение

Получатель - это функция доступа к свойству, которая возвращает значение свойства. Вот как выглядит объект с геттером:

var obj = {
    get example() {
        console.log("getter was called");
        return Math.floor(Math.random() * 100);
    }
};
console.log(obj.example);
// Note no () ---------^

Обратите внимание, что когда мы читаем значение example свойство, функция запускается, даже если она не похожа на вызов функции.

То, что эта часть документов MDN говорит, что Object.assign вызовет этот метод получения, он не создаст эквивалентный метод получения для целевого объекта. Так:

var obj = {
    get example() {
        console.log("getter was called");
        return Math.floor(Math.random() * 100);
    }
};
var obj2 = Object.assign({}, obj); // calls getter
console.log(obj2.example);         // just has a simple value
console.log(obj2.example);         // same value, no call
console.log(obj2.example);         // same value, no call

obj "s example у собственности есть добытчик, но obj2 "s example Свойство - это просто свойство простого значения. Object.assign не скопировал получатель, он просто взял текущее значение получателя и присвоил ему obj2.example,

Вы можете копировать геттеры, но не с Object.assign:

function copyProperties(target, source) {
    Object.getOwnPropertyNames(source).forEach(name => {
        Object.defineProperty(
            target,
            name,
            Object.getOwnPropertyDescriptor(source, name)
        );
    });
    return target;
}
var obj = {
    get example() {
        console.log("getter was called");
        return Math.floor(Math.random() * 100);
    }
};
var obj2 = copyProperties({}, obj); // calls getter
console.log(obj2.example);          // calls getter
console.log(obj2.example);          // calls getter
console.log(obj2.example);          // calls getter

Конечно, если геттер не предназначен для копирования между объектами (например, если example получатель явно используется obj), вы можете получить неожиданные результаты.

Другие вопросы по тегам