• javascript继承分析


    一,传统JS继承方法:

      1,原型式继承:

        

    //声明父类
    function Person(name,age){   
        this.name = name;
        this.age = age;
        this.flag = true;
    }
    // 给父类添加方法
    Person.prototype.sayName = function(){
        console.log(this.name);
    }
    
    //实例化父类
    var person = new Person('zhl',30);
    //调用父类方法
    person.sayName();  // zhl
    
    // 声明子类
    function Worker(name,age,work){
        this.name = name;
        this.age = age;
        this.work = work;
    }
    //原型式继承  其实就是子类的原型指向父类的一个实例
    Worker.prototype = new Person();
    //给子类添加方法
    Worker.prototype.sayWork = function(){
        console.log(this.work);
    }
    
    //实例化一个子类
    var worker = new Worker('vsmart',32,'itcoder');
    //调用子类方法
    worker.sayName();  // vsmart
    worker.sayWork(); // itcoder

      貌似可以用了,不要高兴太早,这里是有很大的坑的!

      此继承方法有几个弊端:

      1,声明父类与子类的构造函数中有很多重复的初始化赋值;

      2,实例化子类的对象 flag 属性竟然是 true

        然而这个属性本身子类并没有初始化,哪来的?

        console.log(worker.flag) //true
        console.log(Worker.prototype.flag) //true

        哦,原来是从子类的原型上查找到的,也就是从父类的一个实例上获取到的;

        本来我们要做到 属性与方法分离的,现在呢,这个属性竟然在原型上,原型应该只放方法才对。

      3,子类的构造函数 constructor 竟然指向了 父类的 constructor,这个指向错误将来势必会带来耦合

        console.log(worker.constructor)  //

    function Person(name,age){
        this.name = name;
        this.age = age;
        this.flag = true;
    }

      综合以上几点我们要做优化;

      1,我们可以借用父类的构造函数初始化子类的构造函数  利用 apply 或 call 改变指向

      2,我们要重新改变子类的构造函数指向

      

    //声明父类
    function Person(name,age){   
        this.name = name;
        this.age = age;
        this.flag = true;
    }
    // 给父类添加方法
    Person.prototype.sayName = function(){
        console.log(this.name);
    }
    
    //实例化父类
    var person = new Person('zhl',30);
    //调用父类方法
    person.sayName();  // zhl
    
    // 声明子类
    function Worker(name,age,work){
        Person.apply(this,arguments);  // 借用父类构造方法
        this.work = work;
        this.flag = false;
    }
    //原型式继承  其实就是子类的原型指向父类的一个实例
    Worker.prototype = new Person();
    //给子类添加方法
    Worker.prototype.sayWork = function(){
        console.log(this.work);
    }
    //改变constructor指向
    Worker.prototype.constructor = Worker;
    
    //实例化一个子类
    var worker = new Worker('vsmart',32,'itcoder');
    //调用子类方法
    worker.sayName();  // vsmart
    worker.sayWork(); // itcoder
    
    console.log(worker.flag) //false    //子类自己的属性
    console.log(Worker.prototype.flag)  //true  从子类原型上查找
    console.log(worker.constructor) //正确指向自己的构造方法

      function Worker(name,age,work){
        Person.apply(this,arguments);
        this.work = work;
        this.flag = false;
      }



       2,混合拷贝继承:

         所谓混合拷贝继承是指,构造函数还是借用父类的方式,但方法继承就是模拟拷贝的方式,

        

    //声明父类
    function Person(name,age){   
        this.name = name;
        this.age = age;
        this.flag = true;
    }
    // 给父类添加方法
    Person.prototype.sayName = function(){
        console.log(this.name);
    }
    
    //实例化父类
    var person = new Person('zhl',30);
    //调用父类方法
    //person.sayName();  // zhl
    
    // 声明子类
    function Worker(name,age,work){
        Person.apply(this,arguments);
        this.work = work;
        this.flag = false;
    }
    //拷贝继承
    extends2(Worker.prototype,Person.prototype);
    //貌似这样也可以啊:
    //Object.setPrototypeOf(Worker.prototype, Person.prototype);
    //给子类添加方法 Worker.prototype.sayWork = function(){ console.log(this.work); } //拷贝继承核心方法 function extends2(child,parent){ for(var attr in parent){ if(parent.hasOwnProperty(attr)){ child[attr] = parent[attr]; } } } //实例化一个子类 var worker = new Worker('vsmart',32,'itcoder'); //调用子类方法 worker.sayName(); // vsmart worker.sayWork(); // itcoder console.log(worker.flag) //false //子类自己的属性 console.log(Worker.prototype.flag) //undefined 子类原型上没有查找到 console.log(worker.constructor) // /*function Worker(name,age,work){ Person.apply(this,arguments); this.work = work; this.flag = false; }*/

     二,ES5中的继承:

      

    //声明父类
    function Person(name,age){   
        this.name = name;
        this.age = age;
        this.flag = true;
    }
    // 给父类添加方法
    Person.prototype.sayName = function(){
        console.log(this.name);
    }
    
    // 声明子类
    function Worker(name,age,work){
        Person.apply(this,arguments);
        this.work = work;
        this.flag = false;
    }
    //继承
    Worker.prototype = Object.create(Person.prototype,{
        hobby:{
            value:'play',
            enumerable:true
        }
    });
    //改变constructor指向
    Worker.prototype.constructor = Worker;
    
    //给子类添加方法
    Worker.prototype.sayWork = function(){
        console.log(this.work);
    }
    
    //实例化一个子类
    var worker = new Worker('vsmart',32,'itcoder');
    //调用子类方法
    worker.sayName();  // vsmart
    worker.sayWork(); // itcoder
    console.log(worker.hobby) //play
    
    console.log(worker.constructor)   //
    /*function Worker(name,age,work){
        Person.apply(this,arguments);
        this.work = work;
        this.flag = false;
    }*/

     三,ES6中的继承

      

    class Person{
        //父类构造函数
        constructor(name,age){
            this.name = name;
            this.age = age;
        }
        //父类方法
        sayName(){
            console.log(this.name);
        }
    }
    
    class Worker extends Person{
        //子类构造函数
        constructor(name,age,work){
            //调用父类构造函数
            super(name,age);
            //自身独有的属性
            this.work = work;
        }
        //自身独有的方法
        sayWork(){
            console.log(this.work);
        }    
    }
    let person = new Person('zhl',30);
    person.sayName(); //zhl
    //实例化一个子类
    let worker = new Worker('vsmart',32,'itcoder');
    worker.sayName(); //vsmart
    worker.sayWork(); //itcoder
    
    console.log(worker.constructor)// 实例构造函数constructor指向
    // class Worker extends Person{
    //     constructor(name,age,work){
    //         super(name,age);
    //         this.work = work;
    //     }
    //     sayWork(){
    //         console.log(this.work);
    //     }    
    // }
  • 相关阅读:
    [c++]在类中定义常量的几个做法
    VC6中使用高版本系统API的方法
    Delphi编程中实现窗口分割
    Win32 SDK窗口程序代码(含详细注释)
    [c++]在C++中定义常量的两种方法的比较
    VC6里的_WIN32_WINNT宏
    [VC]自己实现TRACE功能
    [delphi]保证程序只运行一个实例
    转载:C# 设置文件夹权限(代码简单)
    VC:动态链接库
  • 原文地址:https://www.cnblogs.com/vsmart/p/7595869.html
Copyright © 2020-2023  润新知