函数表达式
模仿块级作用域
- JS和JAVA一个区别就在于JS没有块级作用域。看以下例子:
function outputNumbers(count){
for (var i=0; i < count; i++){
alert(i);
}
alert(i);
}
outputNumbers(5);
- 运行上面的例子会依次弹出0、1、2、3、4、5总共6个数字。学过编程语言都知道块级作用域的概念。一般在for条件中定义的i变量,在循环结束后外部代码是无法访问的(此时i通常已被销毁),但是在JS中却不同。不仅如此,假如你在循环外部重新声明了i变量,JS只会对这样的声明视而不见(不过,它会执行后续声明中的变量初始化)。因为这种性质的存在,我们可以用下面的方式模仿一个块级作用域。
(function(){
//块级作用域
})()
- 这种写法可能会导致困惑。其实可以这样理解。我们不过是用函数表达式取代了函数名,就像用具体值取代了变量名一样。
(function () {
alert("hello world!");
})();
var hello = function () {
alert("hello world!");
}
hello();
- 通过这种写法,我们可以稍微修改一下上面的例子,形成一个模仿块级作用域:
function outputNumbers(count){
(function () {
for (var i=0; i < count; i++){
alert(i);
}
})();
alert(i);
}
outputNumbers(5);
- outputNumbers中的匿名函数在这里其实是个闭包,所以它能访问外部作用域中的count。
- 这种做法拥有的好处是很好理解的。我们之所以有局部变量,而不全创建为全局变量是因为有些变量执行完毕后就没有了存在的意义,即可销毁。就像循环过程中的计数i一样。
私有变量
- JS中没有私有成员的概念,所有的对象属性都是公有的。不过倒是有私有变量的概念。任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数外部访问这些变量。看下面的例子:
function Person(name){
this.getName = function(){
return name;
};
this.setName = function (value) {
name = value;
};
}
var person = new Person("Nicholas");
alert(person.getName());
person.setName("Greg");
alert(person.getName());
- 上面这个例子用到了构造函数模式,第六章曾经提到过构造函数模式的缺点是针对每个实例都会创建同样一组新方法,因此可以使用静态私有变量来实现特权方法(就是例子中的getName、setName )。
静态私有变量
- 其实看着这个名字稍微想想就应该知道了。所谓的静态不过就是将方法放到了原型对象里,看下面的例子:
function Person(name){
}
Person.prototype.getName = function(){
return name;
};
- 但是调用结果并不是我们想象的那样,因为原型对象根本访问不到Person实例中的name变量!那我们只好借助前面的模仿块级作用域了。然后将静态变量存放到块级作用域中。
var Person;
(function () {
var name;
Person = function(pname){
name = pname;
};
Person.prototype.getName = function(){
return name;
};
Person.prototype.setName = function(pname){
name = pname;
};
})();
var person = new Person("Nicholas");
alert(person.getName());
person.setName("Greg");
alert(person.getName());
var person2 = new Person("miaoch");
alert(person.getName());
alert(person2.getName());
- 这种做法也会大大影响速度。调用getName方法找了两次,找到了原型对象中的getName(),然后又需要返回name(注意不是this.name),先是在原型对象中的getName()中查找name找不到又到模仿块级作用域中找,然后找到了。
模块模式
- 前面的模式是用于为自定义类型创建私有变量和特权方法的。而模块模式则是为单例创建私有变量和特权方法。单例是指只有一个实例的对象。JS中一般以对象字面量方式来创建单例对象。
var singleton = function (){
var privateVariable = 10;
function privateFunction() {
return false;
}
return {
publicProperty: true,
publicMethod: function () {
privateVariable++;
return privateFunction();
}
};
}
增强的模块模式
- 模块模式一个缺点就是返回的对象始终都是Object类型的。如果要求必须返回是某个类型,则可以用增强的模块模式
function BaseComponent(){
}
function OtherComponent(){
}
var application = function(){
var components = new Array();
components.push(new BaseComponent());
var app = new BaseComponent();
app.getComponentCount = function(){
return components.length;
};
app.registerComponent = function(component){
if (typeof component == "object"){
components.push(component);
}
};
return app;
}();
alert(application instanceof BaseComponent);
application.registerComponent(new OtherComponent());
alert(application.getComponentCount());