Метод JavaScript для отмены поведения по умолчанию при деструктурировании объектов - PullRequest
2 голосов
/ 27 марта 2019

Есть ли в JS способ переопределить поведение объекта по умолчанию, когда он де-структурирован?

// Normally destructing lifts properties from an object
const foo = {
  a: 1,
  b: 2,
};

const { a, b } = foo; // a = 1, b = 2

// I would like to have a method return the properties to be
// destructured
const bar = {
  toObject: () => {
    return { a, b };
  },
};

const { a, b } = bar; // a = undefiner, b = undefined

Я знаю, что могу просто использовать const { a, b } = bar.toObject();, но это требует от потребителя объекта знать, как работает его внутреннее устройство, и нарушает принцип наименьшего удивления.

Самым близким, что я могу придумать, к тому, что я хочу, является магический метод toJSON.

Ответы [ 3 ]

3 голосов
/ 27 марта 2019

Неа.Спецификация требует с правой стороны для разрешения значения, которое может быть преобразовано в объект через ToObject, который просто возвращает сам объект, если ему передан один (т. Е. Нетвызывается специальный метод для объекта, чтобы преобразовать его во что-то еще).

enter image description here

2 голосов
/ 27 марта 2019

Вы можете заставить ваш toObject работать, как предполагалось, украсив цель прокси-сервером, который перехватывает ownKeys и get, чтобы подделать объект для деструктуризации:

let withToObject = obj => new Proxy(obj, {
    ownKeys(o) {
        return Object.keys(o.toObject())
    },
    get(o, prop) {
        return o.toObject()[prop]
    }
});

let bar = withToObject({
    aa: 11,
    bb: 22,
    cc: 33,

    toObject() {
        return {
            a: this.aa,
            b: this.bb
        };
    }
});

const {a, b} = bar;

console.log(a, b)

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

get(o, prop) {
    if (prop === 'toJSON')
        return () => o; // or o.toObject(), whatever fits better
    return o.toObject()[prop]
2 голосов
/ 27 марта 2019

Если бы вы использовали деструктуризацию массива, это сработало бы:

 const [a, b] = {
   *[Symbol.iterator]() {
     yield "some"; yield "stuff";
   }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...