2015-12-21 4 views
4

Функция прокси-сервера Javascript предлагает некоторые интересные функции для отладки. Например, вы можете «защитить» объект, поставив его за прокси с обработчиком get, который выдает, если вы получаете доступ к неопределенному свойству. Это помогает улавливать опечатки и другие ошибки.Равенство между прокси и целевым объектом

Это может быть использовано что-то вроде этого:

class Something { 
    constructor() 
    { 
     this.foo = "bar"; 

     allObjects.push(this); 
    } 
}; 

function defend(o) 
{ 
    return new Proxy(o, DebugCheckHandler); 
}; 

let rawSomething = new Something(); 
let defendedSomething = defend(rawSomething); 

Код может быть тщательно записаны только сделки с точки зрения defendedSomething. Однако в этом примере конструктор Something передает this где-то в другом месте (до allObjects). Это заканчивается тем же эффектом, что и использование rawSomething и defendedSomething через кодовую базу.

Проблемы возникают из-за того, что ссылка прокси не равна ее исходной ссылке, начиная с rawSomething !== defendedSomething. Например, allObjects.includes(defendedSomething) вернет false, если он содержит rawSomething, потому что includes выполняет строгую проверку ===.

Есть ли хороший способ решить эту проблему без внесения слишком большого количества изменений в код?

ответ

-1

Вместо того, чтобы позволить вызов new оператора [[Construct]], которая производит настоящий экземпляр, вы можете:

  1. Создайте объект, который наследует от prototype конструктора.
  2. Используйте его как обработчик прокси.
  3. Вызовите конструктора, передающего прокси-сервер, как значение this.
function Something() { 
    this.foo = "bar"; 
    allObjects.push(this); 
} 
function defendIntanceOf(C) { 
    var p = new Proxy(Object.create(C.prototype), DebugCheckHandler); 
    C.call(p); 
    return p; 
}; 
let defendedSomething = defendIntanceOf(Something); 

Примечание Я использовал синтаксис функции вместо класса один для того, чтобы иметь возможность использовать Function.call для вызова [[Call]] с помощью пользовательского this значения.

+0

Одна проблемы состоит в том, если 'DebugCheckHandler' бросает на установление несуществующих свойств, он будет бросать, как конструктор добавляет свойство объекта. – AshleysBrain

+0

@AshleysBrain Тогда заставьте его не бросить? Или, может быть, 'var p = new Proxy (новый C(), DebugCheckHandler)', если вы не против нажатия на ненужный объект для 'allObjects'. Или 'var p = new Proxy (Object.assign (Object.create (C.prototype), {foo: void 0}), DebugCheckHandler)', если вы сейчас являетесь собственностью. – Oriol

+0

Я ищу решение, которое позволяет избежать отладки проверки отладки, когда-либо обнаруживающей ложные срабатывания в конструкторах, никогда не подталкивает бесполезный объект для allObjects и не требует полностью переписывания конструкторов или иным образом использует значительно другой стиль. – AshleysBrain

0

Iirc, единственный способ влиять на значение в конструкторе - вот что вам нужно здесь - через подклассирование. Я верю (но не могу проверить), что должно работать:

function Defended() { 
    return new Proxy(this, DebugCheckHandler); 
//     ^^^^ will become the subclass instance 
} 

class Something extends Defended { 
//    ^^^^^^^^^^^^^^^^ these… 
    constructor() { 
     super(); 
//  ^^^^^^^ …should be the only changes necessary 
//  and `this` is now a Proxy exotic object 
     this.foo = "bar"; 

     allObjects.push(this); 
    } 
}; 

let defendedSomething = new Something(); 
+0

Я думаю, проблема в том, что не все экземпляры 'Something' должны быть защищены. – Oriol

+1

Hm, в этом случае вам нужно передать логический параметр из конструктора 'Something' вверх до' Defended' и сделать его как 'function Defendable (protect) {if (protect) вернуть новый Proxy ...; } ' – Bergi

+1

Нет, реальная проблема заключается в том, что DebugCheckHandler бросает на добавление несуществующих свойств (что я хочу), тогда конструктор класса Something будет бросать при добавлении свойства« foo ». – AshleysBrain