javascript自调函数

JavaScript中匿名函数一种非常常见的用法就是自调函数,这种函数可以在定义之后自行调用。

自调函数常见形式是:

(function(){
    alert("foo");
})()

光看这个形式,可能会让人以为是在函数体前后包个括号,然后后面通过括号运算符来立即调用函数,形式上说是对的,但是为什么要给函数包个括号?下面我们就来重新认识一下自调函数。 要理解自调函数,首先我们要理解两个概念

函数声明

函数声明通常由一下几部分组成:

  • function子句
  • 函数名称
  • 函数的参数
  • 函数体
  • return子句,默认返回值为undefined。

例子:

function foo(a,b) {
    return a+b;
}

函数表达式

函数声明容易理解,函数表达式就陌生多了。其实,这里说的函数表达式,顾名思义就是一种表达式,内容是函数。表达式就是那些个加减乘除之类的。

比如说下面这个例子:

var foo = function (a,b) {
            return a+b;
          };

例子中,创建了一个匿名函数,然后把这个匿名函数的引用给了foo这个变量。 严格来说,这个例子不完全是函数表达式,去除var foo之后,剩下的就是一个函数表达式。

上面的例子要如何调用函数?很明显foo(1,2)就可以了,之前说过foo不过是那个匿名函数的引用,对foo使用括号运算符就可以调用这个匿名函数了。

既然如此,是不是也可以这样调用:

d = function (a,b) {
    return a+b;
}(1,2)

这里变量d的值是3,因为此处等号是个二元运算符,所以看的可能不是太清楚,可以尝试改成如下形式:

+ function (a,b) {
        return a+b;
    }(1,2)

控制台中运行会输出3,这就是一个自调函数。

重新认识自调函数

分清楚函数声明和函数表达式之后,我们来重新认识自调函数。 先看几个例子:

(function(a){
    console.log(a);   //123
})(123);

(function(a){
    console.log(a);   //123
}(123));

! function(a){
    console.log(a);   //123
}(123);

+ function(a){
    console.log(a);   //1234
}(123);

- function(a){
    console.log(a);   //123
}(123);

void function(a){
    console.log(a);   //123
}(123)

可以看出,要让匿名函数自调用,首先要把匿名函数变成函数表达式,而不能是函数声明。 而把函数声明变成函数表达式的方法就是在function关键字前面加点什么东西,例如括号,+,-,!,void,=,逗号,~……告诉js解析引擎,这个是一个函数表达式,可以通过()运算符来执行。

而加()是最安全的做法,因为加减号会影响返回值,而void会让返回值为undefined,所以括号用的最广泛,但我们要知道除了括号,别的也能实现自调函数。

自调用函数解决setTimeout传参数

有时候我们需要循环设置setTimeout,并且每次执行的函数的参数还不一样,这个时候就是我们的自调函数大显身手的时候了:

var i = 0, tmp = [1,2,3];
for(i,len=tmp.length;i<len;i++) {
    setTimeout(
        (function(txt){
          return function(){
            console.log(txt)
          }
        })(tmp[i]),
    1000*i);
}

控制台执行,可以看到依次打印出1,2,3 理解一下上面setTimeout的执行:

  1. setTimeout里面把(function(){})()当成函数表达式执行,返回了一个匿名函数的引用;
  2. 当延时结束的时候,由js解释器来执行这个函数引用。

这里要注意,返回的是函数的引用,不要单纯的理解为字符串的传递。

参考资料

http://dengo.org/archives/1004 https://segmentfault.com/q/1010000002867883

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java学习

面试题67(以下程序创建了几个对象——String)

面试例题1:以下程序创建了几个对象? String A,B, C; A="a"; B="b"; A=A+B; StringBuffer D=new String...

2847
来自专栏乐百川的学习频道

Golang学习笔记 结构体和指针

Golang是一门很特殊的语言,虽然它出生比较晚,但是在很多地方却和现在的编程语言有所不同。现在的编程语言要么是函数式的、要么是面向对象的,而Go语言却有指针、...

2119
来自专栏乐百川的学习频道

C++学习笔记 基本数据类型

由于考研的编程题很多都需要使用C++语言来写,所以虽然我不太喜欢C++这门语言,那么还是得来看看。 算术类型 需要提前说明,C++语言属于比较低级的语言,所以没...

1798
来自专栏程序员互动联盟

【编程基础】c printf知多少

printf()函数是格式输出函数,请求printf()打印变量的指令取决与变量的类型.例如,在打印整数是使用%d符号,在打印字符是用%c 符号.这些符号被称为...

3355
来自专栏我和PYTHON有个约会

14.程序编程进阶:函数的参数

函数通过def进行定义,用于执行一个功能,一个函数,可以需要参数,也可以不需要参数。 类似我们现实生活,执行一个功能就是做一件事情,做这件事情需要的资源就是参...

813
来自专栏cs

python的格式化输出

>>> a=1.500; >>> print(a); 1.5 末尾的0没有输出,但是有时候我们需要,这样就必须采用格式化输出。 利用字符串格式运算符% >>> ...

2434
来自专栏python3

python 字符串常用操作

字符串是 Python 中最常用的数据类型。我们可以使用引号('或")来创建字符串。

821
来自专栏陈树义

《JavaScript程序设计》第2课:JS类型系统

JS类型系统可以分为标准类型和对象类型,进一步标准类型又可以分为原始类型和引用类型,而对象类型又可以分为内置对象类型、普通对象类型、自定义对象类型。 ? 1. ...

3357
来自专栏软件开发 -- 分享 互助 成长

(虚)继承类的内存占用大小

(虚)继承类的内存占用大小 首先,平时所声明的类只是一种类型定义,它本身是没有大小可言的。 因此,如果用sizeof运算符对一个类型名操作,那得到的是具有该类...

2078
来自专栏海说

常见正则表达式

正则表达式(RegExp:regular expression):一种用特殊符号编写的模式,描述一个或多个文本字符串。最适合用来搜索和操纵文本字符串。如,检查输...

2040

扫码关注云+社区