javascript高级程序设计---6继承

ByteRhapsody
• 阅读 1432

继承对象

主要实现原理:通过原型链继承~~~~

所以先来了解下原型链

Child.prototype.__proto__ === Parent.prototype;
Child.__proto__ === Parent;
  • Parent是Function的实例。
Parent.__proto__ === Function.prototype;
Function.prototype.__proto__ === Object.prototype;
  • 所有函数的默认原型都是Object的实例。
Parent.prototype.__proto__ === Object.prototype;
Object.prototype.__proto__ === null;
  • 继承的原型链图

javascript高级程序设计---6继承

继承模式总结比较

继承模式 优点 缺点 可以用instance或者isPrototypeOf判断类型吗
原型链基础 Child.prototype = new Parent();重写了原型链继承了Parent的方法 1、Parent类型的实例变成了Child类型的原型对象,如果Parent有引用类型比如Array的属性会被篡改 2、创建Child类型的实例时,不能向Parent的构造函数传参 可以
借用构造函数(伪造对象或经典继承) 解决了引用属性共享和不可传参 无法复用函数 可以
组合继承(伪经典继承) 结合了原型链和构造模式,最常用 总是会调用两次超类型构造函数 可以
原型式继承 简单轻量,不复杂,适合简单需求 会共享引用类型的值,篡改 不可以
寄生式继承 替代不是自定义和构造函数的情况 不能函数复用 不可以
寄生组合式继承 最理想的继承范式 可以
0、类式继承的方案
class Parent {
  constructor(name){
    this.name = name;
  }

  static sayHello() {
    console.log('hello');
  }
  sayName() {
    console.log(`my name is ${this.name}`);
    return this.name;
  }
}

class Child extends Parent {
  constructor (name, age) {
    super(name);
    this.age = age;
  }
  sayAge() {
    console.log(`my age is ${this.age}`);
    return this.age;
  }
}

let parent = new Parent('Parent');
let child = new Child('Child', 18);

console.log(parent);
console.log(child);

console.log(child.__proto__ === Child.prototype);
console.log(Child.prototype.constructor === Child);
console.log(Child.prototype.__proto__ === Parent.prototype); // 继承的原理1

console.log(Parent.prototype.constructor === Parent);
console.log(Parent.prototype.__proto__ === Object.prototype);
console.log(Object.prototype.__proto__ === null);


console.log(Child.__proto__ === Parent); // 继承的原理2
console.log(Parent.__proto__ === Function.prototype);
console.log(Function.prototype.__proto__ === Object.prototype);
console.log(Object.prototype.__proto__ === null);
1、通过原型链实现继承---实现继承的主要方法。基本思想:让一个引用类型继承另一个引用类型的属性和方法。
  • 实现的本质是重写原型对象,代之以一个新类型的实例。因为重写了原型对象,所以给原型添加方法一定要放在替换原型的后面,如果先添加再替换,新添加的都被替换走了,所以永远也不会生效了。

     function Parent () {
       this.parentProperty = true;
     }
     Parent.prototype.getParentProperty = function () {
       console.log(`parent's ${this.parentProperty}`);
     }
    
     function Child() {
       this.childProperty = false;
     }
    
     Child.prototype = new Parent(); // 本质---重写原型对象
    
     Child.prototype.getChildProperty = function () {
       console.log(`child's${this.childProperty}`);
     }
    
     const parentInstance = new Parent();
     console.log(parentInstance.constructor); // Parent{}  
    
     const childInstance = new Child();
     console.log(childInstance.constructor); // Parent{} 导致childInstance的constructor指向Parent
     childInstance.getParentProperty(); // parent's true
    • 确定原型和实例的关系
// 法一:instanceof
 console.log(childInstance instanceof Child);
 console.log(childInstance instanceof Parent);
 console.log(childInstance instanceof Object);
// 法二:isPrototypeOf
 console.log(Child.prototype.isPrototypeOf(childInstance));
 console.log(Parent.prototype.isPrototypeOf(childInstance));
 console.log(Object.prototype.isPrototypeOf(childInstance));
  • 不能使用对象字面量创建原型方法。

    // yes
    Child.prototype = new Parent();
    // no。这样做新建了一个Object实例,而非Parent的实例,切断了与Parent的联系。
    Child.prototype = {
    };
