我的代码如下:
obj.foo(); // obj might, or might not have a `foo` method.
我想知道是否可以覆盖在我的代码中调用obj.foo
时发生的情况,例如:
obj.foo = function(){ alert ("Hello"); });
obj.onCallNonExistentMethod = function(){ // I know this is imaginary syntax
alert("World");
}
obj.foo(); // alerts "Hello"
delete obj.foo;
obj.foo(); // alerts "World" , would TypeError without the method missing handler.
根据我的理解,在Ruby中method_missing
或const_missing
或类似的东西。
我可以覆盖在JavaScript中调用不存在的对象方法时发生的事情吗?如果可以,我该怎么做?
目标是验证我提供给用户的API,以便他们可以安全地使用API,我可以更明确地警告错误。
答案 0 :(得分:5)
两年前,本杰明,你不太了解行为打字的概念吗?
幸运的是,你很快就会在JavaScript中发现an interface is not structural自写这个问题,甚至wrote a library解决了你在这里提到的确切问题,但从不使用它。
所以,回答你的问题:
如果您只需要通过Proxy API支持真正(非常真实)的新浏览器,这是完全可行的。
var realObject = { foo: function(){ alert("Bar"); }); // our fooable api
var api = new Proxy({}, {
get: function(target, name){
if(name in target){ // normal API call
return target[name];
}
// return whatever you want instead of the method:
return function(){ alert("Baz"); });
}
});
api.foo(); //alerts Bar
api.bar(); //alerts Baz
api.IWillNotBuyThisRecordItIsScratched(); // alerts Baz
所以,虽然浏览器支持很简单,但
接口传达行为,在诸如拼写错误之类的情况下,可以(并且应该)通常由静态分析工具(如jshint或ternjs)捕获。
检查拼写错误的工具根本不足以传达JavaScript中的行为,类型检查被认为是反模式,通常 - 在JavaScript,Ruby和Python等语言中,您知道您将获得的类型。
答案 1 :(得分:2)
不幸的是,在任何广泛支持的方式都不可能。您可以获得的最接近的是对所有呼叫使用代理功能,即代替foo.bar()
,您将使用foo.invoke('bar')
之类的内容。然而,这非常丑陋,很可能接近你在第一个“不感兴趣”部分的意思。
在松散类型的语言中,期望开发人员通过兼容的对象是很常见的 - 即在传递意外事件时收到错误通常很好。
但是,如果你足够幸运地使用支持ECMAScript-harmony功能的JS引擎(显然IE不支持),你可以使用Proxy objects来实现这一点。基本上你将对象包装在一个代理中,它允许你在对象上捕获most operations,例如迭代它,检索属性,甚至创建属性。除了查看this answer to this question的两个链接可能值得一试。
答案 2 :(得分:1)
如果你正在使用严格定义的对象,你应该使用自定义对象而不是对象文字:
function Foo(bar, baz) {
this.bar = bar;
this.baz = baz;
}
Foo.prototype = {
fizz: function () {
alert(this.bar + ' ' + this.baz + '!');
}
};
//elsewhere
f = new Foo('Hello', 'World');
f.fizz();
然后,您可以使用Foo
运算符判断对象是否为instanceof
个实例:
function Buzz(foo) {
if (foo instanceof Foo) {
foo.fizz();
}
}
f = new Foo('Hello', 'World');
Buzz(f);
如果您只想查看对象是否包含特定参数的函数,您可以使用以下内容:
function hasFunction(obj, param) {
return (typeof obj[param] === 'function');
}
o = {
foo: function () {}
}
hasFunction(o, 'foo'); //true
hasFunction(o, 'bar'); //false
答案 3 :(得分:1)
这在今天并不是很有用(由于浏览器支持不稳定),但Proxy API将允许您编写拦截对象的属性访问的代码。换句话说,当你写:
obj.foo();
然后代理的陷阱可以返回它想要的任何内容(被调用),无论该属性是否实际存在于原始对象上。