zoukankan      html  css  js  c++  java
  • js 继承,Object.setPrototypeOf | Object.getPrototypeOf | Object.create class

    https://juejin.im/post/5cfd9d30f265da1b94213d28#heading-14

    https://juejin.im/post/5d124a12f265da1b9163a28d

    https://juejin.im/post/5b44a485e51d4519945fb6b7#heading-19

    //1.原型链继承  与Object.create()一样
    // 特点(1)通过原型来实现继承时,原型会变成另一个类型的实例;子实例会混入父实例的方式与属性 
    // 原先的实例属性变成了现在的原型属性,该原型的引用类型属性会被所有的实例共享。
    // (2)在创建子类型的实例时,没有办法在不影响所有对象实例的情况下给超类型的构造函数中传递参数
        function Parent(name,role){
            this.name=name;
            this.role=role;
            this.color=['red','yellow','hotpink']
        }
        Parent.prototype.getName=function(){return this.name};
        function Child(role){
            this.crole=role;
            this.name=role+'999'  //新的实例对象里原型会包含父实例的属性方法;子实例会再次赋值
        }
        Child.prototype=new Parent('wade','papa');
        var child1=new Child('child1')
        child1.color.push('white'); //color: (5) ["red", "yellow", "hotpink", "white", "white"]
        console.log(child1)  //Child {crole: "child1", name: "child1999"} 
    
        var child2=new Child('child2')
        child2.color.push('white'); //color: (5) ["red", "yellow", "hotpink", "white", "white"]
        console.log(child2) //Child {crole: "child2", name: "child2999"}
    
    // 2.借助构造函数
    // (1)解决了原型中包含引用类型值被所有实例共享的问题;但没继承父类的原型
        function Parent(name,role){
            this.name=name;
            this.role=role;
            this.color=['red','yellow','hotpink']
        }
        Parent.prototype.getName=function(){return this.name};
        function Child(name,role){
            Parent.call(this,name,role)
        }
        var child1=new Child('ken','child1');
        child1.color.push('white')
        console.log(child1)
        var child2=new Child('peter','child2');
        child2.color.push('white')
        console.log(child2)
    
    // 3.组合继承(原型链 + 借用构造函数)
    // 基本思路:使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承,
    // 既通过在原型上定义方法来实现了函数复用,又保证了每个实例都有自己的属性。可以继承实例属性/方法,也可以继承原型属性/方法
    // (1)new了两次 而且new父类会造成父类的实例无用属性挂在在子类实例的原型上
    // (2)可以向超类传递参数;每个实例都有自己的属性;实现了函数复用
        function Parent(name,role){
            this.name=name;
            this.role=role;
            this.color=['red','yellow','hotpink']
        }
        Parent.prototype.getName=function(){return this.name};
        function Child(name,role){
            Parent.call(this,name,role)
        }
        Child.prototype=new Parent();
        Child.prototype.constructor=Child;
    
        var child1=new Child('ken','child1');
        child1.color.push('white')
        console.log(child1)
        var child2=new Child('peter','child2');
        child2.color.push('white')
        console.log(child2)
    
    //3-1组合继承优化 减少new父类实例添加多余的属性方法到子类实例的原型上
    // child1 instanceOf Parent =>true   child1 instanceOf Child =>true 
    // 可用 child1.constructor去找
        function Parent(name,role){
            this.name=name;
            this.role=role;
            this.color=['red','yellow','hotpink']
        }
        Parent.prototype.getName=function(){return this.name};
        function Child(name,role){
            Parent.call(this,name,role)
        }
        Child.prototype=Parent.prototype;
        Child.prototype.constructor=Child;
        var child1=new Child('ken','child1');
    // 3-2组合继承优化 
        function Parent(name,role){
            this.name=name;
            this.role=role;
            this.color=['red','yellow','hotpink']
        }
        Parent.prototype.getName=function(){return this.name};
        function Child(name,role){
            Parent.call(this,name,role)
        }
        Child.prototype=Object.create(Parent.prototype);
        Child5.prototype.constructor = Child5;
        var child1=new Child('ken','child1');

    // 4.寄生组合继承
        // 通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性
        // 只调用了一次超类构造函数,效率更高。避免在Child.prototype上面创建不必要的、多余的属性,与其同时,
        // 原型链还能保持不变。 因此寄生组合继承是引用类型最理性的继承范式。
        function Parent(name,role){
            this.name=name;
            this.role=role;
            this.color=['red','yellow','hotpink']
        }
        Parent.prototype.getName=function(){return this.name};
        function Child(name,role){
            Parent.call(this,name,role)
        }
        (
            function(){
                function F(){}
                F.prototype=Parent.prototype;
                Child.prototype=new F();
            }
        )()
        var child1=new Child('ken','child1');
    

    // 5寄生式组合 function parasitic(target){ function F(){} F.prototype=target.prototype; return new F(); } function createAnother(target){ var resultPrototype=parasitic(target); resultPrototype.sayHi=function(){ console.log('hi'); } return resultPrototype; } function Parent(name,role){ this.name=name; this.role=role; this.color=['red','yellow','hotpink'] } Parent.prototype.getName=function(){return this.name}; function Child(name,role){ Parent.call(this,name,role) } Child.prototype=createAnother(Parent); Child.prototype.constructor=Child; var child1=new Child('ken','child1');

    ES6 的 class 允许子类继承父类的静态方法和静态属性

    class MyParent{
        static role='parent';
        static getRole=()=>{return this.role}
    }
    
    MyParent.getRole() //parent
    
    class Mychild extends MyParent{}
    Mychild.getRole() //"parent"
    静态属性与方法:https://www.jb51.net/article/126399.htm

    Object.setPrototypeOf(obj, proto),用来将obj.__proto__设置为proto
    Object.getPrototypeOf(obj),返回obj.__proto__
    function Parent(){
        this.name='i am parent test';
    };
    Parent.role="parent111";
    Parent.getRole=function(){return this.role};
    let temObj=Object.setPrototypeOf({},Parent); //等效于 {}.__proto__=Parent return{}

     Object.create(proto, [propertiesObject])    //方法创建一个新对象,并且该对象继承了proto。其实第一个参数可以理解为添加到原型上的,第二个参数理解为添加到实例对象上的

    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create

    https://www.jianshu.com/p/28d85bebe599

    // Shape - 父类(superclass)
    function Shape() {
      this.x = 0;
      this.y = 0;
    }
    
    // 父类的方法
    Shape.prototype.move = function(x, y) {
      this.x += x;
      this.y += y;
      console.info('Shape moved.');
    };
    
    // Rectangle - 子类(subclass)
    function Rectangle() {
      Shape.call(this); // call super constructor.
    }
    
    // 子类续承父类
    Rectangle.prototype = Object.create(Shape.prototype);
    Rectangle.prototype.constructor = Rectangle;
    
    var rect = new Rectangle();
    
    console.log('Is rect an instance of Rectangle?',
      rect instanceof Rectangle); // true
    console.log('Is rect an instance of Shape?',
      rect instanceof Shape); // true
    rect.move(1, 1); // Outputs, 'Shape moved.'

     

    ES6继承

    function Parent(){
        this.role='parent';
        this.color=['red','black','hotpink']
    }
    Parent.prototype.giveMoney=()=>{console.log('$100')};
    
    var parent1=new Parent();
    
    var child1=Object.create(Object.getPrototypeOf(parent1),Object.getOwnPropertyDescriptors({cRole:'child'}))
    child1.cRole
    child1.giveMoney()  // $100

    Class的super ,分两种情况 https://www.jb51.net/article/126399.htm 

    1、当作函数使用

    class A {
     constructor() {
      console.log(new.target.name); //new.target指向当前正在执行的函数
     }
    }
    class B extends A {
     constructor() {
      super();
     }
    }
    new A() // A
    new B() // B super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,因此super()在这里相当于A.prototype.constructor.call(this)。

    2、当作对象使用,这里也有存和取的区别,存的时候相当于super.x==this.x;取的时候是在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

    class A {
     c() {
      return 2;
     }
    }
    class B extends A {
     constructor() {
      super();
      console.log(super.c()); // 2  super在普通方法之中,指向A.prototype,所以super.c()就相当于A.prototype.c()。
     }
    }
    let b = new B();
    //通过super调用父类的方法时,super会绑定子类的this。
    class A {
     constructor() {
      this.x = 1;
     }
     s() {
      console.log(this.x);
     }
    }
    class B extends A {
     constructor() {
      super();
      this.x = 2;
     }
     m() {
      super.s();
     }
    }
    let b = new B();
    b.m() // 2    super.s() == A.prototype.s.call(this)
    class A {
     constructor() {
      this.x = 1;
     }
    }
    class B extends A {
     constructor() {
      super();
      this.x = 2;
      super.x = 3;
      console.log(super.x); // undefined 
      console.log(this.x); // 3
     }
    }
    let b = new B(); 
    //super.x赋值为3,这时等同于对this.x赋值为3。而当读取super.x的时候,读的是A.prototype.x,所以返回undefined。


  • 相关阅读:
    ThinkPHP中的json对象
    ThinkPHP修改默认错误页面
    E签宝签署短信后回调通知数据结构示例
    E签宝电子签章接口调试请求和响应示例
    Git如何撤销本地所有的更改操作还原到更改前的代码?
    使Egg.js编写RestfulAPI接口(六)路由分组
    使用Egg.js编写RestfulAPI接口(五)资源路由配置
    使用Egg.js编写RestfulAPI接口(四)使用PostMain测试Api接口
    使用Egg.js编写RestfulAPI接口(三)编写Api接口
    使用Egg.js编写RestfulAPI接口(二)配置跨域
  • 原文地址:https://www.cnblogs.com/little-ab/p/11097825.html
Copyright © 2011-2022 走看看