一尘不染

是否有与__noSuchMethod__功能等效的属性,或者是在JS中实现该功能的方法?

javascript

在某些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>

我想知道,是否有一种方法可以对物业进行类似的处理?我想编写可以在属性和方法上分派的代理类。


阅读 290

收藏
2020-04-25

共1个答案

一尘不染

更新: ECMAScript6代理现在已得到广泛支持。基本上,如果您不需要支持IE11,则可以使用它们。

代理对象使您可以定义基本操作的自定义行为,例如属性查找,赋值,枚举,函数调用等。

用ES6代理模拟__noSuchMethod__

通过在属性访问上实现陷阱,您可以模拟非标准__noSuchMethod__陷阱的行为:

function enableNoSuchMethod(obj) {

  return new Proxy(obj, {

    get(target, p) {

      if (p in target) {

        return target[p];

      } else if (typeof target.__noSuchMethod__ == "function") {

        return function(...args) {

          return target.__noSuchMethod__.call(target, p, args);

        };

      }

    }

  });

}



// Example usage:



function Dummy() {

  this.ownProp1 = "value1";

  return enableNoSuchMethod(this);

}



Dummy.prototype.test = function() {

  console.log("Test called");

};



Dummy.prototype.__noSuchMethod__ = function(name, args) {

  console.log(`No such method ${name} called with ${args}`);

  return;

};



var instance = new Dummy();

console.log(instance.ownProp1);

instance.test();

instance.someName(1, 2);

instance.xyz(3, 4);

instance.doesNotExist("a", "b");

原始答案

目前只有一件事可以实际完成您想要的事情,但是不幸的是,它并未得到广泛实施:

  • ECMAScript和声代理。

目前只有 两种有效的 实现方式,在最新的Firefox4beta(自FF3.7预发行版开始出现)和用于服务器端JavaScript的节点代理中,Chrome和Safari当前正在使用该实现,

这是一个早期的提案为[ECMAScript中的下一个版本,它是一个API,可让您实现虚拟化的对象(代理),您可分配各种陷阱-callbacks-了在不同情况下执行的,你得到完全控制目前,ECMAScript
3/5中只有主机对象可以执行此操作。

要构建代理对象,您必须使用Proxy.create方法,因为您对setand 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

在这里尝试。

编辑: 代理API不断发展,Proxy.create为了使用Proxy构造函数而删除了该方法,请参见以上更新为ES6的代码:

const obj = {};

const p = new Proxy(obj, {

  get(target, prop) {        // intercepts property access

    return 'Hello, '+ prop;

  },

  set(target, prop, value, receiver) { // intercepts property assignments

    console.log(prop +'='+ value);

    Reflect.set(target, prop, value, receiver)

    return true;

  }

});



console.log(p.world);

p.foo = 'bar';

Proxy API太新了,甚至没有在Mozilla开发人员中心上进行记录,但是正如我所说,自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)
2020-04-25