4.1 继承机制的实现
出于安全原因,本地类和宿主类不能作为基类,这样可以防止公用访问编译过的浏览器级的代码,因为这些代码可以被用于恶意攻击。
4.1.1 继承的方式
1.对象冒充(Object masquerading)
原理如下:构造函数使用this关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使ClassA的构造函数成为ClassB的方法,然后调用它。ClassB就会收到ClassA的构造函数中定义的属性和方法。例如:
function ClassA(Color) {
this.color = Color;
this.sayColor = function () {
alert(this.color);
};
}
function ClassB(Color) {
}
这个方法中,this指向的是所属的对象。这个原理把ClassA作为常规函数来建立继承机制,而不是作为构造函数。使用构造函数ClassB可实现继承机制:
function ClassB(Color) {
this.newMethod = ClassA;
this.newMethod(Color);
delete this.newMethod;
}
2.call()方法
该方法与经典的对象冒充方法最相似。它的第一个参数用作this的对象。其它参数都直接传递给函数自身。例如:
function sayColor(Prefix, Suffix) {
alert(Prefix + this.color + Suffix);
};
var obj = new Object();
obj.color = “red”;
//输出 “The color is red, a very nice color indeed. “
sayColor.call(obj, “The color is “, “, a very nice color indeed. “);
调用call()方法时,第一个参数是obj,说明应该赋予sayColor()函数中的this关键字值是obj。第二个和第三个参数是字符串。它们与sayColor()函数中的参数prefix和suffix匹配。
要与继承机制的对象冒充方法一起使用,只需将前三行的赋值、调用和删除代码替换即可:
function ClassB(Color, Name) {
//this.newMethod = ClassA;
//this.newMethod(Color);
//delete this.newMethod;
ClassA.call(this, Color);
}
3.apply()方法
该方法有两个参数,用作this的对象和要传递给函数的参数的数组。例如:
function sayColor(Prefix, Suffix) {
alert(Prefix + this.color + Suffix);
};
var obj = new Object();
obj.color = “red”;
//输出 “The color is red, a very nice color indeed. “
sayColor.apply(obj, new Array(“The color is “,”, a very nice color indeed.”));
调用apply()方法时,第一个参数仍是obj,说明应该赋予sayColor()中的this关键字值是obj。第二个参数是由两个字符串构成的数组,与prefix和suffix匹配。
同样的,该方法也可以与对象冒充方法一起使用。
4.原型链(Prototype chaining)
利用了对象的prototype属性,可把它看成创建新对象所依赖的原型。先用空构造函数来设置类名,然后所有的属性和方法都被直接赋予prototype属性。
Prototype对象就是一个模板,要实例化的对象都以这个模板为基础,该对象的任何属性和方法都被传递给那个类的所有实例。原型链利用了这种功能来实现继承机制:
function ClassA() {
}
ClassA.prototype.color = “red”;
ClassA.prototype.sayColor = function () {
alert(this.color);
};
function ClassB() {
}
ClassB.prototype = new ClassA();
注意,调用ClassA的构造函数时,没有给它传递参数,这在原型链中是标准做法。要确保构造函数没有任何参数。
5.混合方式
对象冒充的问题是必须使用构造函数方式。如果使用原型链就无法使用带参数的构造函数。混合方式就是结合这两种方式。
用对象冒充继承构造函数的属性,用原型链继承prototype对象的方法。用这两种方式重写前面的例子:
function ClassA(sColor) {
this.color = sColor;
}
ClassA.prototype.sayColor = function () {
alert(this.color);
};
function ClassB(sColor, sName) {
ClassA.call(this, sColor);
this.name = sName;
}
ClassB.prototype = new ClassA();
ClassB.prototype.sayName = function () {
alert(this.name);
};
在此例中,继承机制由两行突出显示的代码实现。第一行代码中,在ClassB构造函数中,用对象冒充继承ClassA的sColor属性。第二行代码中,用原型链继承ClassA类的方法。由于这种混合方式使用了原型链,所以instanceof运算符仍能使用。
4.2 小结
介绍了ECMAScript中用对象冒充和原型链实现的继承概念,介绍了结合使用这些方式才是建立类之间继承机制的最好方式。