JavaScript函数的多种定义方法
缘起
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.js
和liba.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函数的多种定义方法的更多相关文章
- 解析JavaScript函数的多种写法
本文主要分析了JavaScript中函数的几种写法,具体如下: 1.函数的声明和表达式(旧方法,也是最常见的方法) 2.通过Function构造器 这也是一种从一开始就存在方法,但是因为书写麻烦等原因 ...
- ASP.NET后台中调用前台Javascript函数的几种方法
做web开发,用的技术是aspx.net,可是由于比较习惯于ASP现在做起来,觉得非常别扭,原因在于有很多功能其实在前台可以处理的,但是因为用到了很多webcontrol,导致不断postback.如 ...
- js 匿名函数 js-函数定义方法
1.任何函数都是有返回值的,没有返回值的,在某些语言里称之为过程例如PL/SQL 2.js中的函数如果没有return 关键字指明给出的返回值,那么当调用完函数后,会返回“undefined" ...
- Javascript 函数和模块定义
匿名函数 // calculator.js(function(root) { var calculator = { sum: function(a, b) { return a + b; } ...
- JavaScript 函数定义方法
JavaScript 函数定义方法. 函数声明 在之前的教程中,你已经了解了函数声明的语法 : function functionName(parameters) { 执行的代码 } 函数声明后不会立 ...
- JavaScript 函数定义
JavaScript 使用关键字 function 定义函数. 函数可以通过声明定义,也可以是一个表达式. 函数声明 在之前的教程中,你已经了解了函数声明的语法 : function function ...
- JavaScript函数认识,Js中的常见函数
JavaScript函数: 也称为方法,用来存储一块代码,需要的时候调用. 函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块. 函数需要包含四要素:返回类型,函数名,参数列表,函数体 拓展: ...
- JavaScript 函数与对象的 简单区别
直接上例子 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <met ...
- JS如何定义方法及调用 精选
简单搜索了下,遇到点问题1,经常在JS中看到如var foo = function(){}的形式foo是方法名还是对象名,如果想调用此方法,是用foo(),foo.function(),还是该如何正确 ...
随机推荐
- Spring3.2.3+Quartz2.2.1 整合配置
步骤: 1.下载相关包 quartz-2.2.1.jar quartz-jobs-2.2.1.jar spring相关jar包 2.编写配置文件静态 <bean id="activat ...
- WhyEngine游戏合集2014贺岁版
WhyEngine游戏合集2014贺岁版 自去年9月份开始写我的第一个小游戏,到现在为止,共实现了14个小游戏,10个屏保程序,7个DEMO程序.开发环境是VS2008,渲染使用的是D3D,所有代码都 ...
- 性能二 fortnite unreal opt
https://replay.unrealsummit.co.kr/data2018/usm2018_42.pdf?ckattempt=1 https://www.unrealengine.com/e ...
- 30条技巧提高Web程序执行效率
尽量避免使用DOM.当需要反复使用DOM时,先把对DOM的引用存到JavaScript本地变量里再使用.使用设置innerHTML的方法来替换document.createElement/append ...
- 判断 iframe 是否加载完毕
我能想到的有以下几种方式: 方法一.jQuery load() var frm = document.getElementById('myiframe'); $(frm).load(function( ...
- Cognos与Firefox的那些事
最近怀着一颗好奇的心装了Win10系统,作为一个Coder,或多或少的这么久以来对于它的兼容性还是秉着一颗质疑的态度.但是一切事情都要敢于尝试,毕竟Win10的用户体验还是很好的.和预料的一样,问题马 ...
- Linux学习笔记之初级篇
第一部分:[安装注意环节] 第二部分:[常用命令小试] 第三部分:[oracle的安装]
- 【HTML5】实现QQ聊天气泡效果
今天自己用 HTML/CSS 做了个类似QQ的聊天气泡,以下是效果图: 以下说下关键地方的样式设置.然后贴出html和css代码(不多). 步骤1:布局 消息採用div+float布局,每条消息用一个 ...
- java oracle thin 和 oci 连接方式实现多数据库的故障切换
java oracle thin 和 oci 连接方式实现多数据库的故障切换 一.thin方式 该种方式简便易用非经常见. 当中URL为 jdbc:oracle:thin:@(DESCRIPTION= ...
- WebClient.DownloadData突然失灵
有如下的代码: try { byte[] acsMetadata; using (WebClient webClient = new WebClient()) { acsMetadata = we ...