- 函数表达式的特征
- 使用函数实现递归
- 使用闭包定义私有变量
1. 递归
argument.callee:一个指向正在执行函数的指针,严格模式下会出错
命名函数表达式,严格和非严格都不会出错
var factorial = (function f(num){
if (num <= 1){
return 1;
}else {
return num * f(num - 1);
}
});
2. 闭包
闭包是指有权访问另一个函数作用域中变量的函数
创建闭包的常见方式:在一个函数内部创建另一个函数
过度使用闭包会导致内存占用过多,要慎重使用
2.1 闭包与变量
闭包只能取得包含函数中任何变量的最后一个值
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(){
return i;
};
}
return result;
}
表面看每个函数都返回自己的索引值,实际上每个函数都返回10
因为每个函数的作用域链中都保存着createFunctions()函数的活动对象,它们引用同一变量
可以创建另一个匿名函数让闭包行为符合预期
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(num){
return function(){
return num;
};
}(i);
}
return result;
}
2.2 关于this对象
匿名函数的执行环境具有全局性,this对象通常指向window
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); //"The Window"
把外部作用域中的this对象保存到闭包能够访问到的变量中
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); //"MyObject"
2.3 内存泄漏
如果闭包的作用域链保存着一个HTML元素意味着该元素将无法被销毁
function assignHandler(){
var element = document.getElementById("someElement");
element.onclick = function(){
alert(element.id);
};
}
匿名函数对assignHandler()活动对象的引用,element引用次数最少是1,占用内存无法被回收
修改代码解决内存泄漏问题
function assignHandler(){
var element = document.getElementById("someElement");
var id = element.id;
element.onclick = function(){
alert(id);
};
element = null;
}
3. 模仿块级作用域
(function(){
//这里是块级作用域
})();
匿名函数中定义的变量执行后销毁
不会搞乱全局作用域
4. 私有变量
私有变量包括函数的参数,局部变量和函数内部定义的其他函数
特权方法:有权访问私有变量和私有函数的公有方法成为特权方法
4.1 静态私有变量
静态的,由所有实例共享的属性
(function(){
var name = "";
Person = function(value){
name = value;
};
Person.prototype.getName = function(){
return name;
};
Person.prototype.setName = function (value){
name = value;
};
})();
var person1 = new Person("Nicholas");
alert(person1.getName()); //"Nicholas"
person1.setName("Greg");
alert(person1.getName()); //"Greg"
var person2 = new Person("Michael");
alert(person1.getName()); //"Michael"
alert(person2.getName()); //"Michael"
4.2 模块模式
模块模式:为单例创建私有变量和特权方法
单例:只有一个实例的对象
JavaScript中用对象字面量的方式创建单例对象
如果创建一个对象并以某些数据对其初始化,同时还要公开一些访问私有数据的方法,就可以用模块模式
function BaseComponent(){
}
function OtherComponent(){
}
var application = function(){
//private variables and functions
var components = new Array();
//initialization
components.push(new BaseComponent());
//public interface
return {
getComponentCount : function(){
return components.length;
},
registerComponent : function(component){
if (typeof component == "object"){
components.push(component);
}
}
};
}();
application.registerComponent(new OtherComponent());
alert(application.getComponentCount()); //2
4.3 增强的模块模式
返回对象之前加入对其增强的代码
适合单例必须是某种类型的实例,同时还必须添加某些属性和方法对其加以增强的情况
function BaseComponent(){
}
function OtherComponent(){
}
var application = function(){
//private variables and functions
var components = new Array();
//initialization
components.push(new BaseComponent());
//create a local copy of application
var app = new BaseComponent();
//public interface
app.getComponentCount = function(){
return components.length;
};
app.registerComponent = function(component){
if (typeof component == "object"){
components.push(component);
}
};
//return it
return app;
}();
alert(application instanceof BaseComponent);
application.registerComponent(new OtherComponent());
alert(application.getComponentCount()); //2