缘起

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. Selenium2+python自动化61-Chrome您使用的是不受支持的命令行标记:--ignore-certificate-errors

    前言 您使用的是不受支持的命令行标记:--ignore-certificate-errors.稳定性和安全性会有所下降 selenium2启动Chrome浏览器是需要安装驱动包的,但是不同的Chrom ...

  2. Andorid之使用GMail后台偷偷发送邮件(不要干坏事噢=。 =)

    工具类: import java.util.Date; import java.util.Properties; import javax.activation.CommandMap; import ...

  3. Dijkstra算法求最短路径(java)(转)

    原文链接:Dijkstra算法求最短路径(java) 任务描述:在一个无向图中,获取起始节点到所有其他节点的最短路径描述 Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到 ...

  4. [2] 立方体(Box)图形的生成算法

    顶点数据的生成 bool YfBuildBoxVertices ( Yreal extentX, Yreal extentY, Yreal extentZ, YeOriginPose originPo ...

  5. 认识Mac中的那些符号

    今天看到这篇文章,讲了Mac中的各种符号,还是很不错的. http://www.cnblogs.com/jimcheng/articles/4156268.html

  6. JavaScript前世今生

    JavaScript前世今生,HelloWorld与开发环境 JavaScript历史 大概在1992年,一家称作Nombas的公司开始开发一种叫做C--(C-minus-minus,简称Cmm)的嵌 ...

  7. mysql命令用法复习笔记

    show DATABASES ; create database nulige character set utf8; use nulige; show tables; #创建表 CREATE TAB ...

  8. nginx配置解决vue单页面打包文件大,首次加载慢的问题

    cnpm run build 文件过大,其中主要是vender.js有1.5M,代码部署到服务器,首次访问加载页面时比较慢,耗时6.5s左右,所以需要优化下. 1.Nginx开启gzip 找到ngin ...

  9. Bootstrap popover弹出框

    popover被挤压.遮挡的问题: 弹出框显示的时候如果贴近一个列的边沿,就会很窄或被遮挡,解决起来很简单,只需在初始化的时候添加一个container属性就可以了: $(function (){ $ ...

  10. RS开发值提示默认为当前月

    在报表的开发过程中,按月查询数据,但是由于数据仓库中涉及多年历史数据,而用户最关心的却是最近的数据,针对这个情况.当用户第一次点击报表想看到的就是当前月的数据,那么如何去做呢? 下面用一个小例子来实战 ...