继承是面向对象语言中的一个最为人津津乐道的概念。许多面向对象语言都支持继承,JS没有明确的继承机制,而是通过模拟实现的。由于JS语言的灵活性,有下列几种方式可以实现继承:
1. 使用对象冒充实现继承
// 父构造函数
function Parent(name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log("my name is " + this.name + ", i am " + this.age + " years");
}
}
// 子构造函数
function Child(name, age) {
this.super = Parent; // 将父构造函数当做子构造函数的一个方法
this.super(name, age); // 执行这个方法就相当于执行了Parent
}
var child = new Child('xiaoming', 18);
console.log(child.name); // xiaoming
console.log(child.age); // 18
child.say(); // my name is xiaoming, i am 18 years
实现原理:使父构造函数成为子构造函数的一个方法,调用子构造函数的方法,通过this给所有的属性和方法赋值。
2.原型链继承
// 父构造函数
function Parent() {
this.say = function() {
console.log("my name is " + this.name + ", i am " + this.age + " years, i have " + this.money +"$.");
}
}
Parent.prototype.hello = function() {
console.log('hello world!');
}
// 子构造函数
function Child(name, age, money) {
this.name = name;
this.age = age;
this.money = money;
}
Child.prototype = new Parent(); //
var child = new Child('xiaoming', 18, 100);
console.log(child.name); // xiaoming
console.log(child.age); // 18
child.say(); // my name is xiaoming, i am 18 years, i have 100$.
child.hello(); // hello world!
缺点:包含引用类型值得原型属性会被所有实例共享;在创建子构造函数的实例时,不能向父构造函数中传递参数。
3.借用构造函数实现继承
// 父构造函数
function Parent(name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log("my name is " + this.name + ", i am " + this.age + " years.");
}
}
Parent.prototype.hello = function() {
console.log('hello world!');
}
// 子构造函数
function Child(name, age) {
Parent.call(this, name, age); // 通过call(apply也可以)改变Parent的执行环境,实现继承
}
var child = new Child('xiaoming', 18, 100);
console.log(child.name); // xiaoming
console.log(child.age); // 18
child.say(); // my name is xiaoming, i am 18 years
child.hello(); // error!!!
缺点:无法实现函数复用,也无法访问父类原型对象中定义的属性和方法。
4.组合继承
// 父构造函数
function Parent(name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log("my name is " + this.name + ", i am " + this.age + " years.");
}
}
Parent.prototype.hello = function() {
console.log('hello world!');
}
// 子构造函数
function Child(name, age) {
Parent.call(this, name, age); // 继承Parent构造函数
}
Child.prototype = new Parent(); // 继承Parent原型中的属性和方法
var child = new Child('xiaoming', 18);
console.log(child.name); // xiaoming
console.log(child.age); // 18
child.say(); // my name is xiaoming, i am 18 years
child.hello(); // hello world!