原型链继承
核心: 子构造函数的原型指向父构造函数的实例
每个构造函数都有一个原型对象, 原型对象中都包含一个指向构造函数的指针, 而实例都包含一个指向原型对象的内部指针. 当原型对象等于另外一个类型的实例即继承. 调用某个方法或者属性的步骤
a. 搜索实例
b. 搜索原型
c. 搜索父类原型
- function Animal() {
- this.name = "animal";
- this.arrt = [1, 2]
- }
- Animal.prototype = {
- sayName: function () {
- alert(this.name);
- }
- }
- function Dog() {
- this.color = "灰色"
- }
- Dog.prototype = new Animal();
- Dog.prototype.sayColor = function () {
- alert(this.color);
- }
- var dog = new Dog();
- var dog1 = new Dog();
- console.log(dog);
- dog.arrt.push(5);
- console.log(dog1);
- dog.sayColor();
- dog.sayName();
可以自己打印一下, 看一下结果
优点
1. 非常纯粹的继承关系, 实例是子类的实例, 也是父类的实例
2. 父类新增原型方法 / 原型属性, 子类都能访问到
3. 简单, 易于实现
缺点
1. 包含引用类型值的原型属性会被所有实例共享, 这会导致对一个实例的修改会影响另一个实例.
2. 在创建子类型的实例时, 不能向超类型的构造函数中传递参数. 由于这两个问题的存在, 实践中很少单独使用原型链.
借用构造函数
也称 "伪造对象" 或 "经典继承", 在子类型构造函数的内部调用超类型构造函数. 函数不过是在特定环境中执行代码的对象, 因此通过 apply(),call()方法可以在 (将来) 新建对象上执行构造函数, 即 在子类型对象上执行父类型函数中定义的所有对象初始化的代码. 结果每个子类实例中都具有了父类型中的属性以及方法
- function Animal(name){
- this.name = name;
- this.colors = ["red","gray"];
- }
- function Dog(name){
- // 继承了 Animal
- Animal.call(this,"mary");// 在子类型构造函数的内部调用超类型构造函数
- this.color = "gray";
- }
- Animal.prototype.sayName = function(){
- alert(this.name);
- }
- var dog = new Dog();
- var dog1=new Dog();
- dog.colors.push("hhh");
- console.log(dog.colors);//red gray hhh
- console.log(dog1.colors);//red gray
- Animal.prototype.swif="hua";
- console.log(dog.swif);//undefined
- var animal = new Animal();
- console.log(animal); // 如果将函数定义在构造函数中, 函数复用无从谈起
- dog.sayName(); // 在超类型的原型中定义的方法, 对于子类型而言是无法看到的
优点
1. 解决了 1 中, 子类实例共享父类引用属性的问题
2. 创建子类实例时, 可以向父类传递参数
3. 可以实现多继承(call 多个父类对象)
缺点
1. 实例并不是父类的实例, 只是子类的实例
2. 只能继承父类的实例属性和方法, 不能继承父类原型属性 / 方法
3. 无法实现函数复用, 每个子类都有父类实例函数的副本, 影响性能
组合函数
组合继承(combination inheritance), 有时候也叫做伪经典继承, 指的是将原型链和借用构造函数的 技术组合到一块, 从而发挥二者之长的一种继承模式. 其背后的思路是使用原型链实现对原型属性和方 法的继承, 而通过借用构造函数来实现对实例属性的继承. 这样, 既通过在原型上定义方法实现了函数 复用, 又能够保证每个实例都有它自己的属性
- function Animal(name){
- this.name = name;
- this.colors = ["red","gray"];
- }
- function Dog(name){
- // 继承了 Animal(属性)
- Animal.call(this,name);
- this.color = "gray";
- }
- Animal.prototype.sayName = function(){
- alert(this.name);
- }
- // 继承方法
- Dog.prototype = new Animal();
- Dog.prototype.constructor = Animal;
- var dog = new Dog("2");
- dog.colors.push("hhh");
- console.log(dog);
- var animal = new Animal();
- console.log(animal);
- dog.sayName(); // 可以调用
优点
1. 可以继承实例属性 / 方法, 也可以继承原型属性 / 方法
2. 既是子类的实例, 也是父类的实例
3. 不存在引用属性共享问题
4. 通过 call 继承父类的基本属性和引用属性并保留能传参的优点
5. 函数可复用
缺点
1, 子类原型上有一份多余的父类实例属性, 因为父类构造函数被调用了两次, 生成了两份, 而子类实例上的那一份屏蔽了子类原型上的.
原型式继承
寄生式继承
寄生组合式继承
来源: https://juejin.im/post/5bd67befe51d452c5c002e4a