• 继承


    继承是面向对象中一个比较核心的概念。其他正统面向对象语言都会用两种方式实现继承:一个是接口实现,一个是继承。而 ECMAScript 只支持继承,不支持接口实现,而实现继承的方式依靠原型链完成。

        function Box() {                         //Box 构造
            this.name = 'Lee';
        }
        
        function Desk() {                         //Desk 构造
            this.age = 100;
        }
        
        Desk.prototype = new Box();                 //Desc 继承了 Box,通过原型,形成链条
        
        var desk = new Desk();
        alert(desk.age);
        alert(desk.name); //得到被继承的属性

     当父类中实例中有一个属性age= 100,原型中也有相同的属性age=200;那么当子类继承父类后,子类调用属性age返回的结果是什么呢?

      function Box() {                         //Box 构造
            this.name = 'Lee';
        }
        Box.prototype.name = 'jack';    
        
        function Desk() {                         //Desk 构造
            this.age = 100;
            //this.name='huangjanfeng';                //如果子类中也有name属性,那么子类调用该属性,返回的是子类中的属性值
        }
        
    
        Desk.prototype = new Box();                 //Desc 继承了 Box,通过原型,形成链条
        
        var desk = new Desk();
        alert(desk.age);
        alert(desk.name); //结果是Lee,就近原则,实例里有,就返回实例中的,没有就去原型中找

    以上原型链继承还缺少一环,那就是 Obejct,所有的构造函数都继承自 Obejct。而继承 Object 是自动完成的,并不需要程序员手动继承。

    经过继承后的实例,他们的从属关系会怎样呢?(Desk继承Box,Table继承Desk的情况下)

    alert(table instanceof Object); //true
    alert(desk instanceof Table); //false,desk 是 table 的超类
    alert(table instanceof Desk); //true
    alert(table instanceof Box); //true

    为了解决引用共享和超类型无法传参的问题,我们采用一种叫借用构造函数的技术,或者成为对象冒充(伪造对象、经典继承)的技术来解决这两种问题。

        /*对象冒充,只能继承构造里的信息,不能继承原型中的信息*/
        function Box(age) {
            this.name = ['Lee', 'Jack', 'Hello']
            this.age = age;
        }
        
        function Desk(age) {
            Box.call(this, age);             //对象冒充,给超类型传参  
        }
        
        var desk = new Desk(200);
        alert(desk.age);
        alert(desk.name);
        desk.name.push('AAA');                 //添加的新数据,只给 desk   再创建一个desk对象,中没有AAA这个值
        alert(desk.name);

    借用构造函数虽然解决了刚才两种问题,但没有原型,复用则无从谈起。所以,我们需要原型链 借用构造函数的模式,这种模式成为组合继承。

        function Box(age) {
            this.name = ['Lee', 'Jack', 'Hello']
            this.age = age;
        }
        
        //构造函数里的方法,放在构造里,每次实例化,都会分配一个内存地址,浪费空间,所以最好放在原型中,包中多次实例化只有一个地址
        Box.prototype.run = function () {        
            return this.name + this.age;
        };
        
        function Desk(age) {
            Box.call(this, age); //对象冒充
        }
        
        Desk.prototype = new Box(); //原型链继承
    var desk = new Desk(100); alert(desk.run());//使用对象冒充(继承构造函数里的),和原型链继承(继承原型里的),

    还有一种继承模式叫做:原型式继承;这种继承借助原型并基于已有的对象创建新对象,同时还不必因此创建自定义类型。

        //临时中转函数
        function obj(o) {                     //传递一个字面量对象,
            function F() {}                 //F构造时一个临时新建的对象,用来存储传递过来的对象
            F.prototype = o;                 //把传进来字面量对象赋值给F构造函数的原型
            return new F();                 //最终返回出实例化的构造函数
        }
        
      //F.prototype= o; //其实就相当于Desk.prototype = new Box();
    var box = { //字面量对象 相当于var box = new box(); name : 'Lee', arr : ['哥哥','妹妹','姐姐'] };
      
    var box1 = obj(box); //传递 box1就相当于new F(); alert(box1.name); box1.name = 'Jack'; alert(box1.name); alert(box1.arr); box1.arr.push('父母'); alert(box1.arr); var box2 = obj(box); //传递 alert(box2.name); alert(box2.arr); //引用类型共享了

    寄生式继承:把原型式+工厂模式结合而来,目的是为了封装创建对象的过程。

        //临时中转函数
        function obj(o) {                     //传递一个字面量函数
            function F() {}                 //创建一个构造函数
            F.prototype = o;                 //把字面量函数赋值给构造函数的原型
            return new F();                 //最终返回出实例化的构造函数
        }
        
        function create(o) {                 //封装创建过程
            var f= obj(o);
            f.run = function () {
                return this.arr;             //同样,会共享引用
            };
            return f;
        }
        
        var box = {                         //字面量对象  相当于var box  = new box();
            name : 'Lee',
            arr : ['哥哥','妹妹','姐姐']
        };
        
        var box1 = obj(box); 
        alert(box1.name);
        box1.name = 'Jack';
        alert(box1.name);
        alert(box1.arr);
        
        box1.arr.push('父母');
        alert(box1.arr);
        
        var box2 = obj(box); //传递
        alert(box2.name);
        alert(box2.arr); //引用类型共享了

    组合式继承是 JavaScript 最常用的继承模式;但,组合式继承也有一点小问题,就是超类型在使用过程中会被调用两次:一次是创建子类型的时候,另一次是在子类型构造函数的内部。

        function Box(name) {
            this.name = name;
            this.arr = ['哥哥','妹妹','父母'];
        }
        
        Box.prototype.run = function () {
            return this.name;
        };
        function Desk(name, age) {
            Box.call(this, name); //第二次调用 Box
            this.age = age;
        }
        Desk.prototype = new Box(); //第一次调用 Box

    以上代码是之前的组合继承,那么寄生组合继承,解决了两次调用的问题

       function obj(o) {
            function F() {}
            F.prototype = o;return new F();
        }
        function create(box, desk) {
            var f = obj(box.prototype);
            f.constructor = desk;
            desk.prototype = f;
        }
        function Box(name) {
            this.name = name;
            this.arr = ['哥哥','妹妹','父母'];
        }
        Box.prototype.run = function () {
            return this.name;
        };
        function Desk(name, age) {
            Box.call(this, name);
            this.age = age;
        }
        create(Box, Desk); //通过这里实现继承
        
        var desk = new Desk('Lee',100);
        desk.arr.push('姐姐');
        alert(desk.arr);
        alert(desk.run()); //只共享了方法
        
        var desk2 = new Desk('Jack', 200);
        alert(desk2.arr); //引用问题解决

    原型的应用1(在使用js数组或者字符串对象的操作中,如果功能不够了。只能自己写,那么我们可以通过原型来给对象添加自定义的方法)

    //我们要调用一个方法就能获取该数组中的最大值,而数组并没有提供获取最大值的功能,那么我们可以通过原型来实现
        //this代表本类对象,谁调用,代表谁
        Array.prototype.getMax = function(){
            var max = this[0];
            for(var x = 1;x<this.length;x++){
                if(this[x]>max){
                    max=this[x];
                }
            }
            return max;
        }
    
        //定义一个数组
        var arr = [321,32,432,4,23,4,23];
        alert(arr.getMax());

    需求:去除字符串两端的空格,

  • 相关阅读:
    JS从后台获取数据,前台动态添加tr标签中的td标签
    Java方式导出EXCEL表格
    框架搭建相关博文
    Spring框架相关博文集
    Eclipse相关工具使用
    关于Spring Boot的博客集合
    Springboot spring data jpa 多数据源的配置01
    springboot1.X 到2.X 的改变
    Spring-Boot devtools项目自动重启
    JSR 303
  • 原文地址:https://www.cnblogs.com/LO-ME/p/3602371.html
Copyright © 2020-2023  润新知