zoukankan      html  css  js  c++  java
  • js原型链继承

    js原型链继承有很多种实现的方式,主要介绍以下3种:

    一、拷贝继承:

    顾名思义拷贝就是利用for in 或者jq的extend,把一个构造函数的prototype循环遍历赋值给另一个构造函数的prototype,再把构造函数内的属性也一起继承过去

    var Base = function(name){
            this.name = name;
        };
        Base.prototype.getName = function(){
            alert(this.name);
        };
    
        var Aaa = function(name,sex){
            //继承属性
            Base.call(this,name);
            this.sex = sex;
        };
        //继承方法
        extend(Aaa.prototype,Base.prototype);
    
        //调用:
        var a = new Aaa('小明','男');
        a.getName();

    二、类式继承:

    1. 构造函数A.prototype = new 构造函数B();
    2. 继承属性
    3. 修改构造函数指向
    var Base = function(){
            this.cacheName = [];
        };
        Base.prototype.addName = function(name){
            this.cacheName.push(name);
        };
        Base.prototype.getNames = function(){
            alert(this.cacheName);
        };
    
        var Aaa = function(){
            //继承属性
            Base.call(this);
        };
        //继承方法
        Aaa.prototype = new Base();
        //修改构造函数指向
        Aaa.prototype.constructor = Aaa;
    
        //调用:
        var a = new Aaa();
        a.addName('小明');
        a.getNames();

    三、原型继承:

    利用es5新特性Object.create实现原型继承

    Object.create = Object.create || function(o){
            var F = function(){};
            F.prototype = o;
            return new F();
        };

    Object.create的作用是只继承方法不继承属性

    与类式继承一样需要继承属性、修改构造函数指向

    var Base = function(name){
            this.name = name;
        };
        Base.prototype.getName = function(){
            alert(this.name);
        };
    
        var Aaa = function(){
            //继承属性
            Base.apply(this,arguments);
        };
        //继承方法
        Aaa.prototype = Object.create(Base.prototype);
        //修改构造函数指向
        Aaa.prototype.constructor = Aaa;
    
        var a = new Aaa('小明');
        a.getName();
    
        
        Object.create = Object.create || function(o){
            var F = function(){};
            F.prototype = o;
            return new F();
        };

    通用的原型链继承:

    Object.create = Object.create || function(o){
            var F = function(){};
            F.prototype = o;
            return new F();
        };
    
        function Class(){};
        Class.extend = function(opts){
    
            //父类的原型链
            var _super = this.prototype;
            var prototype = Object.create(_super);
    
            for(var prop in opts){
                var val = opts[prop];
                prototype[prop] = val;
            }
    
            var Fn = function(){
                this.init && this.init.apply(this,arguments);
            };
    
            //继承方法
            Fn.prototype = prototype;
            //修改构造函数指向
            Fn.prototype.constructor = Fn;
            //把父类的所有方法保存到超类
            Fn.prototype._super = Object.create(_super);
    
            //递归调用Class.extend方法
            Fn.extend = arguments.callee;
            return Fn;
    
        };

    调用:

    var Person = Class.extend({
            init:function(opts){
                opts = opts || {};
                this.name = opts.name;
                this.sex = opts.sex;
                this.age = opts.age;
            },
            getName:function(){
                return this.name;
            },
            getSex:function(){
                return this.sex;
            },
            getAge:function(){
                return this.age;
            }
        });
    
        var Student = Person.extend({
            init:function(opts){
                opts = opts || {};
                this.job = opts.job;
                this._super.init.call(this,opts);
            },
            getJob:function(){
                return this.job;
            },
            getInfo:function(){
                alert('name:' + this.getName() + ',sex:' + this.getSex() + ',age:' + this.getAge() + ',job:' + this.getJob());
            }
        });
    
        var student = new Student({
            name:'小明',
            sex:'男',
            age:18,
            job:'学生'
        });
    
        student.getInfo();

    我们发现子类调用父类的方法有些不方便:this._super.init.call(this,opts);

    var Student = Person.extend({
    
            init:function(opts){
                opts = opts || {};
                this.job = opts.job;
                this._super.init.call(this,opts);
            },
    
            .......................
        });

    而且这种添加超类的方式性能也很差。如果子类没有调用超类,那么创建超类就是一种浪费。

    Fn.prototype._super = Object.create(_super);

    利用闭包改写Class.extend方法:

    Object.create = Object.create || function(o){
            var F = function(){};
            F.prototype = o;
            return new F();
        };
    
        var fnTest = /xyz/.test(function(){xyz;}) ? /_super/ : /.*/;
    
        function Class(){};
        Class.extend = function(opts){
    
            //父类的原型链
            var _super = this.prototype;
    
            var prototype = Object.create(_super);
    
            for (var prop in opts) {
                
                var val = opts[prop];
    
                prototype[prop] = typeof val == "function" &&
                typeof _super[prop] == "function" && fnTest.test(val) ?
    
                    (function(prop, fn){
                        return function() {
    
                            var tmp = this._super;
    
                            //在调用fn方法前创建一个超类
                            this._super = _super[prop];
    
                            //该方法只需要暂时绑定,所以在执行完毕后将其移除
                            var ret = fn.apply(this, arguments);
                            this._super = tmp;
                            
                            return ret;
                        };
                    })(prop, val) :
                    val;
            }
    
            var Fn = function(){
                this.init && this.init.apply(this,arguments);
            };
    
            //继承父级的所有方法
            Fn.prototype = prototype;
            //修改构造函数指向
            Fn.prototype.constructor = Fn;
    
            //递归调用Class.extend方法
            Fn.extend = arguments.callee;
            return Fn;
    
        };

    调用:

    var Student = Person.extend({
    
            init:function(opts){
                opts = opts || {};
                this.job = opts.job;
                this._super(opts);
            },
            
            ...................
        });

    现在调用也很方便了,无需修正this的指向。

    当调用原型方法前创建超类,调用后即销毁它。而且超类只保存了对应父类的一个方法,并不是保存父类所有的方法。

    (function(prop, fn){
    
                        return function() {
    
                            var tmp = this._super;
    
                            //在调用fn方法前创建一个超类
                            this._super = _super[prop];
    
                            //该方法只需要暂时绑定,所以在执行完毕后将其移除
                            var ret = fn.apply(this, arguments);
                            this._super = tmp;
                            
                            return ret;
                        };
    
                    })(prop, val)
  • 相关阅读:
    [BZOJ4199][NOI2015]品酒大会
    [BZOJ4198][Noi2015]荷马史诗
    [BZOJ4197][Noi2015]寿司晚宴
    [BZOJ4196][NOI2015]软件包管理器
    2016-11-15NOIP模拟赛
    2016.6.30模拟赛
    BZOJ3672: [Noi2014]购票
    UOJ#191. 【集训队互测2016】Unknown
    第四届CCF软件能力认证(CSP2015) 第五题(最小花费)题解
    bzoj3926: [Zjoi2015]诸神眷顾的幻想乡 对[广义后缀自动机]的一些理解
  • 原文地址:https://www.cnblogs.com/gongshunkai/p/6650215.html
Copyright © 2011-2022 走看看