函数表达式
- 也称为匿名函数
- 常见语法
var functionName=function(){}; - 函数表达式必须在调用前进行赋值
- 在把函数当成值来使用的情况下,都可以使用匿名函数
递归
- 编写递归函数时,使用
arguments.callee代替函数名 - 严格模式下不能使用
arguments.callee - 使用命名函数表达式解决
var factorial=(function f(num){
if(num<=1){
return 1;
}else{
return num*f(num-1);
}
});
闭包
- 有权访问另一个函数作用域中变量的函数
- 常见方式是在函数内部创建另一个函数
- 内部函数能访问外部函数的变量。内部函数的作用域链中包含了外部函数的作用域
- 在某个函数被创建时,会创建其作用域链并保存在函数的[[Scope]]属性中
- 在某个函数被调用时,会创建其执行环境,并从[[Scope]]属性中复制变量对象构建执行环境的作用域链。最后将该函数的活动对象创建并推入执行环境作用域链的前端
- 作用域链的本质是一个保存着指向变量对象的指针列表
- 当外部函数返回时,将执行环境销毁,即将作用域链进行销毁。若作用域链中指向的各个活动对象没有其他指针指向,那么就将这个对象销毁。内部函数的作用域链中存在指向外部函数变量对象的指针,所以外部函数的变量对象仍然会留存在存在中,所以内部函数能够访问外部函数的变量并且在外部函数返回后仍能访问外部函数的变量。
- 闭包的副作用:闭包只能取得包含函数中任何变量的最后一个值
- 创建另外一个匿名函数强制让匿名函数的行为符合预期
- 匿名函数的执行环境具有全局性,其this对象指向window
- 闭包的内存泄漏问题。由于element的元素存在有指向匿名函数的引用,而匿名函数存在有指向element的引用,造成循环引用问题。
- 解决办法是在外部函数保存变量,并且在闭包中引用该变量
function assignHandler(){
var element=document.getElement("someElement");
element.onclick=function(){
alert(element.id);
}
}
块级作用域
- 定义匿名函数并立马调用,实现块级作用域
(function(){
//块级作用域
})();
- 隔离全局作用域和私有作用域。避免了命名冲突
- 也可以减少闭包占用内存的问题
私有变量
- JavaScript中没有私有成员的概念,但是在函数中定义的变量都可以认为是私有变量
- 私有变量包括函数的参数,局部变量和内部函数
- 特权方法:指能够访问私有变量和私有函数的方法
- 构造函数中定义特权方法。其缺点是构造函数中定义的方法在每个实例中不共享
function Person(name){ this.getName=function(){ return this.name; }; this.setName=function(name){ this.name=name; }; }- 在私有作用域中定义私有变量或函数
- 私有作用域中封装构造函数和方法
- 使用函数表达式定义构造函数,这样
MyObject成为全局变量,能够在私有域之外被访问到 - 公有方法定义在原型上,使得所有实例能够共享方法
- 公有方法作为闭包,一直保持着对私有域的引用,因此能够访问到私有变量和私有函数
- 但是所有实例都没有自己的私有变量,它们共享静态私有变量
(function(){ //私有变量 var privateVar=10; //私有函数 function privateFunc(){ return false; } //构造函数 MyObject=function(){ }; //公有方法 MyObject.prototype.publicMethod=function(){ privateVar++; return privateFunc(); } })- 模块模式(module pattern)
- 为单例创建私有变量和特权方法
- 使用一个返回对象的匿名函数,在匿名函数中定义私有变量和私有方法。在返回的对象字面量中定义公有属性和公有方法
- 在需要对单例进行初始化,又要维护其私有变量时很有用
var application=function(){ //私有变量和函数 var components=new Array(); //初始化 components.push(new BaseComponent()); //公共 return { getComponentCount:function(){ return components.length; }, registerComponent:function(component){ if(typeof component=="object"){ components.push(component); } } } }- 增强的模块模式
- 单例必须是某种类型的实例,同时还必须添加某些属性和(或)方法对其加以增强的情况
var singleton=function(){ //私有变量和函数 var privateVar=10; function privateFunc(){ return false; } //创建副本 var o=new CustomType(); //添加增强属性 o.publicProperty=true; //添加增强方法 o.publicMethod=function(){ privateVar++; return privateFunc(); } //返回这个副本 return o; }();