2、借用构造函数:在Child类型构造函数的内部调用Parent类型构造函数。
  • 函数是特定环境中执行代码的对象,可以通过call和apply在新创建的对象上执行构造函数。

     function Parent (name) {
       this.colors = ['red', 'green'];
       this.name = name;
       this.age = 99;
     }
    
     function Child(name){
       // 继承了Parent
       Parent.call(this, name);
    
       // 添加Child的属性,一定要在调用Parent的后面,不然会被Parent构造函数重写属性(如果正好存在)
       this.age = 29;
     }
    
     const childInstance1 = new Child('tom');
     const childInstance2 = new Child('jack');
    
     childInstance1.colors.push('white');
    
     console.log(childInstance1.colors); // ['red', 'green', 'white']
     console.log(childInstance2.colors); // ['red', 'green']
    
     console.log(childInstance1.name); // tom
     console.log(childInstance2.name); // jack
    
     console.log(childInstance1.age); // 29
     console.log(childInstance2.age); // 29
    
     console.log(childInstance2 instanceof Child); // true
     console.log(childInstance2 instanceof Parent); // false
     console.log(childInstance2 instanceof Object); // true
3、组合继承:组合使用原型链和构造函数模式
  • 使用原型链实现对原型属性和方法的继承(复用);使用构造函数实现对实例属性的继承(副本)

    function Parent (name) {
     this.colors = ['red', 'green'];
     this.name = name;
    }
    
    Parent.prototype.getParentName = function () {
     console.log(this.name);
    }
    
    function Child(name, age){
     // 构造函数继承属性
     Parent.call(this, name);
    
     this.age = age;
    }
    
    // 使用原型链继承方法
    Child.prototype = new Parent();
    Child.prototype.constructor = Child;
    
    Child.prototype.getChildAge = function () {
     console.log(this.age);
    }
    
    const childInstance1 = new Child('tom', 29);
    const childInstance2 = new Child('jack', 18);
    
    childInstance1.colors.push('white');
    
    console.log(childInstance1.colors); // ['red', 'green', 'white']
    console.log(childInstance2.colors); // ['red', 'green']
    childInstance1.getParentName(); // 'tom'
    childInstance2.getParentName(); // 'jack'
    
    childInstance1.getChildAge(); // 29
    childInstance2.getChildAge(); // 18
    
    console.log(childInstance2 instanceof Child); // true
    console.log(childInstance2 instanceof Parent); // true
    console.log(childInstance2 instanceof Object); // true
4、原型式继承
  • 借助原型基于已有的对象创建新对象,同时还不必因此创建自定义类型

    // object对传入其中的对象进行了一次浅复制
     function object (o) {
       function F() {}
       F.prototype = o;
       return new F();
     }
    
     const person = {
       name: 'tom',
       friends: ['a', 'b', 'c']
     };
    
     const anotherPerson = object(person);
    
     anotherPerson.name = 'huahua';
     anotherPerson.friends.push('d');
     const onePerson = object(person);
    
     console.log(person.friends); // ['a', 'b', 'c', 'd']
     console.log(anotherPerson.friends); // ['a', 'b', 'c', 'd']
     console.log(onePerson.friends); // ['a', 'b', 'c', 'd']
  • ECMAScript5新增了Object.create方法,规范了原型式继承。
5、寄生式继承:创建一个仅用于封装继承过程的函数,在内部增强对象。
function createAnother(original) {
   const clone = object(original);

   clone.sayHi = function () {
     console.log('hi');
   }

   return clone;
 }

 const person = {
   name: 'tom',
   friends: ['a', 'b', 'c']
 };

 const anotherPerson = createAnother(person);
 anotherPerson.sayHi();

 anotherPerson.friends.push('e');

 console.log(anotherPerson.friends); // ['a', 'b', 'c', 'e']
 console.log(person.friends); // ['a', 'b', 'c', 'e']
