Почему объект Proxy отражает изменения за пределами целевого объекта? - PullRequest
6 голосов
/ 26 сентября 2019

Я хотел немного поэкспериментировать с прокси-объектом и получил несколько неожиданных результатов:

Тестовый скрипт

function Person(first, last, age) {
  this.first = first;
  this.last = last;
  this.age = age;
}

Person.prototype.greeting = function () {
  return `Hello my name is ${this.first} and I am ${this.age} years old`;
};

Так что в отслеживании какобъект prototype изменяется, я добавил эту обертку:

let validator = {
    set: function(target, key, value) {
        console.log(`The property ${key} has been updated with ${value}`);
        target[key] = value;
        return true;
    }
};

Person.prototype = new Proxy(Person.prototype, validator);

let george = new Person('George', 'Clooney', 55);

Person.prototype.farewell = function () {
  return `Hello my name is ${this.first} and I will see you later`;
};

То, что я ожидал

The property: "farewell" has been updated with: "function () {
  return `Hello my name is ${this.first} and I will see you later`;
}"

и ничего больше.

И изКонечно, каждый раз, когда я добавлял или удалял что-то из prototype, то есть Person.prototype или instance.constructor.prototype, я ожидал увидеть сообщение console.log().

Однако я не ожидал увидеть что-либо при установке чего-либо в экземпляре, например:

george.someProp = 'another value'; // did NOT expect to see the console.log()


Выход

The property: "first" has been updated with: "george"
The property: "last" has been updated with: "clooney"
The property: "age" has been updated with: "55"
The property: "farewell" has been updated with: "function () {
  return `Hello my name is ${this.first} and I will see you later`;
}"
Person.prototype
Proxy {greeting: ƒ, first: "George", last: "Clooney", age: 55, farewell: ƒ, constructor: ƒ}

Он устанавливает все свойства на prototype и ничего на экземпляре, и каждый раз, когда я устанавливаю что-то на instance, он устанавливает его прямо на prototype.

Очевидно, что это поведение не по умолчанию, как если бы я удалил это Proxy, каждое свойство, установленное с this, будет установлено на самом экземпляре, и prototype начнется пустым (или в нашем случае с простоgreeting функция).

Что мне здесь не хватает?Точка в правильном направлении приветствуется.

1 Ответ

5 голосов
/ 26 сентября 2019

Что вам не хватает, так это тот факт, что когда у вас есть объект Proxy в цепочке прототипов, при изменении дочернего объекта будет вызываться обработчик набора.

В вашем примере, когда вы устанавливаете свойствона новом экземпляре будет выполнена заданная ловушка, target будет обернутым объектом Person.prototype, но у есть четвертый аргумент, receiver.Этот аргумент указывает на объект, к которому было обращено свойство.

Чтобы правильно выполнить присвоение свойства, вы можете использовать Reflect.set API для его установки:

Reflect.set(target, key, value, receiver);

Вот почемуAPI Reflect соответствует аргументам ловушек прокси.

Итак, в вашем примере мы могли бы использовать API Reflect, и вы увидите, что Person.prototype не "загрязнен".

function Person(first, last, age) {
  this.first = first;
  this.last = last;
  this.age = age;
}

Person.prototype.greeting = function () {
  return `Hello my name is ${this.first} and I am ${this.age} years old`;
};


const validator = {
    set: function(target, key, value, receiver) {
        console.log(`The property ${key} has been updated with ${value}`);
        Reflect.set(target, key, value, receiver)
        return true;
    }
};

Person.prototype = new Proxy(Person.prototype, validator);

const george = new Person('George', 'Clooney', 55);

Person.prototype.farewell = function () {
  return `Hello my name is ${this.first} and I will see you later`;
};

console.log(george.hasOwnProperty('first')); // true
console.log(Person.prototype.hasOwnProperty('first')); // false
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...