admin管理员组

文章数量:1336631

I'm currently writing some code that wrappers user-written JavaScript functions, and have e 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;}; };

I'm currently writing some code that wrappers user-written JavaScript functions, and have e 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;}; };
Share Improve this question asked Dec 1, 2012 at 10:41 PebblPebbl 36.1k6 gold badges64 silver badges65 bronze badges 5
  • I think this is not possible. – Pavel Strakhov Commented Dec 1, 2012 at 10:45
  • I'm curious: What's the use case? Why do you care which of a, b, or c occurred? They are functionally identical. A difference that makes no difference is no difference... :-) – T.J. Crowder Commented Dec 1, 2012 at 10:53
  • Don't forget return; and return void <expr> which also give undefined. – Paul S. Commented Dec 1, 2012 at 11:03
  • If you have access to source before it gets interpreted, you could replace the final } with return someConst; where someConst is something very unlikely to be returned by the user, then return undefined from your wrapper. – Paul S. Commented Dec 1, 2012 at 11:09
  • @T.J.Crowder it's really rather a singular use-case, it's part of a game where coding will be involved - and different things will occur depending on the code used. I was just testing out a few ideas and had not e across this issue before. The responses are sadly as I expected though.. rather a subtle annoyance from JS's pov. Ah well c'est la vie :) Looks like I'll have to try a different approach. – Pebbl Commented Dec 1, 2012 at 12:01
Add a ment  | 

5 Answers 5

Reset to default 4

No, you cannot reliably, cross-browser, tell whether a function returned by just reaching the end of its code, using return without a value, or using return undefined. This is covered by Section 13.2.1 of the specification.

Another answer here suggests you could do it by analyzing the source code of the function. However, there is no standard mechanism for doing that. Though nearly all browsers make some form of the source available from Function#toString, some do not (mostly mobile browsers), and it is not defined by the specification. But if you have a certain set of browsers that you support, and they all have it, that would be your only real option — but even then, you wouldn't necessarily know which code branch was taken within the function.

Leaving a function blank will also return undefined, so a, b and c will all return identical values.

The only way to achieve something like this would to actually set some kind of flag in the function itself, but I'm guessing you want to be able to do this independently of the implementations of the actual function.

There is no way to tell the difference.

If you really wanted to, you could try to analyze the function's source code and determine whether it has any return statements, and if not, then assume it won't return a value. Of course this would be a bit harder to determine if a function sometimes returns and others not (eg. a return statement in an if-block)

This is crazy and definitely not remended, it creates a copy of the function, modifies the function body and uses 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)
    }
}

Assuming you have a function like this,

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

You would use the proxy function like this:

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

With the first parameter being the function itself , and second parameter an array of parameters

The return value will be an object with 2 properties, out contains the function result, and returned is a boolean indicating if the function returned or not

Example output,

returnProxy(someFunction,[1]); // {out: undefined, returned: true}
returnProxy(someFunction,[2]); // {out: "hello", returned: true}
returnProxy(someFunction,[3]); // {out: undefined, returned: false} 

You can only tell if you invoke the functions through a wrapper, but I'm not sure if this is suitable for your usecase.

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());

本文标签: Any way to tell whether a javascript function has returned or notStack Overflow