codeing or artist ?
记得大学第一节编程课,教授说,"如果一件事儿有对错,那么是科学。如果有美丑好坏,那么是艺术。" 一个能顺利运行还能让人阅读时体验思维美妙的代码,就是艺术和科学的结合。能运行的程序并不是好程序,能当作文章来读的才是。在我看来代码是一种特殊的文体,程序猿其实会写诗。

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;}) ? /\b_super\b/ : /.*/;

    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)

 

posted on 2017-03-31 11:05  codeing-or-artist-??  阅读(198)  评论(0编辑  收藏  举报