有没有办法捕获尝试访问不存在的属性或方法?

时间:2010-04-19 10:27:53

标签: javascript

例如这段代码:

function stuff() {
  this.onlyMethod = function () {
    return something;
  }
}

// some error is thrown
stuff().nonExistant();

有没有办法像PHP的__call那样做对象内部的后备?

function stuff() {
  this.onlyMethod = function () {
    return something;
  }
  // "catcher" function
  this.__call__ = function (name, params) {
    alert(name + " can't be called.");
  }
}

// would then raise the alert "nonExistant can't be called".
stuff().nonExistant();

也许我会解释一下我正在做的事情。

该对象包含另一个对象,该对象具有应该可以通过此对象直接访问的方法。但是这些方法对于每个对象都是不同的,所以我不能只是路由它们,我需要能够动态地调用它们。

我知道我可以将其中的对象作为主对象stuff.obj.existant()的属性,但我只是想知道我是否可以避免它,因为主要对象是一种包装器,只是添加一些功能暂时(并使同时更容易访问对象)。

4 个答案:

答案 0 :(得分:13)

嗯,似乎和谐(ES6),会有一种方式,与其他programing languages的方式相比,它更复杂。基本上,它涉及使用Proxy内置对象在对象上创建包装器,并修改其在其上实现的默认行为:

obj  = new Proxy({}, 
        { get : function(target, prop) 
            { 
                if(target[prop] === undefined) 
                    return function()  {
                        console.log('an otherwise undefined function!!');
                    };
                else 
                    return target[prop];
            }
        });
obj.f()        ///'an otherwise undefined function!!'
obj.l = function() {console.log(45);};
obj.l();       ///45

代理会将处理程序未处理的所有方法转发到普通对象中。所以它就好像它不在那里,从代理你可以修改目标。还有更多的处理程序,甚至一些修改原型获取,以及任何属性访问的设置者是!。

正如您所想,目前并非所有浏览器都支持此功能,但在Firefox中您可以非常轻松地使用代理界面,只需转到MDN docs

如果设法在这上面添加一些语法糖,这会让我更开心,但无论如何,以一种已经很强大的语言拥有这种力量是很好的。祝你今天愉快! :)

PD:我没有复制rosettacode js条目,我更新了它。

答案 1 :(得分:10)

有一种方法可以为不存在的方法调用通用处理程序,但它是非标准的。查看Firefox的noSuchMethod。将允许您动态地将调用路由到未定义的方法。似乎v8也是getting support

要使用它,请在任何对象上定义此方法:

var a = {};

a.__noSuchMethod__ = function(name, args) {
    console.log("method %s does not exist", name);
};

a.doSomething(); // logs "method doSomething does not exist"

但是,如果你想要一个跨浏览器的方法,那么如果要走的话,那么简单的try-catch阻塞:

try {
    a.doSomething();
}
catch(e) {
    // do something
}

如果你不想在整个代码中编写try-catch,那么你可以在主对象中添加一个包装器,通过它来路由所有函数调用。

function main() {
    this.call = function(name, args) {
        if(this[name] && typeof this[name] == 'function') {
            this[name].call(args);
        }
        else {
            // handle non-existant method
        }
    },
    this.a = function() {
        alert("a");
    }
}

var object = new main();
object.call('a') // alerts "a"
object.call('garbage') // goes into error-handling code

答案 2 :(得分:1)

您还可以检查方法是否存在。

if(a['your_method_that_doesnt_exist']===undefined){
//method doesn't exist
}

答案 3 :(得分:1)

似乎你了解JS的方式。 不幸的是,我不知道语言中有这样的功能,我很确定它不存在。在我看来,你最好的选择是使用统一的界面并扩展它,或者扩展你的对象继承的原型(然后你可以在继续使用方法调用之前使用instanceof)或使用有点麻烦的'&&和“运算符,以避免访问不存在的属性/方法:

obj.methodName && obj.methodName(art1,arg2,...);

您还可以使用Anurag的建议('call')扩展Object原型。