2

I'm currently writing some code that wrappers user-written JavaScript functions, and have come across a point in the logic where I would like to trigger a particular behaviour if the function in question never returns a value i.e. the return keyword is never evaluated.

Currently I am assuming that if a function returns undefined, it has not returned, however this is not strictly true—due to the fact a function can always return undefined, or return the value of an undefined property.

With a function call you can always tell how many parameters were used due to the arguments.length property, I was wondering if anyone knew of a similar trick for a function's return value?

So, is it possible to tell the difference between the return values of a, b or even c

var a = function(){  };
var b = function(){ return undefined; };
var c = function(){ if(1){}else{return undefined;}; };
4

5 回答 5

4

不,您不能可靠地跨浏览器判断一个函数是通过到达其代码末尾、使用return不带值还是使用return undefined. 规范的第 13.2.1 节涵盖了这一点。

这里的另一个答案建议您可以通过分析函数的源代码来做到这一点。但是,没有标准的机制可以做到这一点。尽管几乎所有浏览器都提供了某种形式的源代码 Function#toString,但有些却没有(主要是移动浏览器),并且规范中没有定义。但是,如果您有一组您支持的浏览器,并且它们都有,那将是您唯一真正的选择——但即使那样,您也不一定知道函数中采用了哪个代码分支。

于 2012-12-01T10:49:35.377 回答
2

这很疯狂,绝对不推荐,它会创建函数的副本,修改函数体并使用eval

function returnProxy(func,args) {
    var returnFlag = Math.random()+"";

    // create new function based on passed function body
    var fullFuncBody = func.toString();
    var tmpFuncStr = "function  "+ fullFuncBody.substr(fullFuncBody.indexOf("("));

    tmpFuncStr = tmpFuncStr.substr(0,tmpFuncStr.length-1)+"\nreturn '"+returnFlag+"'}";

    var tmpFunc;
    eval("tmpFunc = "+tmpFuncStr); // really bad things

    var funcOut = tmpFunc.apply(this,args);

    return {
        out: (funcOut == returnFlag) ? undefined : funcOut,
        returned: (returnFlag != funcOut)
    }
}

假设你有这样的功能,

function someFunction(action) {
    switch(action) {
        case 1:
            return undefined;
        case 2:
            return "hello";
    }
}

您将像这样使用代理功能:

returnProxy(someFunction,[1]); // instead of calling someFunction(1)

第一个参数是函数本身,第二个参数是参数数组

返回值将是一个具有 2 个属性的对象,out包含函数结果,并且returned是一个布尔值,指示函数是否返回

示例输出,

returnProxy(someFunction,[1]); // {out: undefined, returned: true}
returnProxy(someFunction,[2]); // {out: "hello", returned: true}
returnProxy(someFunction,[3]); // {out: undefined, returned: false} 
于 2012-12-01T12:07:06.110 回答
2

将函数留空也将返回未定义,因此 a、b 和 c 都将返回相同的值。

实现这样的事情的唯一方法是在函数本身中实际设置某种标志,但我猜你希望能够独立于实际函数的实现来做到这一点。

于 2012-12-01T10:47:16.763 回答
2

没有办法区分。

如果你真的想,你可以尝试分析函数的源代码并确定它是否有任何返回语句,如果没有,则假设它不会返回值。当然,这会有点难以确定一个函数是否有时返回而其他函数不返回(例如,if 块中的 return 语句)

于 2012-12-01T10:47:41.487 回答
0

您只能判断您是否通过包装器调用函数,但我不确定这是否适合您的用例。

function invoker(f) {
    var actualFunc = f,
        invokeCount = 0;

    function invoke() {
        invokeCount = invokeCount +1;
        return actualFunc.apply(this, arguments);
    }

    function invoked() {
       return invokeCount;
    }

    return {
      invoke: invoke,
      invoked: invoked
    };
}

var a = function(){  };
var b = function(){ return undefined; };
var c = function(){ if(1){}else{return undefined;}; };

var ainvoker = new invoker(a);    

alert(ainvoker.invoke());
alert(ainvoker.invoked());
于 2012-12-01T10:58:00.447 回答