Доступ к получателю / установщику по умолчанию для объекта JavaScript

Получатели и установщики JavaScript могут быть переопределены для определенных свойств с помощью Object.defineProperty, Есть ли какой-нибудь способ получить доступ к получателю / установщику по умолчанию (т.е. к функции, используемой, если получатель / установщик не был перезаписан)? В моем пользовательском сеттере я хочу иметь специальную обработку в некоторых случаях, но использую обработку по умолчанию в других. Я старался:

Object.defineProperty(obj, 'foo',
  'set': function(val) {
    if (useCustom) {
      doCustomProcessing(obj, 'foo', val);
    }
    else {
      obj['foo'] = val;
    }
  }
);

К сожалению, это приводит к переполнению стека, так как obj['foo'] = val; вызывает пользовательский установщик для вызова. Поэтому я хотел бы найти способ установить foo собственностью obj используя установщик по умолчанию. Это возможно?

5 ответов

Решение

Насколько я знаю, свойство либо имеет значение (свойство data), либо имеет getter/setter (свойство accessor): оно не может иметь обоих. Используйте локальную переменную при закрытии или другое свойство в качестве основного хранилища для свойств, для которых вы определили метод получения / установки.

Например,

(function() {
    var value;
    Object.defineProperty(obj, 'foo', {
      set: function(val) {
        if (useCustom) {
          value = doCustomProcessing(obj, 'foo', val);
        } else {
          value = val;
        }
      },
      get: function() { return value; }
    });
})();

В ES6 вы можете использовать объект Proxy:

var myObject = {};

var myProxyObject = new Proxy(myObject, {
  set: function(ob, prop, value) {
    if (prop === 'counter' && value === 10) {
      // Some specialised behaviour
      ob.counter = 0;
    }
    else {
      // Default setter behaviour.
      ob[prop] = value;
    }
    // Return true otherwise you will get a TypeError in strict mode.
    return true;
  }
});

>>> myProxyObject.counter = 5;
>>> console.log(myProxyObject.counter);
5

>>> myProxyObject.counter = 10;
>>> console.log(myProxyObject.counter);
0

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

(function testInheritance(global, doc) {
  "use strict";
  var MyFunc = Object.create({}, {
      _foo: {
        value: "Some Default Value",
        writable: true,
        enumerable: true
      },
      foo: {
        get: function() {
          return this._foo;
        },
        set: function(value) {
          this._foo = value;
        }
      }
    }),
    testFunc = Object.create(MyFunc);
  console.log(testFunc.foo); // "Some default value"
  testFunc.foo = "boo";
  console.log(testFunc.foo); // "boo";
 testFunc._foo = "Not a private variable anymore";
 console.log(testFunc.foo); // "Not a private variable anymore"
}(window, document));

(function testInheritanceTwo(global, doc) {
  "use strict";
  var MyFunc = Object.create({}, {
      foo: {
        get: function() {
          if (!this._foo) {
             return "Some default value set by the getter.";
          }
          return this._foo;
        },
        set: function(value) {
          this._foo = value;
        }
      }
    }),
    testFunc = Object.create(MyFunc);
  console.log(testFunc.foo); // "Some default value set by the getter."
  testFunc.foo = "Whomp";
  console.log(testFunc.foo); // "Whomp";
 testFunc._foo = "Not a private variable anymore, unfortunately.";
 console.log(testFunc.foo); // "Not a private variable anymore"
}(window, document));

Насколько я могу сказать:

  1. Вы не можете ссылаться на значение с тем же именем, что и то, что вы используете в set: function(value), или вы в конечном итоге получаете бесконечный цикл, в котором установка значения вызывает заданное значение и вызывает его снова, и так далее. Отсюда твоя проблема.

  2. Если вы попытаетесь сделать переменную _foo приватной, то установщик не будет работать. С этим синтаксисом кажется, что вы можете скрыть переменную, но вы не можете сделать ее приватной.

Я полагаю, вы пытаетесь найти механизм наследования для методов получения и установки...

var useCustom;
var obj1 = {
   set foo(val){
     console.log(val + " : foo : obj1");
   }
};

var obj2 = {
   set foo(val){
     if (useCustom) {
      console.log(val + " : foo : obj2");
    }
    else {
      Object.getPrototypeOf(obj2).foo = val;
    }
   }
};

Object.setPrototypeOf(obj2,obj1);

useCustom = true;
obj2.foo = "test1";  //test1 : foo : obj2
useCustom = false;
obj2.foo = "test2";  // test2 : foo : obj1

Вы можете сделать что-то вроде:

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