函数表达式
定义的方式:
function functionName(函数名)(arg0,arg2,arg3){
//函数体
}
var functionName=function(arg0,arg1,arg2){
//函数体
}; //注意后面的分号,不能省略,省略会导致错误
一.函数声明
1.函数声明对函数的调用与产生的结果会有很大的影响。
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 </head> 6 <body> 7 <script type="text/javascript"> 8 sayHi(); 9 function sayHi(){ 10 alert("hello word"); 11 } 12 </script> 13 </body> 14 </html>
如果删除script里面的函数声明,则不能弹出内容。函数声明无论放在function定义的函数前面还是后面都可以正确产生结果。
因为函数声明中的函数声明提升会先读取函数声明,再执行函数。但是函数声明不能省略。
二.函数表达式
(1)匿名函数(anonymous function,或拉姆达函数):function关键字后无标识符,name属性值为空字符串。在把函数当成值使用时,都可用匿名函数。
(2)类似其他表达式,函数表达式使用前需先赋值,故不存在"函数声明提升"那样的作用。
(3)ECMAScript中的无效函数语法:
(4)函数表达式
三.递归(通过函数调用自身的情况下构成的)
对于经典的求阶乘函数:
1 function factorial(num){ 2 if(num<=1){ 3 return 1; 4 } 5 else { 6 return num*arguments.callee(num-1); 7 } 8 9 var result=factorial; 10 factorial=null; 11 alert(result(5));
可以看出,里面使用的变量就是在函数定义中的参数,在声明函数是也可以看出,函数是在调用自己,即使有了一个中间变量。
但是如果在输出是将里面的result改为factorial,就会出现错误,所以result变量在递归中是必不可少的
三.闭包
1.闭包有权访问另一个函数作用域中的变量的函数(在函数体内部创建),但是匿名函数就是创建一个函数。
2.
闭包用处:
(1)闭包是可访问上一层函数作用域里变量的函数,即便上一层函数已经关闭,在函数外部不能得到函数的局部变量,但是闭包可以。
1 var name = "The Window"; 2 var object = { 3 name : "My Object", 4 getNameFunc : function(){ 5 return function(){ 6 return this.name; 7 }; 8 } 9 }; 10 alert(object.getNameFunc()());
function里面的name是访问其外部匿名函数中的name,所以alert里面电泳函数实际上就是通过闭包获取name,再返回得到值,在进行输出。
(2)一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。(会占用更多的内存)
注意:函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量
function outerFun() { var a=0; function innerFun() { a++; alert(a); } return innerFun; //注意这里 } var obj=outerFun(); obj(); //1 obj(); //2 var obj2=outerFun(); obj2(); //1 obj2(); //2
在这段代码中,是想通过函数调用outerFun()获取a的值,innerFun()的作用域在outerFun外部,但是通过创建闭包,所以能够获取到外部的变量,如果没有闭包就会出错
3.this 对象
1 var name="The window"; 2 name:"My object"; 3 getNameFunc:function(){ 4 var that=this; 5 return function(){ 6 return that.name; 7 8 }; 9 } 10 }; 11 alert(object.getNameFunc()());
在这个例子中,将this赋值给THAT,通过that在闭包中调用。通过闭包仍然可以调用闭包外面的object,可以获取name值。
在一些情况下,语法的不同会导致结果不同。
4.IE有的版本对于垃圾收集使用了不同的对象,所以对于闭包会出现一些问题。因为闭包会保存不会被销毁,所以内存永远不会被回收。所以需要将元素变量设置为null,可以解除引用,回收内存,避免闭包占用过多的内存。
四、私有变量
在函数中定义的变量,因为在外部不能访问,所以可以看成私有变量,
例:function add(num1,num2){
var sum=num1+num2;
return sum;
}
因为函数add内部的变量num1,num2,sum,在外部都不能被访问,所以是私有变量。(使用闭包可以将函数里面的私有变量变为公有)
2.对于私有变量和函数,可以使用特权方法在外部进行访问,但是这种方法总是使用构造函数,所以每个实例都要创建同一组方法。
五、静态私有变量
静态私有变量可以解决私有变量对于一个实例就要创建一组新方法的缺点,在其中通常不会创建局部函数,而是创建全局的函数。这种方法使私有变量和函数是由实例共享的,实例使用一个函数,就避免了重新创建很多相同的函数。(这种方法是一个闭包,保存着包含作用域的引用),但是对于静态自由变量的使用,需要视需求而定。
1 (function(){ 2 3 var name = ''; 4 5 Person = function(value){ 6 name = value; 7 } 8 9 Person.prototype.getName = function(){ 10 return name; 11 } 12 13 Person.prototype.setName = function(value){ 14 name = value; 15 } 16 })(); 17 18 var person1 = new Person('Tom'); 19 alert(person1.getName()); 20 var person2 = new Person('jack'); 21 alert(person2.getName()); 22 console.log(person1.getName());//jack 23 console.log(person2.getName());//jack 24 alert(person1.getName()); 25 alert(person2.getName());
以上这个例子就使用了两个构造函数getName()和setName(),但是他们的方法一样,都有访问私有变量name的权利,变量name就变成了一个静态的、所有实例共享的属性。也就是在一个实例上调用setName()会影响所有的实例。结果会返回相同的值。
六.模块模式
1.模块模式为单例创建私有变量和特权方法,只有一个实例对象,是一种全局变量。
2.这种模式需要对默写内容初始化。