在前面说对象的时候已经提到了函数对象,对函数的定义参数的传递包括通过argumentd.callee实现递归。这篇博客我会继续深入讲解js中的函数表达式。
一,闭包
关于闭包的概念,可以先看看http://www.jb51.net/article/24101.htm,闭包是指有权访问另一个函数作用域中的变量的函数。在刚刚这个链接中对闭包的用法说的很清楚了,我感觉我没法说得比这个文章更简单更清楚了。但是,还是有几点很重要的东西这个文章没讲的,我补充一下。
1,变量
闭包只能取得包含函数中任何变量的最后一个值,举例就是
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(){
return i;
};
}
return result;
}
var funcs = createFunctions();
//every function outputs 10
for (var i=0; i < funcs.length; i++){
document.write(funcs[i]() + "<br />"); //输出10个10
}
但是,我们可以通过创建另一个匿名函数强制让闭包的行为符合预期
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(num){
return function(){
return num;
};
}(i);
}
return result;
}
var funcs = createFunctions();
//every function outputs 10
for (var i=0; i < funcs.length; i++){
document.write(funcs[i]() + "<br />");
}
原理就是在for循环里面增加一个匿名函数,然后把这个匿名函数的值返回给数组。在循环内部,在调用每个匿名函数时,就形成了闭包,i的值得到了保存并且存到了数组里面。
2,this对象
在闭包使用this对象可能导致一些问题:匿名函数的执行环境具有全局性,那么看例子
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); //"The Window"
有一种比较蠢的办法解决,就是先把包含作用域保存到另一个变量:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); //"MyObject"
3,内存泄露
实际上,闭包保存包含函数作用域的变量利用的就是前面说过的垃圾回收机制,所有被引用的变量都不会被回收,但是总是不回收势必导致一个问题,内存泄漏。解决办法也很简单,很普通的方法,释放该变量就行了。用完之后赋值null。
二,模仿块级作用域
前面说过了,js是没有块级作用域的。但是很多情况下我们需要一个私有作用域,这种情况下可以利用函数作用域来实现。先定义一个匿名函数,然后马上执行这个函数。
function outputNumbers(count){
(function () {
for (var i=0; i < count; i++){
alert(i);
}
})();
alert(i); //causes an error
}
值得注意的是,函数外部的小括号非常重要,加上这个小括号才能把函数声明转化成函数表达式,只有函数表达式才能在后面接小括号立即执行。
三,私有变量
函数内部的变量可以通过闭包的方式保存在内存中,而外部作用域是无法直接修改的,除非在函数内部增加修改这些变量的函数接口,这些接口就是特权方法。只有通过特权方法才能修改这些私有变量。
function Person(name){
this.getName = function(){
return name;
};
this.setName = function (value) {
name = value;
};
}
var person = new Person("Nicholas");
alert(person.getName()); //"Nicholas"
person.setName("Greg");
alert(person.getName()); //"Greg"
不过,在构造函数中定义特权方法让代码复用性很低,原因和前面说过的创建对象一样,构造函数每次实例时都会创建同样的一组新方法。下面介绍新的方法。
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"
alert(person1.name);
alert(person1.getName()); //"Greg"
var person2 = new Person("Michael");
alert(person1.getName()); //"Michael"
alert(person2.getName()); //"Michael"
2.模块模式
没搞明白,以后再说。