1.在ES5中函数定义有两种方式:
函数声明: function functionName(arg){}
函数表达式:var functionName = function(arg){}
这两种方式定义的函数都可以使用,但是他们还是有一些区别的
1.函数声明方式定义的函数,会有函数声明提升的,即你可以在函数声明之前调用改函数,而函数表达式定义的函数不可以
2.匿名函数,匿名函数顾名思义就是其函数没有方法名字
function createCompareFunction(property){
return function (obj1,obj2){
var value1 = obj1[property];
var value2 = obj2[property];
if (value1 < value2){
return -1;
}else if (value1 > value2){
return 1;
}else{
return 0;
}
}
}
如上代码所示,createCompareFunction就会返回一个匿名函数
3 es5中的递归函数,可以使用arguments.callee(这个指向了当前正在执行的函数)来实现,避免函数表达式被赋值为其他,也可以使用命名函数表达式的方法
var factor = (function f (num){
if (num <=1){
return 1;
}else{
return num * f(num-1);
}
});
4.函数自执行
(function (name){
console.log(name);
}('xindi'));
如下实现,这个匿名函数会马上执行
5.闭包
闭包是指能有权访问另一个函数作用域中的变量的函数.
闭包在执行的时候,会使用arguments和其他的命名参数创建自己的活动对象,闭包的作用域链中会包含外部函数的活动对象,当在函数中访问一个变量时,就会从其作用域链中搜索直到找到为止.所以这就是闭包为什么可以访问其外部函数的变量.
ps:this对象和arguments对象只会搜索自己的活动对象,不会去访问外部函数的活动对象.
但是闭包作用域链中保存的是整个的活动对象,而不是某个特殊的变量,所以当闭包执行之后你可能得到的并不是你想要的结果,例如
function createFunctions (){
var newArr = new Array();
for (var i = 0;i<10;i++) {
newArr[i] = function (){
return i
}
}
return newArr;
}
createFunctions().map(function(item){
let result = item();
console.log(result);
});
这个例子中item就是闭包,每个item都都包含了createFunctions的活动对象,但其实每个item引用的都是同一个活动对象.当createFunctions执行完毕之后createFunctions内部的变量I值为10,此时item(闭包)包含的活动对象中I的值也是10.所以得到的结果会都是10;
当然我们也可以采用其他的方式来避免这种情况,如果一定要使用闭包的话,可以采取下面的方式:
function createFunctions (){
var newArr = new Array();
for (var i = 0;i<10;i++) {
newArr[i] = function (num){
return function(){
return num;
}
}(i)
}
return newArr;
}
createFunctions().map(function(item){
let result = item();
console.log(result);
});
这个方式我们采取自执行函数,让闭包返回的变量i的副本.
在闭包中我们还需要关注另一个问题就是this对象和arguments对象.this和arguments对象只会在本身的活动对象去寻找,所以当有闭包的时候,闭包内部访问的this和arguments对象可能不是你想要的.
我们可以有以下几种解决方案:
1.将this和arguments对象用另一个变量保存下来,在闭包内部访问你保存的那个对象
2.借用bind函数,创建一个this对象为你传入的新函数.
3.借用call 或 apply 改变闭包内部的执行环境
6.es5中模仿块级作用域的变量,在es6中,实现let 和const两个块级作用域的变量,但是在es5中只有var,var声明的作用域是非块级的.不过我们可以使用闭包来模仿此行为
(function(){
var i = 0;
}())
如上所示,我们声明了一个匿名的自执行函数,这样在这个函数内部的变量都会只在此函数内部生效,类似块级的变量.
7.私有变量,严格意义上来说在js中并不存在私有变量,但是我们可以通过不同的方式来实现类似私有变量
1.特权方法:
function Person(){
var priviteVar = 10;
function privateFunc (){
console.log(priviteVar);
return 'lsh';
}
this.publicFunc = function(){
priviteVar += 1;
return privateFunc();
}
}
这样实现的结果就是priviteVar 和privateFunc都只能通过publicFunc来访问
2.静态私有变量:
(function(){
var priviteVar = 10;
function privateFunc(){
priviteVar += 1;
return 'lsh'+priviteVar;
}
Person = function (name){
this.name = name;
}
Person.prototype.publicFunc = function (){
return privateFunc();
}
}())
上面的实现,构造函数和priviteVar都处于同一个函数环境下,这样priviteVar就会成为一个静态变量,也就是你调用构造函数创建多个对象,其仍然共享同一个priviteVar.
8.模块模式
有时候程序中我们会需要一个单利对象来管理程序的一些信息,同时这个单利对象我们可能需要有它的私有变量,那么我们可以使用模块模式来实现
var single = function (){
var privateVar = 10;
function privateFunc (){
return 'lsh';
}
var obj = new Object();
obj.publicProperty = false;
obj.publicFunc = function (){
privateVar += 1;
return privateFunc();
}
return obj;
}
这样我们可以得到一个单利对象,同时这个对象有自己的私有方法和属性,也有着公有方法和属性;