• JavaScript继承的实现


    怎样在JavaScript中实现简单的继承? 

    以下的样例将创建一个雇员类Employee,它从Person继承了原型prototype中的全部属性。

    function Employee(name, sex, employeeID) {
        this.name = name;
        this.sex = sex;
        this.employeeID = employeeID;
    }
    // 将Employee的原型指向Person的一个实例
    // 由于Person的实例能够调用Person原型中的方法, 所以Employee的实例也能够调用Person原型中的全部属性。
    Employee.prototype = new Person();
    Employee.prototype.getEmployeeID = function() {
        return this.employeeID;
    };
    var zhang = new Employee("ZhangSan", "man", "1234");
    console.log(zhang.getName()); // "ZhangSan

    上面关于继承的实现非常粗糙,而且存在非常多问题:

    • 在创建Employee构造函数和原型(以后简称类)时,就对Person进行了实例化,这是不合适的。
    • Employee的构造函数没法调用父类Person的构造函数,导致在Employee构造函数中对name和sex属性的反复赋值。
    • Employee中的函数会覆盖Person中的同名函数,没有重载的机制(和上一条是一个类型的问题)。
    • 创建JavaScript类的语法过于零散,不如C#/Java中的语法优雅。
    • 实现中有constructor属性的指向错误。


    正由于JavaScript本身没有完整的类和继承的实现,而且我们也看到通过手工实现的方式存在非常多问题, 因此对于这个富有挑战性的任务网上已经有非常多实现了:

    这篇文章将会给出一个可行的实例代码详细分析这些实现,终于达到对JavaScript中怎样实现类和继承,希望对你理解JavaScript有一定的帮助。

    ( function() {
        jClass = function() {
        };
        // 当前是否处于创建类的阶段
        var initializing = false;
        jClass.extend = function( prop ) {
            var baseClass = null;
            // 假设调用当前函数的对象(这里是函数)不是Class,则是父类
            if ( this !== jClass ) {
                baseClass = this;
            }
            // 本次调用所创建的类(构造函数)
            var jConstructor = function() {
                // 假设当前处于实例化类的阶段,则调用init原型函数
                if ( !initializing ) {
                    // 假设父类存在,则实例对象的baseprototype指向父类的原型
                    // 这就提供了在实例对象中调用父类方法的途径
                    if ( baseClass ) {
                        this._superprototype = baseClass.prototype;
                    }
                    this.init.apply( this, arguments );
                }
            }
            // 假设此类须要从其他类扩展
            if ( baseClass ) {
                initializing = true;
                jConstructor.prototype = new baseClass();
                jConstructor.prototype.constructor = jConstructor;
                initializing = false;
            }
            // 新创建的类自己主动附加extend函数
            jConstructor.extend = arguments.callee;
    
            // 覆盖父类的同名函数
            for ( var name in prop ) {
                if ( prop.hasOwnProperty( name ) ) {
                    // 假设此类继承自父类baseClass,而且父类原型中存在同名函数name
                    if ( baseClass &&
                            typeof ( prop[name] ) === "function" &&
                            typeof ( jConstructor.prototype[name] ) === "function" &&
                            /_super/.test( prop[name] ) ) {
                        // 重定义函数name - 
                        // 首先在函数上下文设置this._super指向父类原型中的同名函数
                        // 然后调用函数prop[name],返回函数结果
                        // 注意:这里的自运行函数创建了一个上下文,这个上下文返回还有一个函数,
                        // 此函数中能够应用此上下文中的变量,这就是闭包(Closure)。
                        // 这是JavaScript框架开发中经常使用的技巧。
                        jConstructor.prototype[name] = ( function( name, fn ) {
                            return function() {
                                this._super = baseClass.prototype[name];
                                return fn.apply( this, arguments );
                            };
                        } )( name, prop[name] );
                    } else {
                        jConstructor.prototype[name] = prop[name];
                    }
                }
            }
            return jConstructor;
        };
    } )();
    
    
    // Demo
    var Person = jClass.extend( {
        init: function( name ) {
            this.name = name;
        },
        getName: function( prefix ) {
            return prefix + this.name;
        }
    } );
    var Employee = Person.extend( {
        init: function( name, employeeID ) {
            //  调用父类的方法
            this._super( name );
            this.employeeID = employeeID;
        },
        getEmployeeIDName: function() {
            // 注意:我们还能够通过这样的方式调用父类中的其他函数
            var name = this._superprototype.getName.call( this, "Employee name: " );
            return name + ", Employee ID: " + this.employeeID;
        },
        getName: function() {
            //  调用父类的方法
            return this._super( "Employee name: " );
        }
    } );
    
    var zhang = new Employee( "ZhangSan", "1234" );
    console.log( zhang.getName( ) );   // "Employee name: ZhangSan"
    console.log( zhang.getEmployeeIDName() ); // "Employee name: ZhangSan, Employee ID: 1234"



  • 相关阅读:
    ES的基本操作
    Tomcat常规配置
    20220606 JDK 915 新版本特性
    style="wordbreak: breakall;" 用于 对应 td 文本内容过长自适应换行适用
    Springboot项目远程dubug调试
    矩阵可逆的充要条件
    机器学习基础知识
    Linux第一章
    QT linux QT更改默认构建目录debug与release生成的目录放在项目的文件夹内部
    通讯方式通信协议通讯通信区别by txwtech
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4091538.html
Copyright © 2020-2023  润新知