缘起

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. Android中RelativeLayout和LinearLayout性能分析

    先看一些现象吧:用eclipse或者Android studio,新建一个Activity自动生成的布局文件都是RelativeLayout,或许你会认为这是IDE的默认设置问题,其实不然,这是由 a ...

  2. [GIT] Git 工作流程(Git flow, Github flow flow, Git lab flow)

    reference : http://www.ruanyifeng.com/blog/2015/12/git-workflow.html Git 作为一个源码管理系统,不可避免涉及到多人协作. 协作必 ...

  3. [Android] osx下如何使用SublimeText阅读Android系统源码

    reference to : http://www.jianshu.com/p/c295d2729ecf 平时使用Sublimetext都是打开单个文件,这次要导入几万个文件,这在一些ide中称为pr ...

  4. sscanf,sprintf用法

    #include<string.h> #include<stdio.h> int main() { ],sztime1[],sztime2[]; sscanf("12 ...

  5. tyvj P2018 「Nescafé26」小猫爬山 解题报告

    P2018 「Nescafé26」小猫爬山 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 Freda和rainbow饲养了N只小猫,这天,小猫们要去爬山.经 ...

  6. 百度编辑器ueditor通过ajax方式提交,不需要事先转义字符的方法(异常:从客户端(xxx)中检测到有潜在危险的 Request.Form 值)

    最近项目中使用百度编辑神器ueditor,确实是很好用的一款编辑器.官网教程提供的与后端数据交互都是跟表单方式有关的,项目中使用的是ajax方式提交,因此出现了不少问题,现在记录备忘下. 环境:.ne ...

  7. 【Gson】简介 文档 基本使用 示例

    简介 new TypeToken<List<Person>>() {}.getType() 1 1   1 new TypeToken<List<Person> ...

  8. 10 款基于 jQuery 的切换效果插件推荐

    本文整理了 10 款非常好用的 jQuery 切换效果插件,包括平滑切换和重叠动画等,这些插件可以实现不同元素之间的动态切换. 1. InnerFade 这是一个基于 jQuery 的小插件,可以实现 ...

  9. 修改一行SQL代码 性能提升了100倍

    在PostgreSQL中修改了一行不明显的代码,把(ANY(ARRAY[...]) 改成 ANY(VALUES(...))),结果查询时间从20s变为0.2s.最初我们学习使用 EXPLAN ANAL ...

  10. 使用ECharts实现数据图表分析

    一.ECharts介绍 实现对统计数据的图形分析之前用过JFreeChar,但它是用纯java实现编码繁琐且效果不佳,后来又使用过Fusioncharts 报表工具,它是基于Flash的图表组件.以X ...