zoukankan      html  css  js  c++  java
  • JS继承的几大方法

    原文链接: https://juejin.im/post/6844904098941108232

    这篇是阅读文章,自己在控制台打印,记录一下,方便后期复习

    原文写得很好,容易理解,对继承不太清楚的可以看看

    // 一,原型链继承
    
      // function Parent () {
      //   this.name = 'Parent'
      //   this.sex = 'boy'
      // }
      // Parent.prototype.getName = function () {
      //   console.log(this.name)
      // }
      // function Child () {
      //   this.name = 'child'
      // }
      // 将子类的原型对象指向父类的实例或者指向父类的原型对象
      // Child.prototype = new Parent()
      // Child.prototype = Parent.prototype
      
      // var child1 = new Child()
      // child1.getName()
      // console.log(child1)
    
      // 将上面的原型方法再添加一个
      // Parent.prototype.getSex = function () {
      //   console.log(this.sex)
      // }
    
      // 使用这种方法只能继承到父类原型链上的方法,构造函数上的属性和方法将不会被继承
      // Child.prototype = Parent.prototype
      // 使用父实例继承,可以继承构造函数和原型对象上的方法
      // Child.prototype = new Parent()
    
      // var child1 = new Child()
      // child1.getName()
      // child1.getSex() // undefined
      // console.log(child1)
    
      /** --------------------------------------- */
    
      // function Parent (name) {
      //   this.name = name
      //   this.sex = 'boy'
      //   this.colors = ['white', 'black']
      // }
      // function Child () {
      //   this.feature = ['cute']
      //   this.colors = ['white', 'red']
      // }
      // var parent = new Parent('parent')
      // Child.prototype = parent
      
      // Child.prototype.age = 17
      // var child1 = new Child('child1')
      // child1.sex = 'girl'
      // child1.colors.push('yellow')
      // child1.feature.push('sunshine')
      
      // var child2 = new Child('child2')
      
      // console.log(child1) // colors: (3) ["white", "red", "yellow"] feature: (2) ["cute", "sunshine"] sex: "girl"
      // console.log(child2) // colors: (2) ["white", "red"]  feature: ["cute"]
      
      // console.log(child1.name) // parent
      // console.log(child2.age) // 17
      
      // console.log(parent) // colors: (2) ["white", "black"]  name: "parent"  sex: "boy" age:17
    
      // 原型链继承缺点
      // 1.子类原型新增方法和属性要放在继承之后
      // 2.无法实现多继承
      // 3.来自原型对象的所有属性都被共享了,如果修改原型对象的属性,所有创建的实例对象都会受到影响
      // 4.创建子类时,不能向父类构造函数传参
    
       /** --------------------------------------- */
    
       // instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
       // a instanceof B
    
      // 实例对象a instanceof 构造函数B
    
      // 检测a的原型链(__proto__)上是否有B.prototype,有则返回true,否则返回false。
      // function Parent () {
      //   this.name = 'parent'
      // }
      // function Child () {
      //   this.sex = 'boy'
      // }
      // Child.prototype = new Parent()
      // var child1 = new Child()
      
      // console.log(child1 instanceof Child) // true
      // console.log(child1 instanceof Parent) // true
      // console.log(child1 instanceof Object) // true
    
      /** --------------------------------------- */
    
      // isPrototypeOf()的用法和instanceof相反。
      // 它是用来判断指定对象object1是否存在于另一个对象object2的原型链中,是则返回true,否则返回false。
    
      // function Parent () {
      //   this.name = 'parent'
      // }
      // function Child () {
      //   this.sex = 'boy'
      // }
      // Child.prototype = new Parent()
      // var child1 = new Child()
      
      // console.log(Child.prototype.isPrototypeOf(child1)) // true
      // console.log(Parent.prototype.isPrototypeOf(child1)) // true
      // console.log(Object.prototype.isPrototypeOf(child1)) // true
    
      /** --------------------------------------- */
      
      // 3.构造函数继承
      // call接受若干个参数 apply接受一组数组 bind不会立即执行,返回函数
      // function Parent (name) {
      //   this.name = name
      // }
      // function GrandParent (age) {
      //   this.age = age
      // }
      // function OtherParent (color) {
      //   this.color = color
      // }
    
      // function Child () {
      //   this.sex = 'boy'
      //   this.name = 'juan'
      //   Parent.call(this, 'child')
      //   this.name = 'junn'
      //   GrandParent.apply(this, [17, 'red'])
      // }
    
      // var child1 = new Child()
      // OtherParent.bind(child1, 'yellow')()
      // console.log(child1) // {sex: "boy", name: "junn", age: 17, color: "red"}
    
      /** --------------------------------------- */
    
      // function Parent (name, sex) {
      //   this.name = name
      //   this.sex = sex
      //   this.colors = ['white', 'black']
      // }
      // function Child (name, sex) {
      //   Parent.call(this, name, sex)
      // }
      // var child1 = new Child('child1', 'boy')
      // child1.colors.push('yellow')
      
      // var child2 = new Child('child2', 'girl')
      // console.log(child1) // {name: "child1", sex: "boy", colors: Array(3)}
      // console.log(child2) // {name: "child2", sex: "girl", colors: Array(2)}
    
      // 构造继承的优点: 1.可以继承多个父类 2.修改实例不会影响其他实例  3.可以传递参数
    
      /** --------------------------------------- */
    
      // const arr = ['5', '6', '7', '11']
      // const res = Math.max.apply(null, arr)
      // console.log(res)
    
      // function Parent (name) {
      //   this.name = name
      // }
      // Parent.prototype.getName = function () {
      //   console.log(this.name)
      // }
      // function Child () {
      //   this.sex = 'boy'
      //   Parent.call(this, 'good boy')
      // }
      // Child.prototype.getSex = function () {
      //   console.log(this.sex)
      // }
      // var child1 = new Child()
      // console.log(child1)
      // child1.getSex()
      // child1.getName() // 报错
    
      // 构造函数的缺点: 不能继承父类构造函数原型对象上的方法和属性
    
      /** --------------------------------------- */
    
      // function Parent (name) {
      //   this.name = name
      // }
      // function Child () {
      //   this.sex = 'boy'
      //   Parent.call(this, 'child')
      // }
      // var child1 = new Child()
      
      // console.log(child1)
      // console.log(child1 instanceof Child) // true
      // console.log(child1 instanceof Parent) // false
      // console.log(child1 instanceof Object) // true
    
      // 通过构造函数继承的实例不是继承父类的实例,也不能使用父类原型对象上的方法
    
      /** --------------------------------------- */
    
      // 4.组合继承
    
      // 组合继承就是将原型链继承与构造函数继承组合在一起,从而发挥两者之长的一种继承模式
    
      // function Parent (name) {
      //   this.name = name
      // }
      // Parent.prototype.getName = function () {
      //   console.log(this.name)
      // }
      // function Child (name) {
      //   this.sex = 'boy'
      //   Parent.call(this, name)
      // }
      // Child.prototype = new Parent()
      // Child.prototype.getSex = function () {
      //   console.log(this.sex)
      // }
      // var parent1 = new Parent('parent1')
      // var child1 = new Child('child1')
      // console.log(child1) // Child{ name: 'child1', sex: 'boy' }
      // console.log(parent1)// Parent{ name: 'parent1' }
      // child1.getName()    // 'child1'
      // child1.getSex()     // 'boy'
      // parent1.getName()   // 'parent1'
      // parent1.getSex()    // Uncaught TypeError: parent1.getSex is not a function
    
      /** --------------------------------------- */
    
      // function Parent (name) {
      //   this.name = name
      // }
      // Parent.prototype.getName = function () {
      //   console.log(this.name)
      // }
      // function Child (name) {
      //   this.sex = 'boy'
      //   Parent.call(this, name)
      // }
      // Child.prototype = new Parent()
      // Child.prototype.getSex = function () {
      //   console.log(this.sex)
      // }
      
      // var child1 = new Child('child1')
      // var parent1 = new Parent('parent1')
      // console.log(child1.constructor)  // parent
      // console.log(parent1.constructor) // parent
    
      // 原型链继承会切断child原来的原型链结构,需要加上Child.prototype.constructor = Child修正
    
      // constructor它是构造函数原型对象中的一个属性,正常情况下它指向的是原型对象。
      // 它并不会影响任何JS内部属性,只是用来标示一下某个实例是由哪个构造函数产生的而已。
      // 如果我们使用了原型链继承或者组合继承无意间修改了constructor的指向,那么出于编程习惯,我们最好将它修改为正确的构造函数。
    
      /** --------------------------------------- */
    
      // function Parent (name, colors) {
      //   this.name = name
      //   this.colors = colors
      // }
      // Parent.prototype.features = ['cute']
      // function Child (name, colors) {
      //   this.sex = 'boy'
      //   Parent.apply(this, [name, colors])
      // }
      // Child.prototype = new Parent()
      // // Child.prototype.constructor = Child
      // Child.prototype.age = '17'
      
      // var child1 = new Child('child1', ['white'])
      // child1.colors.push('yellow')
      // child1.features.push('sunshine')
      // var child2 = new Child('child2', ['black'])
      // var par = new Parent('child2', ['black'])
    
      // console.log(child1)
      // console.log(child2)
      // console.log(Child.prototype)
      // console.log(child1.features)
      // console.log(child2.features)
      // console.log(par.features)
      
      // console.log(child1 instanceof Child)
      // console.log(Child.prototype.isPrototypeOf(child1))
      // console.log(child1 instanceof Parent)
    
       /** --------------------------------------- */
    
      // function Parent (name) {
      //   console.log(name) // 这里有个console.log()
      //   this.name = name
      // }
      // function Child (name) {
      //   Parent.call(this, name)
      // }
      // Child.prototype = new Parent()
      // var child1 = new Child('child1')
      
      // console.log(child1)
      // console.log(Child.prototype)
    
      // 组合继承的缺点: 1 使用组合继承时,父类构造函数会被调用两次
      // 2 并且生成了两个实例,子类实例中的属性和方法会覆盖子类原型(父类实例)上的属性和方法,所以增加了不必要的内存。
    
      /** --------------------------------------- */
    
      // 组合继承
      // 实现方式:
    
      // 使用原型链继承来保证子类能继承到父类原型中的属性和方法
      // 使用构造继承来保证子类能继承到父类的实例属性和方法
      // 优点:
    
      // 可以继承父类实例属性和方法,也能够继承父类原型属性和方法
      // 弥补了原型链继承中引用属性共享的问题
      // 可传参,可复用
      // 缺点:
    
      // 使用组合继承时,父类构造函数会被调用两次
      // 并且生成了两个实例,子类实例中的属性和方法会覆盖子类原型(父类实例)上的属性和方法,所以增加了不必要的内存。
      // constructor总结:
    
      // constructor它是构造函数原型对象中的一个属性,正常情况下它指向的是原型对象。
      // 它并不会影响任何JS内部属性,只是用来标示一下某个实例是由哪个构造函数产生的而已。
      // 如果我们使用了原型链继承或者组合继承无意间修改了constructor的指向,那么出于编程习惯,我们最好将它修改为正确的构造函数。
    
      /** --------------------------------------- */
    
      // 5.寄生组合继承
    
      // function Parent (name) {
      //   this.name = name
      // }
      // Parent.prototype.getName = function () {
      //   console.log(this.name)
      // }
      // function Child (name) {
      //   this.sex = 'boy'
      //   Parent.call(this, name)
      // }
      // // 与组合继承的区别
      // Child.prototype = Object.create(Parent.prototype)
      // Child.prototype.constructor = Child
      
      // var child1 = new Child('child1')
      
      // console.log(child1) // Child{ sex: "boy", name: "child1" }
      // child1.getName() // "child1"
      
      // console.log(child1.__proto__) // Parent{}
      // console.log(Object.create(null)) // {}
      // console.log(new Object()) // {}
    
      //   寄生组合继承算是ES6之前一种比较完美的继承方式吧。
    
      // 它避免了组合继承中调用两次父类构造函数,初始化两次实例属性的缺点。
    
      // 所以它拥有了上述所有继承方式的优点:
    
      // 只调用了一次父类构造函数,只创建了一份父类属性
      // 子类可以用到父类原型链上的属性和方法
      // 能够正常的使用instanceOf和isPrototypeOf方法
    
      /** --------------------------------------- */
    
      // 6.原型继承
    
      // function Create(obj) {
      //   function F() {}
      //   F.prototype = obj
      //   return new F()
      // }
    
      // var cat = {
      //   heart: '❤️',
      //   colors: ['white', 'black']
      // }
      
      // var guaiguai = Create(cat)
      // var huaihuai = Create(cat)
      
      // console.log(guaiguai)
      // console.log(huaihuai)
      
      // console.log(guaiguai.heart)
      // console.log(huaihuai.colors)
    
      // 该方法的原理是创建一个构造函数,构造函数的原型指向对象,然后调用 new 操作符创建实例,并返回这个实例,本质是一个浅拷贝。
    
      // 在ES5之后可以直接使用Object.create()方法来实现
    
      /** --------------------------------------- */
    
      // 7.寄生式继承
    
      // var cat = {
      //   heart: '❤️',
      //   colors: ['white', 'black']
      // }
      // function createAnother (original) {
      //     var clone = Object.create(original);
      //     clone.actingCute = function () {
      //       console.log('我是一只会卖萌的猫咪')
      //     }
      //     return clone;
      // }
      // var guaiguai = createAnother(cat)
      // var huaihuai = Object.create(cat)
      
      // guaiguai.actingCute()
      // console.log(guaiguai.heart)
      // console.log(huaihuai.colors)
      // console.log(guaiguai)
      // console.log(huaihuai)
    
      // 实现方式:
    
      // 在原型式继承的基础上再封装一层,来增强对象,之后将这个对象返回。
      // 优点:
    
      // 再不用创建构造函数的情况下,实现了原型链继承,代码量减少一部分。
      // 缺点:
    
      // 一些引用数据操作的时候会出问题,两个实例会公用继承实例的引用数据类
      // 谨慎定义方法,以免定义方法也继承对象原型的方法重名
      // 无法直接给父级构造函数使用参数
    
      /** --------------------------------------- */
    
      // 8. 混入方式继承多个对象
    
      // function Parent() {
      //   this.name = 'parent'
      // }
      // Parent.prototype.getName = function() {
      //   console.log('parent')
      // }
      // function OtherParent(sex) {
      //   this.sex = sex
      // }
      // OtherParent.prototype.getColor = 'red'
    
      // function Child (sex) {
      //   Parent.call(this)
      //   OtherParent.call(this, sex)
      // }
      // Child.prototype = Object.create(Parent.prototype)
      // Object.assign(Child.prototype, OtherParent.prototype)
      // Child.prototype.constructor = Child
    
      // var child1 = new Child('boy')
      // // console.log(child1)
      // // child1.getName()
      // // console.log(child1.getColor)
    
      // console.log(Child.prototype.__proto__ === Parent.prototype) // true
      // console.log(Child.prototype.__proto__ === OtherParent.prototype) // false
      // console.log(child1 instanceof Parent) // true
      // console.log(child1 instanceof OtherParent) // false
    
      /** --------------------------------------- */
    
      // 9. class中的继承
    
      // class中的继承主要是extends和super
    
      // class Parent {
      //   constructor (name) {
      //     this.name = name
      //   }
      //   getName() {
      //     console.log(this.name)
      //   }
      // }
    
      // class Child extends Parent {
      //   // constructor (name, sex) {
      //   //   super(name)
      //   //   this.sex = sex
      //   // }
      //   sex = 'boy' // 等同于注释部分
      // }
    
      // var child1 = new Child('child1', 'boy')
      // console.log(child1)
      // child1.getName()
    
      // console.log(child1 instanceof Child)
      // console.log(child1 instanceof Parent)
    
      // extends 和 super必须一起使用
      // 子类必须得在constructor中调用super方法,否则新建实例就会报错,
      // 因为子类自己没有自己的this对象,而是继承父类的this对象,然后对其加工,如果不调用super的话子类就得不到this对象。
    
      /** --------------------------------------- */
    
      // class Parent {
      //   constructor () {
      //     console.log(new.target.name) // 此方法将调用两次
      //   }
      // }
    
      // class Child extends Parent {
      //   constructor () {
      //     const instance = super()
      //     console.log(instance)
      //     console.log(instance === this)
      //   }
      // }
    
      // const child1 = new Child()
      // const parent1 = new Parent()
      // console.log(child1, parent1)
    
      // Child
      // Child {}
      // true
      // Parent
      // Child{} Parent{}
    
      /** --------------------------------------- */
    
      // class Parent {
      //   constructor (name) {
      //     this.name = name
      //   }
      // }
      // class Child extends Parent {
      //   constructor (name) {
      //     this.sex = 'boy' // this调用必须放到super之后
      //     super(name)
      //   }
      // }
      // var child1 = new Child('child1')
      // console.log(child1)
    
      // 子类constructor中如果要使用this的话就必须放到super()之后
      // super当成函数调用时只能在子类的construtor中使用
    
      /** --------------------------------------- */
    
      // class Parent {
      //   constructor (name) {
      //     this.name = name
      //   }
      //   getName() {
      //     console.log(this.name)
      //   }
      // }
      // Parent.prototype.getSex = () => {
      //   console.log('boy')
      // }
      // Parent.getColors = () => {
      //   console.log(['red'])
      // }
    
      // class Child extends Parent {
      //   constructor (name) {
      //     super(name)
      //     super.getName()
      //   }
      //   initGetSex () {
      //     super.getSex()
      //   }
      //   static initColor () {
      //     super.getColors()
      //   }
      // }
    
      // const child1 = new Child('child1')
      // child1.initGetSex()
      // Child.initColor()
      // console.log(child1)
    
      /** --------------------------------------- */
    
      // class Parent {
      //   constructor () {}
      // }
      // Parent.prototype.sex  = 'boy'
      // Parent.prototype.getSex = function () {
      //   console.log(this.sex)
      // }
      // class Child extends Parent {
      //   constructor () {
      //     super()
      //     this.sex = 'girl'
      //     super.getSex()
      //   }
      // }
      // var child1 = new Child()
      // console.log(child1)
    
      // ES6规定,通过super调用父类的方法时,super会绑定子类的this
    
      /** --------------------------------------- */
    
      // function Parent () {
      //   this.name = 'parent'
      // }
      
      // class Child1 extends Parent {}
      // class Child2 {}
      // class Child3 extends Array {}
      // var child1 = new Child1()
      // var child2 = new Child2()
      // var child3 = new Child3()
      // child3[0] = 1
      
      // console.log(child1)
      // console.log(child2)
      // console.log(child3)
    
      // extends后面接着的继承目标不一定要是个class。
    
      // class B extends A {},只要A是一个有prototype属性的函数,就能被B继承。
    
      // 由于函数都有prototype属性,因此A可以是任意函数。
    
      /** --------------------------------------- */
    
      // 总结:
      /**
       * ES6中的继承:
    
        主要是依赖extends关键字来实现继承,且继承的效果类似于寄生组合继承
        使用了extends实现继承不一定要constructor和super,因为没有的话会默认产生并调用它们
        extends后面接着的目标不一定是class,只要是个有prototype属性的函数就可以了
        super相关:
    
        在实现继承时,如果子类中有constructor函数,必须得在constructor中调用一下super函数,因为它就是用来产生实例this的。
        super有两种调用方式:当成函数调用和当成对象来调用。
        super当成函数调用时,代表父类的构造函数,且返回的是子类的实例,也就是此时super内部的this指向子类。在子类的constructor中super()就相当于是Parent.constructor.call(this)。
        super当成对象调用时,普通函数中super对象指向父类的原型对象,静态函数中指向父类。且通过super调用父类的方法时,super会绑定子类的this,就相当于是Parent.prototype.fn.call(this)。
        ES5继承和ES6继承的区别:
    
        在ES5中的继承(例如构造继承、寄生组合继承) ,实质上是先创造子类的实例对象this,然后再将父类的属性和方法添加到this上(使用的是Parent.call(this))。
        而在ES6中却不是这样的,它实质是先创造父类的实例对象this(也就是使用super()),然后再用子类的构造函数去修改this。
       */
  • 相关阅读:
    zTree的学习
    spring第9天(事务)
    spring学习第8天(advisor)
    spring学习第7天(PCD以及切点表达式)
    学习spring第6天(aop获取目标方法参数)
    学习spring第五天 mybatis+spring的整合(maven多模块数据查询使用了分页和连接池),以及aop
    学习spring的第4天
    Arcgis for Js之GeometryService实现测量距离和面积
    Arcgis for Js实现graphiclayer的空间查询(续)
    Arcgis for Js实现graphiclayer的空间查询
  • 原文地址:https://www.cnblogs.com/steamed-twisted-roll/p/13840664.html
Copyright © 2011-2022 走看看