Есть ли эквивалент свойства __noSuchMethod__ для свойств или способ реализовать его в JS? - PullRequest
40 голосов
/ 15 февраля 2010

В некоторых реализациях javascript (Rhino, SpiderMonkey)

имеется функция noSuchMethod .
proxy = {
    __noSuchMethod__: function(methodName, args){
        return "The " + methodName + " method isn't implemented yet. HINT: I accept cash and beer bribes" ;
    },

    realMethod: function(){
     return "implemented" ;   
    }
}

js> proxy.realMethod()
implemented
js> proxy.newIPod()
The newIPod method isn't implemented yet. HINT: I accept cash and beer bribes
js>

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

Ответы [ 4 ]

62 голосов
/ 21 сентября 2010

В настоящее время существует только одна вещь, которая может делать то, что вы хотите, но, к сожалению, не получила широкого распространения:

На данный момент доступно только две рабочие реализации, в последних бета-версиях Firefox 4 (это было со времен предварительных выпусков FF3.7) и в node-proxy для серверного JavaScript - Chrome и Safari в настоящее время работают над ним -.

Это одно из ранних предложений для следующей версии ECMAScript , это API, который позволяет реализовывать виртуализированных объектов (прокси), где Вы можете назначить множество ловушек -callbacks-, которые выполняются в разных ситуациях, вы получаете полный контроль над тем, что в это время в ECMAScript 3 / 5- могут делать только хост-объекты.

Чтобы построить прокси-объект, вы должны использовать метод Proxy.create, так как вас интересуют ловушки set и get, я оставляю вам очень простой пример:

var p = Proxy.create({
  get: function(proxy, name) {        // intercepts property access
    return 'Hello, '+ name;
  },
  set: function(proxy, name, value) { // intercepts property assignments
    alert(name +'='+ value);
    return true;
  }
});

alert(p.world); // alerts 'Hello, world'
p.foo = 'bar';  // alerts foo=bar

Попробуйте здесь .

Proxy API настолько нов, что даже не документирован в Mozilla Developer Center, но, как я уже сказал, со времени предварительных выпусков Firefox 3.7 была включена рабочая реализация.

Объект Proxy доступен в глобальной области видимости, а метод create может принимать два аргумента: объект handler, который представляет собой просто объект, содержащий свойства, названные ловушками, которые вы хотите реализовать, и необязательный аргумент proto, позволяющий указать объект, от которого наследуется ваш прокси.

Доступны ловушки:

// TrapName(args)                          Triggered by
// Fundamental traps
getOwnPropertyDescriptor(name):           // Object.getOwnPropertyDescriptor(proxy, name)
getPropertyDescriptor(name):              // Object.getPropertyDescriptor(proxy, name) [currently inexistent in ES5]
defineProperty(name, propertyDescriptor): // Object.defineProperty(proxy,name,pd)
getOwnPropertyNames():                    // Object.getOwnPropertyNames(proxy) 
getPropertyNames():                       // Object.getPropertyNames(proxy) 
delete(name):                             // delete proxy.name
enumerate():                              // for (name in proxy)
fix():                                    // Object.{freeze|seal|preventExtensions}(proxy)

// Derived traps
has(name):                                // name in proxy
hasOwn(name):                             // ({}).hasOwnProperty.call(proxy, name)
get(receiver, name):                      // receiver.name
set(receiver, name, val):                 // receiver.name = val
keys():                                   // Object.keys(proxy)

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

Редактировать: Появляется дополнительная информация, Брендан Айх недавно выступил с докладом на конференции JSConf.eu , его слайды можно найти здесь:

6 голосов
/ 10 марта 2016

Вот как можно получить поведение, подобное __noSuchMethod __

Прежде всего, вот простой объект с одним методом:

var myObject = {
    existingMethod: function (param) {
        console.log('existing method was called', param);
    }
}

Теперь создайте Proxy, который будет отлавливать доступ к свойствам / методам, и добавьте существующий объект в качестве первого параметра.

var myObjectProxy = new Proxy(myObject, {
   get: function (func, name) {
       // if property or method exists, return it
       if( name in myObject ) {
           return myObject[name];
       }
       // if it doesn't exists handle non-existing name however you choose
       return function (args) {
           console.log(name, args);
       }
    }
});

Теперь попробуйте:

myObjectProxy.existingMethod('was called here');
myObjectProxy.nonExistingMethod('with a parameter');

Работает в Chrome / Firefox / Opera. Не работает в IE (но уже работает в Edge). Также тестируется на мобильном Chrome.

Создание прокси может быть автоматизировано и невидимо, т. Е. Если вы используете шаблон Factory для создания ваших объектов. Я сделал это для создания рабочих, внутренние функции которых можно вызывать непосредственно из основного потока. Использование рабочих теперь стало таким простым благодаря этой замечательной новой функции под названием Proxy. Самая простая рабочая реализация:

var testWorker = createWorker('pathTo/testWorker.js');
testWorker.aFunctionInsideWorker(params, function (result) {
    console.log('results from worker: ', result);
});
3 голосов
/ 24 сентября 2010

Я не верю, что этот тип метапрограммирования возможен (пока) в javascript. Вместо этого попробуйте использовать функциональность __noSuchMethod__, чтобы добиться эффекта с помощью методов получения свойств. Не кросс-браузерный, так как это расширение Mozilla .

var proxy = {
    __noSuchMethod__: function(methodName, args) {
       if(methodName.substr(0,3)=="get") {
          var property = methodName.substr(3).toLowerCase();                             
          if (property in this) {
              return this[property];
          }
       }
    }, color: "red"
 };
 alert(proxy.getColor());           
0 голосов
/ 06 июля 2011

В SpiderMonkey есть __defineGetter__, __defineSetter__, __lookupGetter__ и __lookupSetter__ в дополнение к __noSuchMethod__.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...