如何在JavaScript中检查函数是否存在?

784

我的代码是

function getID( swfID ){
     if(navigator.appName.indexOf("Microsoft") != -1){
          me = window[swfID];
     }else{
          me = document[swfID];
     }
}

function js_to_as( str ){
     me.onChange(str);
}

然而,有时我的onChange无法加载。Firebug报错为

me.onChange不是一个函数

我想要优雅地降级,因为这不是我的程序中最重要的功能。 typeof会给出同样的错误。

有什么建议可以确保它存在,然后再执行onChange

(除了try catch之外,下面的方法都不起作用)


可能是重复的问题:如何判断JavaScript函数是否已定义 - Tot Zam
34个回答

1590

试试这样的方法:

if (typeof me.onChange !== "undefined") { 
    // safe to use the function
}

或者更好的是(根据UpTheCreek的点赞评论)

if (typeof me.onChange === "function") { 
    // safe to use the function
}

11
@UpTheCreek,如果作为一种通用解决方案的话可能会有些危险,因为较旧版本的IE将某些函数视为对象,例如typeof window.alert === 'object' - Noyo
3
为什么不直接使用 if (me.onChange) { // do something } 呢? - BornToCode
4
因为me.onChange可以是任何值为true的东西,不一定是一个函数(例如,它可以是布尔值、字符串等)。所以,这样写会有问题。具体可以看看这个例子:http://jsfiddle.net/j5KAF/1/ - Ohad Schneider
1
@UpTheCreek 和 @Noyo:我错过了你们的评论并遇到了问题。我刚刚把测试改成了:((typeof me.onChange === "function") || (typeof me.onChange === "object")) 在我的情况下在ie8上运行良好。 - Swiss Mister
3
只是明显地指出,如果全局的 me 未定义,typeof me.onChange === "function" 就会失败。 - Mark Schultheiss
显示剩余2条评论

178

现代JavaScript来拯救!

me.onChange?.(str)

可选链语法 (?.) 可以解决这个问题。

  • JavaScript 中从ES2020版本开始
  • TypeScript 中从3.7版本开始

在上面的示例中,如果存在me.onChange属性并且是一个函数,则会调用该函数。

如果不存在me.onChange属性,则不会发生任何事情:表达式仅返回undefined

注意 - 如果存在me.onChange属性但它不是函数,则会像在JavaScript中调用任何非函数一样抛出TypeError。 可选链不能通过魔术来使这个问题消失。


这不能检查裸函数是否存在。如果“me”未定义,它将会抛出异常。 - duhaime
2
@duhaime me 未定义是一个独立的问题(该函数只是在问题中发生在 me 对象上)- 但是,如果您确实需要首先检查 me 是否已定义,则也可以使用可选链来执行此操作:me?.onChange?.(str) - davnicwil
如果你在开发控制台中运行 me?.onChange?.(str),它会崩溃。但是,如果你知道全局上下文,可以使用 window?.$me?.onChange?.(str) - duhaime
啊,有趣的问题!如果me甚至没有被声明(而不是声明但是undefined),那么我猜这将会是一个ReferenceError。看了一下问题,如果这是整个代码,那确实是这种情况,我原本以为只是一个片段,其中me被暗示在其他地方已经被声明了。很好的发现! - davnicwil
3
一个关于使用这个的警示故事:https://blog.jim-nielsen.com/2022/a-web-for-all/ - cbirdsong

162

我曾经遇到这样的问题。如果obj恰好是undefined,那么if (obj && typeof obj === 'function') { ... }会无法执行并抛出引用错误,所以最终我做了以下更改:

if (typeof obj === 'function') { ... }
if (typeof obj !== 'undefined' && typeof obj === 'function') { ... }

然而我的同事指出,检查是否为!== 'undefined'=== 'function'是冗余的,因此:

更简单的写法:

if (typeof obj === 'function') { ... }

更加清洁,而且表现出色。


1
有人知道为什么第一个代码片段会抛出“ReferenceError”吗?这对我来说似乎不合逻辑。 - saidfagan
@saidfagan 请查看ReferenceError的定义 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError - Misha Nasledov
3
为什么typeof obj == 'function'不足以说明问题呢?提醒一下,严格相等测试运算符只有在静态操作数为空、为null、为0或者被任何强制类型转换混合时才有意义。 - Fabien Haddadi

27

怎么样:

if('functionName' in Obj){
    //code
}

需要翻译的内容:

e.g.

var color1 = new String("green");
"length" in color1 // returns true
"indexOf" in color1 // returns true
"blablabla" in color1 // returns false

或者就您的情况而言:

if('onChange' in me){
    //code
}

请查看MDN文档


1
但是这个解决方案并不总是有效 :( 例如,如果我想知道字符串中是否有 lastIndexOf() 方法(我们知道有,但从理论上讲) typeof String().lastIndexOf === "function" 是正确的,但 'lastIndexOf' in String 是错误的。 - iiic

21

如果您正在使用 eval 将字符串转换为函数,并且想要检查此 eval 方法是否存在,您将需要在 eval 中使用 typeof 和您的函数字符串:

var functionString = "nonexsitantFunction"
eval("typeof " + functionString) // returns "undefined" or "function"

不要反转这个并尝试在 eval 上使用 typeof。如果你这样做,将抛出一个 ReferenceError:

var functionString = "nonexsitantFunction"
typeof(eval(functionString)) // returns ReferenceError: [function] is not defined

9
你可以不使用 eval 来实现这个。 例如:var a = 'alert'; window[a]('it works'); - Levent Yumerov

15

使用typeof关键字 -- 如果结果为'undefined'则表示该对象不存在,如果结果为'function'则表示该对象是一个函数。可访问此代码的JSFiddle链接

function thisishere() {
    return false;
}
alert("thisishere() is a " + typeof thisishere);
alert("thisisnthere() is " + typeof thisisnthere);

或者作为一个if语句:

if (typeof thisishere === 'function') {
    // function exists
}

或者带有返回值,写在一行:

var exists = (typeof thisishere === 'function') ? "Value if true" : "Value if false";
var exists = (typeof thisishere === 'function') // Returns true or false

14

没有看到这个建议:

如果me.onChange未定义(如果它尚未初始化,则会是这样),则不会执行后面的内容。 如果me.onChange是一个函数,它将执行me.onChange(str)。

你甚至可以进一步做到:

me && me.onChange && me.onChange(str);

如果我也是异步的话。


12

对我而言,最简单的方法是:

function func_exists(fname)
{
  return (typeof window[fname] === 'function');
}

这是正确的答案,因为它是一个字符串字面量。我认为最好这样写:if ((typeof window["function_name"] !== 'undefined') && ((typeof window["function_name"] === 'function'))) { return true; } else { return false; } 但这只是一个小调整。 - Mr Heelis

10

在您想要检查的函数名称前加上双感叹号,即 !!。如果它存在,则返回true。

function abc(){
}
!!window.abc; // return true
!!window.abcd; // return false

简洁明了的解决方案 - J. Volkya

7
function function_exists(function_name)
{
    return eval('typeof ' + function_name) === 'function';
}
alert(function_exists('test'));
alert(function_exists('function_exists'));

或者

function function_exists(func_name) {
  //  discuss at: http://phpjs.org/functions/function_exists/
  // original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  // improved by: Steve Clay
  // improved by: Legaev Andrey
  // improved by: Brett Zamir (http://brett-zamir.me)
  //   example 1: function_exists('isFinite');
  //   returns 1: true

  if (typeof func_name === 'string') {
    func_name = this.window[func_name];
  }
  return typeof func_name === 'function';
}

1
请给一些解释。 - Gufran Hasan
在两种情况下,只需使用函数参数的名称调用function_exists来检查其是否存在,返回布尔值。 - Mohammad Lotfi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接