函数执行环境和作用域链
要理解JavaScript,必须理解函数执行环境与作用域链(栈)!!
ES5以函数作为执行环境的划分,代码执行从外部到内部,执行环境从外部环境到内部环境依次堆栈,每个函数执行完毕,其执行环境对应的则出栈。
闭包:内部执行环境引用了外部执行环境中的变量,因此外部执行环境的变量不会被销毁。
关于this和that的问题
函数调用时,会搜索谁调用了这个函数。
var name = "The window";
var obj = {
name: "My obj",
getName: function(){
return function(){
return this.name;
}
}
}
alert(obj.getName()()); // "The window"
由于调用getName返回的是匿名函数,匿名函数直接运行时,没有人调用它,因此它的this指向window。
假如:
var obj = {
name: "My obj",
getName: function(){
return function(){
return this.name;
}
}
}
obj.test = obj.getName();
obj.test() // “My obj“
或者:
var obj = {
name: "My obj",
getName: function(){
var that = this;
return function(){
return that.name;
}
}
}
obj.getName()(); // "My obj"
模仿块级作用域
由于JS没有块级作用域,而是以函数范围作为作用域划分。所以可以用以下方法模仿块级作用域,使用匿名立即执行函数来创建块级作用域。
(function(){
//这里是块级作用域
})()
由于JS将function关键字当作函数声明的开始,因此不能直接在函数声明后加()
而是应该用()
包住函数。
当在全局环境使用该方式时,可以创建自己的私有环境,避免向全局注入过多函数和变量。这在多人协作中很重要。
私有变量和公有方法
构造函数模式
由于函数内部的变量对于外部不可访问,因此可以使用函数来创建私有变量,使用闭包来创建公有方法
function MyObject() {
var privateVar = 20; // 私有变量
this.getName = function() { //公有方法
return privateVar;
};
this.setName = function(value) { //公有方法
privateVar = value;
};
}
注意,不能写成以下函数:
function MyObject() {
this.privateVar = 20; // 公有变量
this.getName = function() { //公有方法
return this.privateVar;
};
this.setName = function(value) { //公有方法
this.privateVar = value;
};
}
只要加上this,那么变量就将成为构造函数构造出来的对象的一个可以访问的属性。
这种方法的缺点在于,对于每一个变量都会创建一组相同的新方法。
静态私有变量
创建一个所有实例共享的私有变量和公有方法
//立即执行函数创建私有域
(function(){
//静态私有变量
var name = "";
//构造函数
//Person为全局变量方便外部访问
Person = function(value) {
name = value;
};
//所有实例的共享方法
Person.prototype.getName = function(){
return name;
};
Person.prototype.setName = function(){
name = value;
};
})();
模块模式(单例模式)
例子:一个管理组件的application。
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);
}
}
}
}