- 原文:Create Advanced Web Applications With Object-Oriented Techniques
- 译文(因文章较长,分多篇贴出,此篇为第3部分):
不用类的构造函数
正如我们注意到的,关于JavaScript面向对象编程的最奇怪之处就是,JavaScript不像C#或C++那样有类。在C#中,当你这样写:
Dog spot = new Dog();
会得到一个Dog类所实例化的对象。但JavaScript没有类可以让我们入手。最接近的方法是,你可以像这样定义一个构造函数:
function DogConstructor(name) {
this.name = name;
this.respondTo = function(name) {
if(this.name == name) {
alert("Woof");
}
};
}
var spot = new DogConstructor("Spot");
spot.respondTo("Rover"); // 不是这个
spot.respondTo("Spot"); // 啊,就是它了
那么,这里到底发生了什么事呢?让我们先把DogConstructor函数的定义放一边,来看看下面这行:
var spot = new DogConstructor("Spot");
这里”new”所做的事其实很简单。首先,它创建一个新的空对象,然后随之而执行的就是函数的调用,同时,这个函数的”this”的值就变成这个新的空对象了。换个说法,上面的用”new”操作符的那一行代码,可以相似地看作下面这两行:
// create an empty object
var spot = {};
// call the function as a method of the empty object
DogConstructor.call(spot, "Spot");
正如你所见,在DogConstructor里,对函数进行初始化,就会把”this”关键字映射到对象上。这样,你就有了一个为对象创建模板的方法了!无论何时,只要你用”new”去调用构造函数,得到的结果就是一个完全初始化了的对象。这听起来是不是和类一样呢?事实上,在JavaScript中,构造函数的名就是你所要模拟成的类的名,所以在上面的例子中你只要把构造函数命名为Dog就可以了:
// 把这个想像成Dog类
function Dog(name) {
// 实例的变量
this.name = name;
// 实例的方法
this.respondTo = function(name) {
if(this.name == name) {
alert("Woof");
}
};
}
var spot = new Dog("Spot");
在上面的Dog的定义中,我定义了一个名为name的实例级的变量。每一个使用Dog作为构造器创建的对象都有各自的实例级变量name(就像之前注意到的,这是通向对象字典的入口)。这也是我们所期望的,每一个对象都需要有自己的实例副本去保持它的状态。同样,每个实例同样拥有自己的respondTo方法副本,这真是一个浪费;你只需要一个respondTo 实例共享到所有Dog实例就行了!为了解决这个问题,我们可以在Dog的外部定义respondTo 方法,就像这样:
function respondTo() {
// respondTo 的定义语句
}
function Dog(name) {
this.name = name;
// 把函数作为实例的方法附上
this.respondTo = respondTo;
}
这样,所有Dog的实例(即所有用Dog构造函数创建的实例)都可以共享到同一个respondTo实例了。但随着方法的数量的增长,这种情况就会变得越来越难以维持。你在基础代码中大量停用全局函数后,事情只会变得更糟糕,因为你的”类”也变得越来越多,特别是这些类的方法名非常相似的时。更好的处理方法是使用原型对象,这也正是文章下一部分要讨论的话题。
To be Continued…


Leave a Reply