ES5继承
先定义一个父类
// 1.定义父类 (包含实例属性和方法)
function Animal(name) {
this.name = name || 'Animal';
this.sleep = function () {
console.log(this.name + "正在睡觉!")
}
}
// 原型方法
Animal.prototype.eat = function (food) {
console.log(this.name + "正在吃" + food);
}
1. 原型链继承
实现:将父类的实例作为子类的原型对象
// 2.定义子类
function Cat() { }
Cat.prototype = new Animal(); //!将父类的实例作为子类的原型对象
Cat.prototype.name = "cat";
var cat = new Cat();
console.log(cat.name); //cat
cat.eat("fish"); //cat正在吃fish
cat.sleep(); //cat正在睡觉!
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
特点:
- 非常纯粹的继承关系,实例 cat 既是父类的实例,也是子类的实例
- 子类能访问到父类的所有属性和方法(包括原型属性和方法)
缺点:
- 无法实现多继承
- 来自原型对象的引用属性是所有实例共享的
- 创建子类实例时,无法向父类构造函数传参
2. 构造继承
实现:让父类的 this 指向子类,复制父类的实例属性和方法给子类
// 2.定义子类
function Cat(name) {
Animal.call(this); //!让父类的this指向子类,复制父类的【实例属性和方法】给子类
this.name = name || "Tom"
}
//Test Code
var cat = new Cat("cat");
console.log(cat.name); //cat
cat.sleep(); //cat正在睡觉!
// cat.eat("fish"); //报错:cat.eat is not a function
console.log(cat instanceof Animal); //false
console.log(cat instanceof Cat); //true
特点:
- 创建子类实例时,可以向父类传递参数
- 可实现多继承(call 多个父类对象)
缺点:
- 实例 cat 是子类的实例,不是父类的实例
- 只能继承父类的实例属性方法,不能继承其原型属性方法
(解决原型链继承中,子类实例共享父类引用属性的问题) - 每个子类都有父类实例属性和方法的副本,影响性能
3. 实例继承
实现:为父类实例添加新属性和方法,作为子类实例返回
// 2.定义子类
function Cat(name) {
var instance = new Animal();
instance.name = name || "Tom"; //!为父类实例添加新属性、方法,作为子类实例返回
return instance;
}
var cat = new Cat();
console.log(cat.name); //Tom
cat.sleep(); //Tom正在睡觉!
cat.eat("fish"); //Tom正在吃fish
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //false
特点:不限制调用方法,不管是 new 子类()还是子类(),具有相同的效果
缺点:
- 实例 cat 是父类的实例,但不是子类的实例
- 不支持多继承
ES6继承
// 定义父类
class Person {
constructor(skin,language) {
this.skin = skin
this.language = language
}
say() {
console.log("I'm a Person")
}
}
// 子类继承
class American extends Person {
/*有无注释效果都一样*/
// constructor(skin,language) {
// super(skin,language)
// }
aboutMe() {
console.log(this.skin+" "+this.language)
}
}
var m = new American("张三","中文")
m.say() //I'm a Person
m.aboutMe() //张三 中文
子类调用 super 函数是为了在子类中获取父类的 this(即执行父类.prototype.constructor.call(this)),使用父类的属性和方法。
- 子类中没有 constructor 时,会默认添加一个并在 constructor 中执行 super 函数,即调用父类的构造函数
- 子类中有 constructor 时,必须在 constructor 中执行 super 函数,否则 new 实例时会报错(子类没有自己的 this 对象)