函数表达式
定义函数的两种方式
函数声明:
function functionName(arg0, arg1, arg2) {
//函数体
}
利用函数声明方式定义的函数,有一个重要特征函数声明提升
sayHi(); //可以把函数声明放在调用它的语句后面
function sayHi(){
alert("Hi!");
}
函数表达式
var functionName = function(arg0, arg1, arg2){
//函数体
};
创建的一个函数将其赋值给一个变量
这种函数叫匿名函数(拉欧姆函数)
sayHi(); //错误:函数还不存在
var sayHi = function(){
alert("Hi!");
};
闭包
闭包是指有权访问另一个函数作用域中的变量的函数。(啥意思?)
通俗点就是:
闭包是一个函数,这个函数可以访问另一个函数中的变量。
如何创建闭包
在一个函数中创建另一个函数。
function createComparisonFunction(propertyName) {
return function(object1, object2){ //这个匿名函数是一个闭包
var value1 = object1[propertyName]; //可以访问外层函数的propertyName
var value2 = object2[propertyName];
if (value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else {
return 0;
}
};
}
为什么内部函数可以访问外部函数的变量?
内部函数的作用域链包含外部函数的作用域链。
几个名词
- 执行环境:函数被调用时,会创建一个执行环境以及相应的作用域链
- 作用域链:一个指向变量对象的指针列表
- 活动对象:一个对象,包含arguments和其他命名参数
- 全局变量对象:
//创建函数
var compareNames = createComparisonFunction("name");
//调用函数
var result = compareNames({ name: "Nicholas" }, { name: "Greg" });
从图中可以看到:
内部函数包含外部函数的作用域链,因此内部函数被返回时,也可以访问到外部函数的变量。
还可以看到:
闭包会携带其他函数的作用域,因此会占用更多的内存。
闭包与变量
一个经典的题目
function func() {
var result = new Array();
for(var i = 0; i < 10; i ++){
result[i] = function() {
return i;
}
}
return result;
}
var res = func();
console.log(res[0]()); //此时的结果是什么?
func函数中返回了10个闭包,每个闭包都会包含func的活动对象—— i ,
在执行完循环体后,i的值就变成了10 ,所以这10个闭包的返回值都是10。
如果想返回0,1,2,3,4,5,6,7,8,9该怎么办
- 再增加一层闭包
- 立即执行函数
function func2() {
var result = new Array();
for(var i = 0; i < 10; i++) {
result[i] = function(num){ //立即执行函数
return function() { //result得到的是这一层闭包
return num;
}
}(i);
}
return result;
}
var res2 = func2();
console.log(res2[0]()); // 0
块级作用域
可以利用闭包和立即执行函数创建一个块级作用域
(function(){
//这里是块级作用域
})();
(function(){})
利用圆括号包起来代表函数表达式,函数表达式后再接一个圆括号代表立即执行函数。
function(){}()
这种写法是错的,以function开头代表函数声明,函数声明不能跟圆括号
私有变量
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"
getName(),setName()为Person的闭包,闭包的作用域包含它自己的作用域、包含函数的作用域和全局作用域。
模块模式
为单例创建私有变量和特权方法。
单例:只有一个实例的对象。
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 application = function(){
//私有变量和函数
var components = new Array();
//初始化
components.push(new BaseComponent());
//创建application 的一个局部副本
var app = new BaseComponent();
//公共接口
app.getComponentCount = function(){
return components.length;
};
app.registerComponent = function(component){
if (typeof component == "object"){
components.push(component);
}
};
//返回这个副本
return app;
}();