1.继承的概念
通过某种方式让一个对象可以访问到另一个对象中的属性和方法,我们把这种方式称之为继承
2.为什么要使用继承(节约内存)
有些对象会有方法(动作、行为),而这些方法都是函数,如果把这些方法和函数都放在构造函数中声明就会导致内存的浪费
3.继承的几种方法
3.1 原型链继承
让新实例的原型等于父类的实例。
//动物对象
function Animal(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
this.sleep = function () {
return this.name + '在睡觉!'
}
}
//狗对象
function Dog() {
this.eat = function () {
return this.name + '吃狗粮!'
}
}
//让新实例的原型等于父类的实例
Dog.prototype = new Animal()
var dog = new Dog() //没有办法传参
var lx = new Dog()
Dog.prototype.name = '团团'
Dog.prototype.age = 3
Dog.prototype.sex = '公'
Dog.prototype.play = function () {
return this.name + '玩皮球!'
}
//这种写法是在Dog对象上新建立了一个属性
// dog.name = '团团'
优点:实例可继承实例的构造函数的属性,父类构造函数属性,父类原型的属性。
输出一下
console.log(dog);
console.log(dog.name, dog.age, dog.sex);
console.log(dog.sleep());
console.log(dog.eat());
console.log(dog.play());
这里eat方法在Dog对象上,剩下的属性是从Animal对象上继承过来的
console.log(dog instanceof Dog); //true
console.log(dog instanceof Animal); //true
子类的实例即是本身也是父类
缺点:
1.无法实现多继承
2.无法传参
3.所有新实例都会共享父类实例的属性。
console.log(dog.__proto__.__proto__.__proto__); //Animal,Animal原型对象,obj
console.log(Dog.prototype); //原型对象指向Animal
console.log(lx.name); //属性值固定
3.2 构造继承
用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
//动物对象
function Animal(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
this.sleep = function () {
return this.name + '在睡觉!'
}
}
//因为
Animal.prototype = {
play: function () {
console.log(this.name + "在玩!");
}
}
//类型
function Type(type) {
this.type = type
}
//狗对象
function Dog(name, age, sex, type) {
//实现了多继承
Animal.call(this, name, age, sex)
Type.call(this, type)
this.eat = function () {
return this.name + '吃狗粮'
}
}
优点:1.实现多继承 2.可以传参 3.所有新实例都不会共享父类实例的属性(没有继承父类原型的属性)
缺点:1.只能继承父类构造函数的属性 2.无法实现构造函数的复用 3.每个新实例都有父类构造函数的副本,臃肿
console.log(dog.name, dog.age, dog.sex, dog.type);
console.log(dog.__proto__.__proto__.__proto__); //Dog,Obj,null
console.log(dog instanceof Dog); //true
console.log(dog instanceof Animal); //false
继承到了Animal和Type对象的属性,子类的实例即是本身但不是父类
console.log(dog.play());
这里调用Animal原型对象新增的方法会报错,只能继承Animal构造函数上的属性
3.3 组合继承(构造+原型链)
结合了两种模式的优点,传参和复用
//动物对象
function Animal(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
this.sleep = function () {
return this.name + '在睡觉!'
}
}
Animal.prototype = {
play: function () {
return this.name + "在玩!"
}
}
//类型
function Type(type) {
this.type = type
}
//狗对象
function Dog(name, age, sex, type) {
Animal.call(this, name, age, sex) //第一次
Type.call(this, type)
this.eat = function () {
return this.name + '吃狗粮'
}
}
Dog.prototype = new Animal() //第二次
var dog = new Dog('小白', 5, '公', '哺乳动物')
console.log(dog.name, dog.age, dog.sex, dog.type);
console.log(dog.play());
console.log(dog.__proto__.__proto__.__proto__.__proto__); //Dog,Animal和Type,Obj,null
优点:结合了前两种继承的所有优点
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
3.4 实例继承
function Animal(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
this.sleep = function () {
return this.name + '在睡觉!'
}
}
Animal.prototype = {
play: function () {
return this.name + "在玩!"
}
}
//狗对象
function Dog(name, age, sex) {
var fn = new Animal(name, age, sex)
return fn
}
var dog = new Dog('旺旺', 2, '母')
console.log(dog);
console.log(dog.name, dog.age, dog.sex);
console.log(dog.play());
console.log(dog.__proto__.__proto__.__proto__); //Animal,Obj,null
console.log(dog instanceof Dog); //false
console.log(dog instanceof Animal); //true
缺点:不支持多继承
优点:不限制调用方式 (new或者直接调用函数执行都可以)
3.5 寄生继承
就是给原型式继承外面套了个壳子
function Person(name) {
this.name = name
this.people = function () {
return this.name + '工作人员'
}
}
Person.prototype.age = 10
//实例继承
function content(obj) {
function F() { }
F.prototype = obj
return new F()
}
var sup = new Person() //实例化中间变量
//带个壳子
function Student(obj) {
var sub = content(obj)
sub.name = '小明'
return sub
}
var student = Student(sup)
console.log(typeof subobject);
console.log(typeof student);
console.log(student.name, student.age);
</script>
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象
缺点:没用到原型,无法复用
3.6 寄生组合继承
<script>
function Animal(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
this.sleep = function () {
return this.name + '在睡觉!'
}
}
Animal.prototype = {
play: function () {
return this.name + "在玩!"
}
}
//狗对象
//实例继承
function content(obj) {
function F() { }
F.prototype = obj //继承了传入的参数
return new F()
}
var sup = content(Animal.prototype) //中间变量
//构造继承
function Dog() {
Animal.call(this)
}
//原型链继承
Dog.prototype = sup
sup.constructor = Dog
var dog = new Dog('小黑', 5, '公')
console.log(dog);
console.log(dog.play());
</script>
修复了组合继承的问题