SOURCE

// 记录js继承方式

// 继承:让一个对象能够访问另一个对象的属性和方法 以减少内存使用
// 因为每声明一个对象 就需要开内存来存放该对象的属性和方法 类似的对象拥有同样的属性和方法时 就导致来内存浪费
// 故使用 继承 的方式 来使得 一个对象够访问另一对象的属性和方法 减少同一属性和方法的重复声明

// js prototype __proto__ constructor
// __proto__ constructor 对象独有
// prototype 函数独有 又因 函数也是对象 故 函数也有 __proto__ constructor
// prototype 作用 包含特定的 属性和方法 以方便实例共享
// constructor 作用 指向该对象的构造函数 最上层就是Function
// __proto__ 作用 一个对象指向另一个对象 通过__proto__进行继承

// 统一父类
function Animal(name = 'Animal'){
    this.name = name
    this.getName = function () {
        return this.name
    }
}

Animal.prototype.setName = function(name) { 
    this.name = name
}

console.log(Animal.prototype) // 返回Animal的prototype
console.log(Animal.constructor) // 因function也是对象 故 constructor 指向 function 这个方法
console.log(Animal.__proto__) // 因function也是对象 故 __proto__ 指向 function 这个对象

console.log('-----animal实例-----')
let animal = new Animal()
console.log(animal.constructor) // 返回创建animal的构造函数
console.log(animal.__proto__) // 就是Animal的prototype

console.log('--------------------前提--------------------')


// 1、原型链继承

function Cat () {
    this.name = 'Cat'
}
// 继承父类的属性和方法
Cat.prototype = new Animal() // Cat继承Animal的特定 属性和方法 因为通过new返回了一个对象 

console.log(Cat.prototype) // 就是Animal的实例
console.log(Cat.constructor) // Cat是方法 故返回funciton
console.log(Cat.__proto__) // Cat是方法 故 原型就是function

console.log('-----cat实例-----')

let cat = new Cat()
console.log(cat)
console.log(cat.constructor) // cat没有constructor 故 从__proto__去找 又因cat.__proto__是Animal 故 返回 Animal的构造函数
console.log(cat.__proto__) // cat 通过 new 而来 cat.__proto__ 指向 Cat.prototype

// 缺点 
// 子类实例共享一个引用类型的属性
// 子类实例不能想父类构造函数传值

console.log('--------------------Cat--------------------')

// 2、借用构造函数继承
function Dog (name) {
    Animal.call(this, name) // 构造函数.call(this) 即 调用构造函数的初始化方法 把自己的this传入 这样就能把构造函数属性的this指向自己
}
// 通过call将Animal的属性和方法赋值给了Dog 但是不能继承Animal的prototype

console.log(Dog.prototype) // 返回funtion的prototype 因为Dog的prototype没有重新赋值 故通过__proto__去function里找
console.log(Dog.constructor) // 同Cat
console.log(Dog.__proto__) // 同Cat

console.log('-----dog实例-----')

let dog = new Dog("dog")
console.log(dog)
console.log(dog.constructor) // dog没有constructor 通过__proto__向上找到了Dog()
console.log(dog.__proto__) // 因为通过 Dog()来创建 故 原型链是Function的propotype
// dog.setName('2') // 不能继承Animal的prototype

// 优点
// 避免了子类实例共享一个引用类型的属性问题 (因为没有了)
// 解决原型链继承 不能向父类构造函数传值的问题
// 缺点
// 子类实例的构造函数只是子类 不是父类 
// 方法在构造函数中定义 导致 每次创建实例 方法都会被再创建一次 (call)
// 不能继承父类的prototype

console.log('--------------------Dog--------------------')

// 3、组合继承
function Duck (name) {
    Animal.call(this, name)
}
Duck.prototype = new Animal()

console.log(Duck.prototype) // 因为Duck的prototype重新赋值 故 返回Animal
console.log(Duck.constructor) // 同Cat
console.log(Duck.__proto__) // 同Cat

console.log('-----duck实例-----')
let duck = new Duck('duck')
console.log(duck)
console.log(duck.constructor) // duck没有constructor 向上找找到 Duck.prototype 也没有 再向上就到Animal()了
console.log(duck.__proto__) // Duck.prototype

// 优点
// 结合了 原型链继承 和 借用构造函数 继承的优点
// 能够向父类构造函数传值
// 每个新实例引入的构造函数属性是私有的 (因为引用两次父类属性 第一次的时候重新赋值了 在第一次属性上独立)
// 缺点
// 引用了两次父类构造函数 消耗内存 (一次call 第二次是通过prototype)

console.log('--------------------Duck--------------------')

// 4、原型式继承

function creactBird (obj) {
    function F() {}
    F.prototype = obj // 基于已有对象
    return new F()
}

let Bird = new Animal()
let bird = creactBird(Bird)

console.log(bird)
console.log(bird.constructor) // 因为bird返回一个实例 实例的prototype指向Animal 故构造函数是Animal
console.log(bird.__proto__)
console.log(bird.name)

// 概念 基于已有的对象 创建新的对象 同时不必因此创建自定义类型 (同寄生继承理解 就是说 直接用了父类的属性 寄生是用自己的属性 但是原型链上有父类属性)

// 优点
// 复制一个对象 用函数包装
// 缺点
// 所有子类实例会继承构造函数属性 (因为子例通过Bird->new Animal()实例的)
// 无法实现复用

console.log('--------------------Bird--------------------')

// 5、寄生继承

var Bird2 = new Animal();
function creactBird2 (obj, name) {
    var sub = creactBird(obj);
    sub.birdName = name;
    return sub;
}
// 以上是原型式继承,给原型式继承再套个壳子传递参数

let bird2 = creactBird2(Bird2, 'bird2')

console.log(bird2) // 因为通过了creactBird2是的返回的实例拥有自己的属性
console.log(bird2.constructor) // 因为bird返回一个实例 实例的prototype指向Animal 故构造函数是Animal
console.log(bird2.__proto__)

console.log('--------------------Bird2--------------------')

// 6、组合寄生继承

let subBird3 = creactBird(Animal.prototype)
function Bird3 () {
    Animal.call(this)
}
Bird3.prototype = subBird3
subBird3.constructor = Bird3

let bird3 = new Bird3()

console.log(bird3) // 因为通过了creactBird2是的返回的实例拥有自己的属性
console.log(bird3.constructor) // 因为bird返回一个实例 实例的prototype指向Animal 故构造函数是Animal
console.log(bird3.__proto__)

console.log('--------------------Bird3--------------------')


console 命令行工具 X clear

                    
>
console