缘起

javascript和其他编程语言相比比较随意,所以javascript代码中充满各种奇葩的写法,有时雾里看花,当然,能理解各型各色的写法也是对 javascript语言特性更进一步的深入理解,那么他有几种写法呢?

 ( function(){…} )()

或者

 ( function (){…} () )

首先要明白两个知识点

js中函数是引用类型;
函数一般执行方式:函数名+();

下面的例子帮你理解引用类型

var a = function(x,y){
console.log(x + y);
};
var b = a;
a(1,2);
b(1,2); //b,a指向同一个函数对象 //b重新赋值
b = function(x,y){
console.log(x - y);
}
a(1,2);
b(1,2);

函数的几种定义方式

js函数有普通函数、构造函数、匿名函数,定义方式有三种,即函数声明方式(function declaration, abbreviation as FD)、函数表达式方式(function expression, abbreviation as FE)、函数对象方式(对象的方式定义函数,前面参数为函数的参数,最后为函数体。但是需要解析传入的字符串参数,导致两次解析,所以不推荐这种方式来定义函数)

1、函数声明方式

//不会报错,但是javascript引擎只解析函数声明,忽略后面的括号,函数声明不会被调用
function fnName(){
alert('Hello World');
}();
//可以执行
alert(sum(1,2));
function sum(x,y){
return x + y;
}

 2、函数表达式方法

//这段代码会报错
alert(sum(1,2));
var sum = function (x,y){
return x + y;
}
//函数表达式后面加括号,当javascript引擎解析到此处时能立即调用函数
var show=function(){
alert('Hello World');
}();

 3、函数对象方法

var sum = new Function('value1', 'value2', 'return value1 + value2');

在写递归的时候可以这样写

//如果直接用sum(x-1) + sum(x-2),如果sum被改名,或者重新赋值,产生bug
var sum = function fSum(x){
if(x<=2)
return 1;
else
return fSum(x-1) + fSum(x-2);
};
alert(sum(5));

 4、匿名函数

使用function关键字声明一个函数,但未给函数命名,所以叫匿名函数,匿名函数属于函数表达式,匿名函数有很多作用,赋予一个变量则创建函数,赋予一个事件则成为事件处理程序或创建闭包等等

function () {}

区别

1、FD是在构建函数的Execution Context时会被计算并作为Activation Object的一个属性被引用,因此就出现declaration hoisting的现象。而FE则是在函数的Runtime中才被计算,而且不会作为Activation Object的一个属性被引用,也就是说FD会被解析器通过函数声明提升的过程即function declaration hoisting置于原代码数的顶部,所以即使在函数前调用该函数也可以正常使用

2、而函数表达式方式除了不能在声明前调用外,与函数声明方式一样

3、函数对象方法可以直观地理解“函数是对象,函数名是指针”这个概念,但是它会造成解析器两次解析,一次是普通的ECMAScript代码,一次是解析传入 Function构造函数里的字符串,会影响js引擎性能

4、函数表达式后面可以加括号立即调用该函数,函数声明不可以

立即执行函数表达式

我们在使用JavaScript的时候经常会看见类似如下的函数调用方式

(function(){
console.log("test");
})();

或者

(function(){
console.log("test");
}());

比如jQuery

(function( window, undefined ) {
// code here
}) ( window );

这种写法有两种称呼

「自执行匿名函数」(self-executing anonymous function),
「立即执行函数表达式」(Immediately-Invoked Function Expression,以下简称IIFE)

还有一些奇葩的定义方式

// 如果本身就是expression,那么根本不需要做任何处理
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }(); // 如果你不在乎返回值,可以这么做
!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }(); // 还有更奇葩的方式,但是不知道性能如何,来自 new function(){ /* code */ }
new function(){ /* code */ }()

为什么要用立即执行函数表达式

1、模拟块作用域

众所周知,JavaScript没有C或Java中的块作用域(block),只有函数作用域,在同时调用多个库的情况下,很容易造成对象或者变量的覆盖,比如

liba.js

var num = 1;
// code....

libb.js

var num = 2;
// code....

如果在页面中同时引用liba.jsliba.js两个库,必然导致num变量被覆盖,为了解决这个问题,可以通过IIFE来解决:

liba.js

(function(){
var num = 1;
// code....
})();

libb.js

(function(){
var num = 2;
// code....
})();

2、解决闭包冲突

闭包(closure)是JavaScript的一个语言特性,简单来说就是在函数内部所定义的函数可以持有外层函数的执行环境,即使在外层函数已经执行完毕的情况下,在这里就不详细介绍了,感兴趣的可以自行Google。我们这里只举一个由闭包引起的最常见的问题

var f1 = function() {
var res = [];
var fun = null;
for(var i = 0; i < 10; i++) {
fun = function() { console.log(i);};//产生闭包
res.push(fun);
} return res;
} // 会输出10个10,而不是预期的0 1 2 3 4 5 6 7 8 9
var res = f1();
for(var i = 0; i < res.length; i++) {
res[i]();
}

修改成:

var f1 = function() {
var res = [];
for(var i = 0; i < 10; i++) {
// 添加一个IIFE
(function(index) {
fun = function() {console.log(index);};
res.push(fun);
})(i);
} return res;
} // 输出结果为0 1 2 3 4 5 6 7 8 9
var res = f1();
for(var i = 0; i < res.length; i++) {
res[i]();
}

