Как создать прокси-геттер для всех экземпляров класса в javascript?

#javascript #getter-setter #es6-class #es6-proxy

#javascript #getter-сеттер #es6-класс #es6-прокси

Вопрос:

Прокси можно использовать для определения «общих геттеров» для объектов. Например

 var obj = {'a':3, 'b':4 };
var proxy = new Proxy( obj, {
    get: function(obj, prop){return obj[prop] 10} 
} );
proxy.a //13
 

У меня есть векторный класс, который расширяет Array :

 class vec extends Array{
   constructor(...a){
      super(...a)    
   }
   get x(){
      return this[0];
   }
   /* some more functions */
}
 

и я хочу, чтобы индекс обтекался, как в python. Например, if v — это вектор, который я хочу v[-1] вернуть последним элементом v . Для этого мне нужно было бы обернуть прокси вокруг каждого экземпляра vector (я думаю), чтобы я мог ограничить индекс. Но я не знаю, как создать прокси для всех экземпляров, я знаю только, как это работает для одного объекта. Итак, как бы вы это сделали?

Комментарии:

1. Допустимо возвращать объект из функции-конструктора, или вы можете использовать фабричную функцию.

Ответ №1:

Вы могли бы создать свой класс так, чтобы он возвращал экземпляр прокси, и на этом прокси вы создаете метод get, в который добавляете свою пользовательскую логику.

 class Vec extends Array {
  constructor(...a) {
    super(...a)

    return new Proxy(this, {
      get: function(target, prop, receiver) {
        const n =  prop;

        if (!isNaN(n) amp;amp; n < 0) {
          return [...target].slice(n)
        }

        return Reflect.get(...arguments);
      }
    })
  }

  get x() {
    return this[0];
  }
}

const v = new Vec(1, 2, 3);
console.log(v[-1])
console.log(v[-2])
console.log(v.x) 

Комментарии:

1. Я не думаю [...target].slice(n) , что делает то, что хочет OP

2. Кажется, это делает то, что я хочу, и кажется, что это правильный способ сделать это .. Поведение среза не то, что (я хочу взять модуль индекса, чтобы зафиксировать его между 0… (arr.length-1) ) но это внесло бы быструю модификацию. Спасибо!

Ответ №2:

Я хочу v[-1] вернуть последний элемент v .

Кажется, у вас Vector фиксированный размер (например, 3 для .x , .y и .z ), поэтому вы могли бы просто определить другой геттер с именем -1 .

В общем, я бы рекомендовал следовать предложению относительной индексации и просто реализовать .at() метод или предложение массива .last .

Я не знаю, как создать прокси для всех экземпляров

Вы можете сделать свой прототип прокси-сервером:

 vec.prototype = new Proxy(vec.protoype, {
   get(target, prop, receiver) {
     if (typeof prop == "string" amp;amp; prop[0] == '-') {
       const i = Number(prop);
       if (Number.isInteger(i)) {
         return receiver[receiver.length   i];
       }
     }
     return Reflect.get(target, prop, receiver)
   }
});
 

Комментарии:

1. Мой класс работает как массив, поэтому он может иметь любую длину. Метод x() — это просто сокращение. Мне нравится этот ответ, но ответ Ненада немного ближе к тому, что я хочу.

2. Так ли это? Вы запросили один прокси для всех экземпляров, и это именно то, что делает мой ответ (но решение Nenad этого не делает).

3. Ну, я не был уверен, каков наилучший способ его реализации, у меня просто было смутное представление о том, чего я хотел. Теперь, когда я думаю об этом, может быть, наличие одного прокси в прототипе дает лучшую производительность? Я подумаю об этом еще немного, но сейчас ответ Ненада остается принятым.

4. Я бы надеялся, что это так, но я бы проверил его, чтобы быть уверенным. В любом случае, даже если вы создаете по одному прокси для каждого экземпляра, я бы рекомендовал передавать один и тот же объект-обработчик всем им.