主要分为两部分,第一部分是ES5环境下的继承,另外一部分是ES6部分的继承,首先先看ES5,如何通过构造函数的形式实现继承。
1:原型链继承
function Foo(name) {
this.name = name;
}
Foo.prototype.age = function() {
console.log('父类:' + this.name);
};
function fn (name) {
this.name = name;
}
fn.prototype = new fn();
fn.prototype.age = function() {
console.log('子类:' + this.name);
};
var a = new fn('lisi');
a.age();
这种方法缺点比较明显,看起来很不直观,而且子类的方法不能优先于父类方法出现,通过new调用时,不能直接调用父类的构造函数而是要调用子类。
2:类式继承
function Foo(name) {
this.name = name;
}
Foo.prototype.age = function() {
console.log('父类:' + this.name);
};
Foo.prototype.obj = function() {
console.log('hello world');
};
function fn (name) {
Foo.call(this,name);
}
fn.prototype.age = function() {
console.log('子类:' + this.name);
};
var a = new fn('lisi');
a.age();
a.obj(); //TypeError: a.obj is not a function
这里通过call的方法,将this绑定在Foo构造函数上运行,但是会导致没有自己的原型对象,无法共享原型的方法和属性。
3:组合式继承
function Foo(name) {
this.name = name;
}
Foo.prototype.age = function() {
console.log('父类:' + this.name);
};
Foo.prototype.obj = function() {
console.log('hello world');
};
function fn (name) {
Foo.call(this,name); //第二次调用
}
fn.prototype = new Foo(); //第一次调用
fn.prototype.constructor = fn;
fn.prototype.age = function() {
console.log('子类:' + this.name);
};
fn.prototype.set = function() {
console.log('set si es5');
};
var a = new fn('lisi');
a.age();
a.obj();
a.set();
这是比较常用的继承方法,通过调用两次实现了继承,具备了原型链继承和类式继承的优点也可以自己定制方法或者属性。
不过缺点就是第一次调用Foo函数,实际上我们只是想获取原型,你可能在想如果通过
fn.prototype = Foo.prototype;
的方法实现,不过很可惜,这种方法是错误的,因为这会导致,两个函数的prototype属性发生改变,这显然是没有必要的。
这也是第四种继承的由来。
4:寄生组合式继承
function Foo(name) {
this.name = name;
}
Foo.prototype.age = function() {
console.log('父类:' + this.name);
};
Foo.prototype.obj = function() {
console.log('hello world');
};
function fn (name) {
Foo.call(this,name);
}
fn.prototype = Object.create(Foo.prototype);
fn.prototype.constructor = fn;
fn.prototype.age = function() {
console.log('子类:' + this.name);
};
fn.prototype.set = function() {
console.log('set si es5');
};
var a = new fn('lisi');
a.age();
a.obj();
a.set();
这里使用了Object.create()方法,事实上你也可以通过这种方法自己模拟一个,使用这种方法继承,可以让Foo这个函数只执行一次。
function Create(arr) {
function foo() {}
foo.prototype = arr;
return new foo();
}
5:多重继承(混合继承)
function foo(name) {
this.name = name;
}
function fn(arr) {
this.age = arr;
}
function obj(name, age) {
foo.call(this, name);
fn.call(this, age);
}
obj.prototype = Object.create(foo.prototype);
Object.assign(obj.prototype, fn.prototype);
obj.prototype.constructor = obj;
var a = new obj('zhangsan', 18);
console.log(a); //obj {name: "zhangsan", age: 18}
class继承
class是ES6新增的,继承通过extends实现
class Foo { constructor(name) { this.name = name; } age() { console.log(this.name); } obj() { console.log('hello world'); } } class fn extends Foo { constructor(name) { super(name); } age() { console.log(`子类调用${this.name}`); } } var a = new fn('zhangsan'); a.age(); a.obj();
参考文章:
30分钟学会js继承