可以参考http://segmentfault.com/q/1010000003490094

3、模拟单例

在JavaScript的OOP中,我们可以通过IIFE来实现,如下

var counter = (function(){
var i = 0;
return {
get: function(){
return i;
},
set: function( val ){
i = val;
},
increment: function() {
return ++i;
}
};
}()); counter.get(); // 0
counter.set( 3 );
counter.increment(); // 4
counter.increment(); // 5

参考:
http://benalman.com/news/2010/11/immediately-invoked-function-expression/#iife
http://blog.coolaj86.com/articles/how-and-why-auto-executing-function.html
http://stackoverflow.com/questions/592396/what-is-the-purpose-of-a-self-executing-function-in-javascript
http://www.cnblogs.com/TomXu/archive/2011/12/31/2289423.html
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function

JavaScript函数的多种定义方法的更多相关文章

  1. 解析JavaScript函数的多种写法

    本文主要分析了JavaScript中函数的几种写法,具体如下: 1.函数的声明和表达式(旧方法,也是最常见的方法) 2.通过Function构造器 这也是一种从一开始就存在方法,但是因为书写麻烦等原因 ...

  2. ASP.NET后台中调用前台Javascript函数的几种方法

    做web开发,用的技术是aspx.net,可是由于比较习惯于ASP现在做起来,觉得非常别扭,原因在于有很多功能其实在前台可以处理的,但是因为用到了很多webcontrol,导致不断postback.如 ...

  3. js 匿名函数 js-函数定义方法

    1.任何函数都是有返回值的,没有返回值的,在某些语言里称之为过程例如PL/SQL 2.js中的函数如果没有return 关键字指明给出的返回值,那么当调用完函数后,会返回“undefined" ...

  4. Javascript 函数和模块定义

    匿名函数 // calculator.js(function(root) {  var calculator = {    sum: function(a, b) { return a + b; }  ...

  5. JavaScript 函数定义方法

    JavaScript 函数定义方法. 函数声明 在之前的教程中,你已经了解了函数声明的语法 : function functionName(parameters) { 执行的代码 } 函数声明后不会立 ...

  6. JavaScript 函数定义

    JavaScript 使用关键字 function 定义函数. 函数可以通过声明定义,也可以是一个表达式. 函数声明 在之前的教程中,你已经了解了函数声明的语法 : function function ...

  7. JavaScript函数认识,Js中的常见函数

    JavaScript函数: 也称为方法,用来存储一块代码,需要的时候调用. 函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块. 函数需要包含四要素:返回类型,函数名,参数列表,函数体 拓展: ...

  8. JavaScript 函数与对象的 简单区别

    直接上例子 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <met ...

  9. JS如何定义方法及调用 精选

    简单搜索了下,遇到点问题1,经常在JS中看到如var foo = function(){}的形式foo是方法名还是对象名,如果想调用此方法,是用foo(),foo.function(),还是该如何正确 ...

随机推荐

  1. velocity.properties配置说明

    1.Runtime  Log runtime.log  =  velocity.log 用以指定 Velocity 运行时日志文件的路劲和日志文件名,如不是全限定的绝对路径,系统会认为想对于 当前目录 ...

  2. docker get 到的命令 (持续更新)

    删除容器:  docker rm containerID (is running) 删除not running的容器:  docker ps -a   然后  docker rm -f contain ...

  3. table固定首行(二)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. linux 复制目录结构,但不复制文件

    find src -type d | sed 's/src/mkdir -p dst/'|sh

  5. Objective-C:对象之间循环引用会造成死循环

    对象之间的循环引用        两个对象A.B,有可能会出现一种特殊的情况:A中包含B的实例变量:B中又包含A的实例变量,如果两个实例变量都是强引用(A有B实例变量的所有权,B也有A的实例变量的所有 ...

  6. OpenCV学习(25) 直方图(2)

    在OpenCV中,也可以对三通道的图像,比如BGR,HSV等计算直方图.方法和计算单通道图像直方图相似,下面的代码描述了如何计算一个BGR三通道图像的直方图,需要注意的是,因为是三通道,每个通道取值都 ...

  7. WhyDX9:翻写D3D红龙书中的程序

    之前写过一套学习OpenGL的框架:WhyGL,即然有了GL那也应该再写个学习D3D的框架:WhyDX9.两个程序的架构相同,然后这个程序是将D3D红龙那本书的DEMO翻写了一遍.先将可执行程序发一下 ...

  8. 错误: 找不到或无法加载主类 Files\red5-server ,原因与解决办法

    因为你把 red5放到了 Program Files 下,而Program Files 中间有个空格,启动路径不允许有空格,换个没空格的路径就OK啦

  9. 拍案惊奇!9款神奇的jQuery/CSS3经典插件

    款非常给力的jQuery/CSS3经典插件,插件包括CSS3图片特效.jQuery动画菜单.jQuery时尚登录表单等,一起来看看这些jQuery插件. .CSS3图片重力感应特效 这是一款应用重力感 ...

  10. Nginx配置文件(nginx.conf)配置具体解释

    欢迎扫码增加Java高知群交流 Nginx的配置文件nginx.conf配置具体解释例如以下:   user nginx nginx ; Nginx用户及组:用户 组. window下不指定   wo ...