对象冒充
原理
构造函数使用this关键字给所有属性和方法赋值(即采用类生命的构造函数方式)。因为构造函数只是一个函数,所以可以使classA构造函数成为classB的方法,然后调用它。classB就会收到classA中定义的属性和方法。
function classA(sColor) { this.color = sColor; this.sayColor = function() { alert(this.color); } } function classB(sColor, sName) { this.newMethod = classA; this.newMethod(sColor); delete this.newMethod; // 所有新属性和新方法都必须在删除了新方法的代码行后定义。 this.name = sName this.sayName = function() { alert(this.name); } } var objA = new classA("blue"); var objB = new classB("red", "John"); objA.sayColor(); //输出 "blue" objB.sayColor(); //输出 "red" objB.sayName(); //输出 "John"
弊端
对象冒充支持多重继承,一个类可以继承多个超类。这样会产生一个弊端,
如果存在两个类 ClassX 和 ClassY 具有同名的属性或方法,ClassY 具有高优先级。因为它从后面的类继承。
除这点小问题之外,用对象冒充实现多重继承机制轻而易举。function classB() { this.newMethod = classX; this.newMethod(); delete this.newMethod; this.newMethod = classY; this.newMethod(); delete this.newMethod; }
由于这种继承方法的流行,ECMAScript 的第三版为 Function 对象加入了两个方法,即
call()
和apply()
。
原型链 prototype chaining
原理
prototype 对象的任何属性和方法都被传递给那个类的所有实例。原型链利用这种功能来实现继承机制。
function classA(){} classA.prototype.color = 'red' classA.prototype.sayColor = function() { alert(this.color) } function classB(){} classB.prototype = new classA(); // 调用 classA 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。 classB.prototype.name = ""; classB.prototype.sayName = function() { alert(this.name); } var objA = new classA(); var objB = new classB(); objA.color = 'blue' objB.color = 'red' objB.name = 'Kevin' objA.sayColor(); // blue objB.sayColor() // red objB.sayName() // Kevin
弊端
原型链的弊端是不支持多重继承。记住,原型链会用另一类型的对象重写类的 prototype 属性。
混合方式
原理
用对象冒充继承构造函数的属性,用原型链继承prototype对象的方法。
function classA(sColor){ this.color = sColor; } classA.prototype.sayColor = function() { alert(this.color); } function classB(sColor, sName){ classA.bind(this, [sColor]); this.name = sName; } classB.prototype = new ClassA(); classB.prototype.sayName = function(){ alert(this.name) } // 运行 var objA = new classA('blue') var objB = new classB('red', 'Kevin') objA.sayColor(); // blue objB.sayColor() // red objB.sayName() // Kevin