2014-11-25 5 views
3

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

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

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

ответ

3

Насколько я знаю, свойство имеет либо значение (свойство данных), либо имеет свойство 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; } 
    }); 
})(); 
+1

@OP, Чтобы узнать больше о свойствах данных против свойств аксессоры см [ECMAScript 5, раздел 8.6] (HTTP: // WWW. ecma-international.org/ecma-262/5.1/#sec-8.6). – apsillers

0

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

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 
+0

Не уверен, что модификация произвольных свойств прототипа является такой хорошей идеей. В любом случае, это, конечно, не помогло бы реализовать геттер так, как я описал. –

1

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

(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. Вы не можете ссылаться на значение с тем же именем, что вы используете в наборе: функция (значение) или вы в конечном итоге с бесконечным циклом, где установка значения вызывает заданное значение, и снова называет себя , и так далее. Следовательно, ваша проблема.

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

+0

Помогли мне много, спасибо! – chris97ong

2

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

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