6、寄生组合式继承
  • 不必为了指定Child类型的原型而调用Parent类型的构造函数,需要的只是Parent原型的一个副本。
  // object对传入其中的对象进行了一次浅复制
  function object (o) {
    function F() {}
    F.prototype = o;
    return new F();
  }

  function inheritPrototype (Sub, Super) {
    const prototype = object(Super.prototype); // 创建对象
    prototype.constructor = Sub; // 增强对象
    Sub.prototype = prototype; // 指定对象
  }

  function Parent (name) {
    this.name = name;
    this.colors= ['a', 'b', 'c'];
  }

  Parent.prototype.getParentName = function () {
    console.log(this.name);
  }

  function Child (name, age) {
    // 继承属性
    Parent.call(this, name);

    this.age = age;
  }

  // 继承方法
  inheritPrototype(Child, Parent);

  Child.prototype.getChildAge = function () {
    console.log(this.age);
  }

  const childInstance1 = new Child('tom', 29);
  const childInstance2 = new Child('jack', 18);

  childInstance1.colors.push('white');

  console.log(childInstance1.colors); // ["a", "b", "c", "white"]
  console.log(childInstance2.colors); // ["a", "b", "c"]
  childInstance1.getParentName(); // 'tom'
  childInstance2.getParentName(); // 'jack'

  childInstance1.getChildAge(); // 29
  childInstance2.getChildAge(); // 18

  console.log(childInstance2 instanceof Child); // true
  console.log(childInstance2 instanceof Parent); // true
  console.log(childInstance2 instanceof Object); // true
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
ZY ZY
4年前
js继承的几种方式
1.原型链继承原型链继承:想要继承,就必须要提供父类(继承谁,提供继承的属性)//父级functionPerson(name)//给构造函数添加参数this.namename;this.age10;this.sumfunction()console.log(this.name)//原
Stella981 Stella981
3年前
JavaScript prototype原型用法
JavaScript对象原型所有JavaScript对象都从原型继承属性和方法。<!DOCTYPEhtml<html<metacharset"utf8"<titlejs</title<body<h2JavaScript对象</h2
Stella981 Stella981
3年前
JavaScript学习总结(十七)——Javascript原型链的原理
一、JavaScript原型链ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。在JavaScript中,用__proto__属性来表示一个对象的原型链。当查找一个对象的属性时,JavaScript会向上遍历原型
Stella981 Stella981
3年前
JavaScript 学习笔记八 继承与引用
functionlogs(obj){document.write(obj"<br/");}//打印log日志//继承//继承可以通过原型链来实现//解释器会在对象中查找该属性,如果//没有找到,则在其内部对象prototype对象上搜索,由于prototype对象与对象本身的结/
Stella981 Stella981
3年前
Javascript 是如何体现继承的 ?
js继承的概念js里常用的如下两种继承方式:原型链继承(对象间的继承)类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于对象的,它没有类的概念。所以,要想实现继承,可以用js的原型prototype机制或者用apply和call方法去实现在面向对象的语言中,我们使用类来创建一个自定义对象
Stella981 Stella981
3年前
JavaScript 原型和原型链的定义和使用
目录JavaScript原型和原型链的定义和使用01原型原型定义原型实例理解书写方法1:属性单个定义书写方法2:属性多个定义02原型链原型链定义原型链实例理解最终原型问题03原型和原型链的使用应用举例Ja
Stella981 Stella981
3年前
JavaScript 基于原型链的继承
JavaScript对象是动态的属性“包”(指其自己的属性)。JavaScript对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。遵循ECMAScript标准,someObject.Prototype
Stella981 Stella981
3年前
Javascript中,实现类与继承的方法和优缺点分析
Javascript是一种弱类型语言,不存在类的概念,但在js中可以模仿类似于JAVA中的类,实现类与继承第一种方法:利用Javascript中的原型链1//首先定义一个父类23functionAnimal(name,age){4//定义父类的属性5thi
Stella981 Stella981
3年前
Javascript继承5:如虎添翼
/寄生式继承其实就是对原型继承的第二次封装,在封装过程中对继承的对象进行了扩展。也存在原型继承的缺点!!这种思想的作用也是为了寄生组合式继承模式的实现。///声明基对象varbook{name:'jsbook',al