来自https://blog.csdn.net/u012369153/article/details/69948569
在JavaScript中,函数也是一种数据类型,定义函数有两种方式:
function f(){return 1;}
var f=function(){return 1;}
- 1
- 2
所以,JavaScript中的函数是一种数据,但是它有两个重要的特性:
- 包含的是代码
- 是可执行的
函数的命名规则和一般变量相同,不能以数字开头、可以由任意的字母、数字、下划线组成
匿名函数
一段数据既没有赋值给某个变量,也没有被赋予任何名字就是匿名的。匿名函数的两种用法:
- 将匿名函数作为参数传递给其他函数,接收方函数就可以利用传递过来的匿名函数完成相应的任务
- 定义某个匿名函数来执行一些一次性任务
回调函数
定义一个以两个函数为参数的函数,该函数会分别执行这两个参数函数:
//定义一个以两个函数为参数的函数,该函数会分别执行这两个参数函数,并返回它们的返回值之和
function invoke_and_add(a,b){
return a() + b();
}
//简单定义参与运算的函数
function one(){
return 1;
}
function two(){
return 2;
}
//将这两个函数传递给目标函数
invoke_and_add(one ,two);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
在这里我们可以用匿名函数来代替上面参与运算的两个函数,作为目标函数的参数:
function invoke_and_add(a,b){
return a() + b();
}
invoke_and_add(function(){return 1;},function(){return 2;})
- 1
- 2
- 3
- 4
当我们将函数A传递给函数B,并且由B来执行A时,A就成了一个回调函数(callback functions),如果此时A还是一个无名函数,那么就叫它匿名回调函数。
回调函数的优势
- 在不做命名的情况下传递函数,这也就是说可以节省全局变量
- 将一个函数调用委托给另一个函数,节省编码
- 可以提高性能
回调示例
一般将一个函数的返回值传递给另一个函数。
//通过一个循环将其所接收的三个参数分别乘以2,并以数组的形式返回结果
function multiplyByTwo(a,b,c){
var i,ar =[];
for(i=0;i<3;i++){
ar[i] = arguments[i]*2;}
return ar;
}
//只接受一个参数,将它加1后并返回
function addOne(a){
return a+1;
}
multiplyByTwo(1,2,3);
addOne(100);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
接下来,我们实现这三个元素在两个函数之间的传递,在这定义一个用于存储元素的数组,先从multiplyByTwo()的调用开始
var myarr = [];//定义一个数组
myarr = multiplyByTwo(10,20,30);//调用函数
- 1
- 2
然后,用遍历循环每个元素,并将它们分别传递给addOne()
for(var i=0;i<3;i++){
myarr[i] = addOne(myarr[i])
}
myarr
- 1
- 2
- 3
- 4
在以上的过程中,使用了两个循环,这是可以改进的将他们合二为一,对multiplyByTwo()函数改为接收一个回调函数,并在每次迭代操作中调用它:
function multiplyByTwo(a,b,c,callback){
var i,ar =[];
for(i=0;i<3;i++){
ar[i] = callback(arguments[i]*2);
}
return ar;
}
function addOne(a){
return a+1;
}
myarr = multiplyByTwo(1,2,3,addOne);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
我们还可以用匿名函数来代替addOne(),这样可以节省一个额外的全局变量
function multiplyByTwo(a,b,c,callback){
var i,ar =[];
for(i=0;i<3;i++){
ar[i] = callback(arguments[i]*2);
}
return ar;
}
myarr = multiplyByTwo(1,2,3,function(a){return a+1});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
自调函数
匿名函数的另一个应用,可以在定义后自行调用。
(
function(){
alert('boo');
}
)()
- 1
- 2
- 3
- 4
- 5
只需要将匿名函数的定义放进一堆括号中,然后外面再紧跟一对括号即可,第二个括号的作用是“立即调用”的意思,同时也是向匿名函数传递参数的地方。
(
function(name){
alert('Hello '+ name +'!');
}
)('dudu')
- 1
- 2
- 3
- 4
- 5
内部私有函数
在一个函数内部定义另一个函数。
function a(param){
function b(theinput){
return theinput*2;
};
return 'the result is ' + b(param);
};
- 1
- 2
- 3
- 4
- 5
- 6
或者用函数标识记法:
var a = function(param){
var b = function(theinput){
return theinput*2;
};
return 'the result is '+ b(param);
};
- 1
- 2
- 3
- 4
- 5
- 6
当我们调用全局函数a()时没,本地函数b()也会再其内部被调用,由于b()是本地函数,它在a()以外的地方是不可见的,所以称它为私有函数。它的优势有:
- 有助于确保全局名字空间的纯净性(就是命名冲突的几率小)
- 私有性——可以选择只将一些必要的函数暴露给外部,并保留属于自己的函数,使得它们不能被程序的其他部分所用
返回函数的函数
函数始终都会有一个返回值,即便不是显式返回也会隐式返回一个undefined。既然函数能返回一个唯一的值,那么这个值也有可能是另一个函数:
function a(){
alert('A!');
return function(){
alert('B!');
};
}
- 1
- 2
- 3
- 4
- 5
- 6
函数a()会在执行说A之后返回另一个函数b(),而b()又会去执行另外一些事情说B,我们吧该返回值赋值给某个变量,然后就可以向向使用一般函数一样调用它了。
function a(){
alert('A!');
return function(){
alert('B!');
};
}
var newFunc = a();
newFunc()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
如执行结果所示,第一行执行的是A,第二行是B,若是想让返回的函数立即执行,也可以不用将它赋值给变量,直接在该调用函数再加一对括号就可以:
a()()
- 1
重写自己的函数
一个函数可以返回另一个函数,因此可以用新的函数来覆盖旧的函数,比如上个例子,可以通过a()的返回值来重写a()函数自己。
a = a();
- 1
当前这句依然只会执行alert(”A!”),但是我们再次调用a(),就会执行alert(“B!”)了。我们也可以让函数从内部重写自己:
function a(){
alert('A!');
a=function(){
alert('B!');
};
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
一个综合实例:
var a = function(){
function someSetup(){
var setup = 'done';
}
function actualWork(){
alert('Worky-worky');
}
someSetup();
return actualWork;
}();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
在这个函数中使用了私有函数:someSetup()和actualWork()
使用了自调函数:函数a()的定义后面有一对括号,会执行自行调用。
当该函数第一次被调用时,会调用someSetup()函数,并返回函数变量actualWork的引用,注意返回值是不带括号的,因此这个结果仅仅是一个函数的引用,并没有执行函数不会产生函数调用。这里执行的语句是以var a = 开头的,因而该自调函数所返回的值会重新赋值给a