• js 中的继承


    继承就是让一个对象拥有另一个对象的属性和方法

    一、原型链继承(两种)

      1、Son.prototype = Father.prototype (原型继承)

      (1)Son的实例对象只能继承Father实例中原型的方法,无法继承Father本身的属性。

    function Father(){
        this.age = 50;
        this.h = 15
    }
    Father.prototype.eat = function(){
        console.log(this.age); // 25 
        console.log(this.h); // undefined
    }
    function Son(){
        this.age = 25;
    }
    Son.prototype = Father.prototype;
    var son = new Son()
    son.eat()
    // son继承Father原型中的eat函数,所以this.age指向Son,故 25
    // this.h 弹出undefined 说明无法继承Father本身的属性

      2、Son.prototype = new Father() (实例化对象继承)

      原理:就是把构造函数Father()的实例化对象father的属性和方法继承到构造函数Son()的原型上。修改的属性是实例化对象father的属性,每次实例化一个构造函数Son(),都是从father上继承,故属性相通。

      (1)优先查找自身属性,如果有的话优先使用,如果没有则从继承中查找

      (2)继承的构造函数的不同实例化对象的属性不会互相影响;不同的Son实例对象会共享继承Father的实例化对象father的属性。这样的话修改一个Son实例化对象son的arr,Son实例化对象son1的arr也会改变,修改被继承Fathe实例化对象father的属性时会影响继承者Son继承的属性

    function Father(){
        this.age = 50;
        this.arr = [1,2,3]
        this.h = 15;
    }
    Father.prototype.eat = function(){
        console.log(this.age); 
        console.log(this.h);
    }
    function Son(){
        this.age = 25;    
    }
    var father = new Father();
    Son.prototype = father;
    var son = new Son();
    son.eat();
    // 25 说明当son优先查找自身属性
    // 15 说明son继承Father实例对象的属性
    son.arr.push(4)
    console.log(son.arr); // [1,2,3,4]
    console.log(father.arr)  // [1,2,3]
    var son1 = new Son()
    console.log(son1.arr);// [1,2,3,4] 说明不同的Son实例对象会共享继承Father的实例化对象father的属性
    father.arr.push(5)
    console.log(father.arr)// [1,2,3,5]
    console.log(son.arr);// [1,2,3,4,5] 说明修改被继承Fathe实例化对象father的属性时会影响继承者Son继承的属性

      对于继承后 Son.prototype.constructor指向的问题,是否需要修改可以查看 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor

    二、构造函数继承

      在继承构造函数里通过call或者apply或bind修改被继承函数的this。

      1、继承属性会覆盖自身属性,

      2、继承的构造函数的不同实例化对象的属性不会互相影响

      3、无法继承原型上的方法,

    function Father(){
        this.age = 50;
        this.hello = "你好";
        this.arr = [1,2,3];
    }
    Father.prototype.cat = function(){
        console.log(cat);
    }
    function Son(){
        // 三种方式
        this.age = 25;
        Father.call(this);
        // Father.bind(this)();
        // Father.apply(this);
    }
    var son = new Son(15)
    console.log(son.age); // 50 // 说明继承属性会覆盖自身属性
    console.log(son.hello); // 你好
    try{
        son.cat()
    }catch(e){
        console.log(e); 
    // TypeError: son.cat is not a function
    }
    son.arr.push(4);
    console.log(son.arr); // [1,2,3,4]
    var son1 = new Son(25);
    console.log(son1.arr); // [1,2,3]
    // 这说明构造函数Son的不同实例化对象的属性是不相通,修改实例化对象  

    三、组合式继承 (原型链与构造函数)

      在原型链继承中Son.prototype = Father.prototype只能继承Fanther的原型上的方法,在构造函数继承中,Fathe.call(this)只能继承构造函数的属性,两者结合。

      1、继承属性会覆盖自身属性

      2、继承的构造函数的不同实例化对象的属性不会互相影响

    function Father(){
    	this.age = 50;
    	this.hello = "你好";
    	this.arr = [1,2,3];
    };
    Father.prototype.eat=function(){
    	console.log("这是Father构造函数原型上方法");
    }
    function Son(){
    	this.age = 25;
    	Father.call(this)
    };
    Son.prototype = Father.prototype;
    
    var son = new Son();
    console.log(son.age); // 50 说明继承的属性会覆盖自身的属性
    console.log(son.hello); //你好
    son.arr.push(4)
    son.eat()
    var son1 = new Son();
    console.log(son.arr); //[1,2,3,4]
    console.log(son1.arr); // [1,2,3]
    // 说明同一构造函数的不同实例化对象之间属性不相通;
    

      弊端:通过Father.call() 和Father.prototype ,父类构造函数Father被调用了两次。继承属性会覆盖原属性

    四、原型式继承 (个人认为这种方式和原型链Son.prototype = new Father()的原理是一致的,各种表现也是一致)

      1、优先查找自身属性,如果有的话优先使用,如果没有则从继承中查找

      2、继承的构造函数的不同实例化对象的属性不会互相影响;

    function Father(){
        this.age = 50;
        this.hello = "你好";
        this.arr = [1,2,3]
    };
    Father.prototype.eat = function(){
        console.log("这是Father原型上的方法");
    }
    function content(obj){
        function Son(){
            this.age = 25;
        };
        Son.prototype = obj; // 传入继承构造函数Father的实例化对象father
        return new Son();
    }
    var father = new Father();
    var son = content(father);
    console.log(son.hello); //你好 说明继承构造函数Father实例化对象father上的属性。
    console.log(son.age); // 25 // 说明优先查找自身是否有某属性,有的话优先调用自身属性
    son.eat() // 这是Father原型上的方法  说明继承了构造函数Father实例化对象father上的方法
    
    son.arr.push(4)
    var son1 = content(father)
    console.log(son.arr); // [1,2,3,4]
    console.log(son1.arr); // [1,2,3,4] 说明这个不同实例间继承的属性是相通的

    五、寄生式继承(在原型式继承的基础上,对Son实例化的外面添加函数封装而已,表现一致)

      1、优先查找自身属性,如果有的话优先使用,如果没有则从继承中查找

      2、继承的构造函数的不同实例化对象的属性不会互相影响;

    function Father(){
        this.age = 50;
        this.hello = "你好";
        this.arr = [1,2,4];
    };
    Father.prototype.eat = function(){
        console.log("这是Father构造函数原型上的方法");
    }
    function content(obj){
        function Son(){
            this.age = 25;
        };
        Son.prototype = obj;
        return new Son();
    }
    function subObject(obj){
        var son = content(obj)
        son.name = 'son 名字' // 可直接对son添加属性
        return son
    }
    var father = new Father()
    var son1 = subObject(father) 
    console.log(son1.age);//25
    console.log(son1.hello);//你好
    console.log(son1.name); // son 名字
    son1.eat(); // 这是构造函数原型上的方法
    son1.arr.push(4)
    var son2 = content(father)
    console.log(son1.arr); // [1,2,3,4]
    console.log(son2.arr); // [1,2,3,4] 说明这个不同实例间继承的属性是相通的

    六、寄生组合式继承  (构造函数继承与寄生式继承组合)

      1、寄生属性会覆盖原属性

      2、继承的构造函数的不同实例化对象的属性不会互相影响

      3、与组合式继承相比效果相同,但是更加复杂。

    function Father(){
        this.age = 50;
        this.hello = "你好";
        this.arr = [1,2,3];
    };
    function content(obj){
        function Son(){
            this.age = 25;
        };
        Son.prototype = obj;
        return new Son();
    };
    var son = content(Father.prototype)
    // var son = content(new Father()) 效果一致
    
    function Sub(){
        Father.call(this);
        // Father.apple(this);
        // Father.bind(this)();
    };
    Sub.prototype = son; 
    son.constructor = Sub;
    var sub = new Sub();
    console.log(sub.age); // 50 说明继承的属性会覆盖自身的属性
    console.log(sub.hello); // 你好
    sub.arr.push(4)
    console.log(sub.arr); // [1,2,3,4]
    var sub1 = new Sub();
    console.log(sub1.arr); // [1,2,3]
    // 说明同一构造函数的不同实例化对象之间属性不相通;

     七、Object.assign()  

      与组合式继承基本相同,除了Son.prototype = Object.create(Father.prototype),对原型继承的方式不一样

      1、寄生属性会覆盖原属性

      2、继承的构造函数的不同实例化对象的属性不会互相影响

    // Father - 父类(superclass)
    function Father() {
      this.age = 50;
      this.arr = [1,2,3]
    }
    
    // 父类的方法
    Father.prototype.move = function(x, y) {
      console.info('Father moved.');
    };
    
    // Son - 子类(subclass)
    function Son() {
        this.age = 25;
      Father.call(this); // call super constructor.
    }
    
    // 子类续承父类
    Son.prototype = Object.create(Father.prototype);
    // Son.prototype.constructor = Son;
    
    var son = new Son();
    console.log(son.age); // 50 说明继承属性覆盖原属性
    son.move(); // Father moved
    son.arr.push(4)
    console.log(son.arr); // [1,2,3,4]
    var son1 = new Son();
    console.log(son1.arr); // [1,2,3]
    // 说明不同实例之间数据不相通,可复用

        

      

  • 相关阅读:
    iOS NSString的常用用法
    有序数组在数据量较少时候的查找效率比较
    【转载】gdb基本命令总结
    从一个笔误引起的思考
    常见性能优化小技巧原理
    使用T-SQL进行活动目录查询
    你需要一条怎样的牛仔裤?
    #VSTS日志# 2015/12/10 – 终于可以删除工作项了
    #VSTS定制#全新的模版定制能力
    混合使用TFVC和GIT配置库的优化方案
  • 原文地址:https://www.cnblogs.com/aidixie/p/12807935.html
Copyright © 2020-2023  润新知