一.函数表达式的语法形式
- 匿名函数
-
1 var functionName = function(arg0, arg1, arg2) { 2 //函数体 3 }
二.函数表达式没有函数提升
1 var a = 1; 2 if(a != 1) { 3 function sayHi() { 4 console.log("Hi"); 5 } 6 } else { 7 function sayHi() { 8 console.log("Hello"); 9 } 10 } 11 sayHi(); //sayHi() is not defined
1 var say; 2 if (a == 1) { 3 say = function() { 4 console.log("Hi"); 5 } 6 } else { 7 say = function() { 8 console.log("Hello"); 9 } 10 } 11 say(); //Hi
二.使用函数实现递归
1 function f (num) { 2 if (num <= 1) { 3 return 1; 4 } else { 5 return num * f(num-1); 6 } 7 } 8 9 var otherF = f; 10 f = null; 11 console.log(otherF(1)); //1 12 console.log(otherF(4)); //error : f is not a function
1 function f2(num) { 2 if (num <= 1) { 3 return 1; 4 } else { 5 return num * arguments.callee(num-1); 6 } 7 } 8 9 var otherF = f2; 10 f2 = null; 11 console.log(otherF(1)); // 1 12 console.log(otherF(3)); // 6,严格模式下会出错
1 var f3 = (function ff(num) { 2 if (num <= 1) { 3 return 1; 4 } else { 5 return num * ff(num - 1); 6 } 7 }); //将函数表达式赋值给变量 8 console.log(f3(1)); // 1 9 console.log(f3(3)); // 6,严格模式和非严格模式都可以
三.闭包
- 闭包中外部函数在执行完毕后,其活动对象也不会被销毁,因为闭包中返回的内部函数的作用域链仍然在引用这个活动对象。直到匿名函数被销毁后,外部函数的活动对象才会被销毁。
- 作用域链的这种配置机制引出了一个值得注意的副作用,即闭包只能取得包含函数中任何变量的最后一个值。
-
1 function createFunction() { 2 var result = new Array(); 3 4 for (var i = 0; i < 10; i++) { 5 result[i] = function() { 6 return i; 7 }; 8 } 9 10 return result; 11 } 12 var re = createFunction(); 13 /* 14 re是一个函数数组,表面上看每个函数都要返回自己的索引值。 15 但实际上,每个函数都返回10.因为每个函数的作用域中对保存 16 着createFunction()函数的活动对象,所以它们引用的都是同一个变量i 17 */ 18 console.log(re[1]()); //10
-
1 function createFunction() { 2 var result = new Array(); 3 4 for (var i = 0; i < 10; i++) { 5 result[i] = function(num) { 6 return function() { 7 return num; 8 }//函数参数按值传递 9 }(i); 10 } 11 12 return result; 13 } 14 var re = createFunction(); 15 console.log(re[1]()); //1
四.模仿块级作用域
这种技术通常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。
而通过创建私有作用域,每个开发人员即可以使用自己的变量,又不必担心搞乱全局作用域。
1 (function () { 2 var now = new Date(); 3 console.log(now.getMonth()); 4 })();
五.私有变量
1.构造函数模式
1 function Person(name) { 2 this.getName = function() { 3 return name; 4 }; 5 6 this.setName = function(value) { 7 name = value; 8 } 9 } 10 11 var pserson = new Person("A"); 12 console.log(pserson.getName()); //A 13 pserson.setName("B"); 14 console.log(pserson.getName()); //B
【有权访问私有变量和私有函数的公有方法称为特权方法。能够在构造函数中定义特权方法,是因为特权方法作为闭包有权访问在构造函数中定义的所有变量和函数。
利用私有和特权成员,可以隐藏那些不应该被直接修改的数据。构造函数模式的缺点是针对每个实例都会创建同样一组新方法。】
2.通过私有作用域
1 (function() { 2 var name = ""; 3 Person = function(value) { 4 name = value; 5 }; 6 7 Person.prototype.getName = function() { 8 return name; 9 } 10 11 Person.prototype.setName = function(value) { 12 name = value; 13 } 14 })(); 15 16 var p1 = new Person("1"); 17 console.log(p1.getName()); //1 18 p1.setName("2"); 19 console.log(p1.getName()); //2 20 21 var p2 = new Person("3"); 22 console.log(p1.getName()); //3 23 console.log(p2.getName()); //3
【上面的例子中,变量name就变成了一个静态的,由所有实例共享的属性。以这种方式创建静态私有变量会因为使用原型而增加代码复用,但每个实例都没有自己的私有变量。】
六.单例模式
1 var application = function() { 2 //私有变量和函数 3 var components = new Array(); 4 5 //初始化 6 components.push(new BaseComponent()); 7 8 //公共 9 return { 10 getComponentCount : function() { 11 return components.length; 12 }, 13 14 registerComponent : function(component) { 15 if (typeof component == "object") { 16 components.push(component); 17 } 18 } 19 }; 20 }();
七. 增强的单例模式
【适合那些单例必须是某些类型的实例,同时还必须增加某些属性,方法对其加以增强的情况】
1 var application = function() { 2 //私有变量和函数 3 var components = new Array(); 4 5 //初始化 6 components.push(new BaseComponent()); 7 8 //创建application的一个局部副本 9 var app = new BaseComponent(); 10 11 //公共接口 12 app.getComponentCount = function() { 13 return components.length; 14 }; 15 16 app.registerComponent = function(component) { 17 if (typeof component == "object") { 18 components.push(component); 19 } 20 }; 21 22 return app; 23 }();