【第二章】寄生组合继承&extend多继承

243 阅读3分钟
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!--<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">-->
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>【第二章】寄生组合继承&多继承</title>
</head>
<body>
<script>
    // 组合继承
    /*
    function Super(){
        this.name = 'superName';
        this.age = 'superAge';
    }
    Super.prototype.showName = function(){
        return this.name;
    };
    function Sub(){
        Super.call(this);
        this.age = 'subAge';
    }
    Sub.prototype = new Super();
    Sub.prototype.showAge = function(){ // 这里由于用了类继承,所以Sub.prototype不能写成 Sub.prototype = {}的形式了。
        return this.age;
    };

    var sub01 = new Sub();
    console.log(sub01.name); // superName
    console.log(sub01.age); // subAge
    console.log(sub01.showName()); // superName
    console.log(sub01.showAge()); // subAge
    console.log(sub01 instanceof Sub); // true
    console.log(sub01 instanceof Super); // true
    console.log(Sub.prototype instanceof Super); // true
    */
</script>
<script>
    /*
    // 原型式继承
    function inheritObj(obj){
        var F = function(){};
        F.prototype = obj;
        return new F();
    }

    function Super(){
        this.name = 'superName';
        this.age = 'superAge';
        this.arr = ['super'];
    }
    Super.prototype.getAge = function(){
        return this.age;
    };

//    var super01 = {
//        name: 'super',
//    };
    var super01 = new Super();

    // 寄生式继承
    function inherit(obj){
//        var _instance = new inheritObj(obj); // 这里返回的就是inheritObj执行后,返回的带有父级原型的一个函数,有没有new应该没区别。
        var _instance = inheritObj(obj); // 这返回来的是一个原型是super的一个实例,但是return的F原型是Super 而_instance的原型不是
//        console.log(_instance);
//        console.log(_instance.__proto__);

        _instance.name = 'subName';
        _instance.getName = function(){
            return this.name;
        };
//        _instance.prototype = obj;
        return _instance;
    }
    var sub01 = inherit(super01);
    sub01.arr.push('sub1Name');

    console.log(sub01.getName());
    console.log(sub01.getAge());
    console.log(sub01.prototype instanceof Super);
    console.log(sub01 instanceof Super);

    var sub02 = inherit(super01);
    sub02.arr.push('sub2Name');
    console.log(super01.arr); // ["super", "sub1Name", "sub2Name"] 这个并不能解决共用问题。 只是解决了组合模式的重复new Super的问题。
    */
</script>
<script>
    /*
    // 寄生组合继承
    function inheritObject(obj){
        var F = function(){};
        F.prototype = obj;
        return new F();
    }
    function inheritPrototype(subClass,superClass){
        var p = inheritObject(superClass.prototype);
        p.constructor = subClass;
        subClass.prototype = p;
    }

    function Super(){
        this.name = 'superName';
        this.age = 'superAge';
        this.arr = ['super'];
    }
    Super.prototype.showName = function(){
        return this.name;
    };
    Super.prototype.showAge = function(){
        return this.age;
    };
    function Sub(){
        Super.call(this);
        this.age = 'subAge';
        this.job = 'subJob';
    }

//    inheritPrototype(Sub, Super); // 这个方法必须执行到Sub.prototype绑定的前边

    Sub.prototype.showJob = function(){
        return this.job;
    };
    console.log(Sub.prototype);
    inheritPrototype(Sub, Super); // 放在前边的原因: subClass.prototype = p; 覆盖掉了之前的 Sub.prototype
    console.log(Sub.prototype);

    var s1 = new Sub();
    console.log(s1 instanceof Sub);
    console.log(s1 instanceof Super);
    console.log(s1.prototype instanceof Super);
    console.log(s1.constructor);

    console.log(s1.showName());
    console.log(s1.showAge());
//    console.log(s1.showJob());

    var s2 = new Sub();
    s2.arr.push('sub02');
    s1.arr.push('sub01');
    console.log(s1.arr);
    console.log(s2.arr);
    */
</script>
<script>
    // 判断是否是数组
    function isArray(obj) {
        return (Object.prototype.toString.call(obj).indexOf('Array') != -1) ? true : false;
    }

    // 判断是否是对象
    function isObject(param){
        return (param instanceof Object);
    }

    // 复制类数组
    function copyArr(arr){
        var tempArr = [];
        for(var index in arr){
            tempArr[index] = arr[index];
        }
        return tempArr;
    }


    // extend 单复制浅复制
    Object.prototype.extend = function(sourceObj){
        for(var key in sourceObj){
            this[key] = sourceObj[key];
        }
    }


    // extend 深复制(利用JSON.stringify和JSON.parse)
    Object.prototype.extend = function(source, isCover){
        // if(proxy.hasOwnProperty(key) && !this.hasOwnProperty(key)){ // 已经有同名属性则不复制
        var coverConditionStr,
            coverConditionArr = ['proxy.hasOwnProperty(key)', 'proxy.hasOwnProperty(key) && !this.hasOwnProperty(key)'],
            effectIsCover = (typeof isCover == 'boolean') ? isCover : true ;

        coverConditionStr = effectIsCover ? coverConditionArr[0] : coverConditionArr[1]; // 0: 覆盖, 1:不覆盖

        var proxy = JSON.stringify(source);
        proxy = JSON.parse(proxy);
        for(var key in proxy){
            // 这里的hasOwnProperty其实有一点问题,不能遍历出原型上的属性。但作为属性复制来讲,反而是个好处。
            if(eval(coverConditionStr)){ // eval 有安全问题
                this[key] = proxy[key];
            }
        }
        proxy = null;
    }

    // 这里有一个问题涉及到依赖注入,如果想在extend里判断是否覆盖已有属性,就需要在extend方法添加一个flag参数,
    // 这样如果extends里也需要判断就需要作依赖注入来判断flag参数值。
    // 这里说的angular中的$score那种不根据参数顺序的依赖注入,具体实现不清楚,先用argument[length-1]的方法实现。

    // extend 多复制
    // extends(paramArray, [isCover]) || extends(param1, param2, ..., [isCover])
    Object.prototype.extends = function(){
        var tempArr = [];
        try{
            if(isObject(arguments[0])){
                if(isArray(arguments[0])){
                    tempArr = copyArr(arguments[0]);
                }else{
                    tempArr = copyArr(arguments);
                }
            }else{
                throw 'params is must instanceof Object';
            }
            for(var i=0; i<tempArr.length; i++){
                // 如果最后一个参数是boolean值,则传入到extend方法中
                if(typeof tempArr[tempArr.length - 1] == 'boolean'){
                    this.extend(tempArr[i], tempArr[tempArr.length - 1]);
                }else{
                    this.extend(tempArr[i]);
                }
            }
        }catch(err){
            console.log(err);
        }
    };

    var a = {
        name: 'a的名字',
        arr: [
            {
                ele1: 'a的arr属性第一个元素',
                ele2: function(){
                    return 'a的arr属性第二个元素';
                }
            },
            'index=a'
        ],
        obj: {
            objName: 'a的obj_name',
            objArr: [1,2,3,4,5]
        }
    };

    var b = {
        name: 'b的名字',
        publicInfo: '公用信息'
    };

    // 验证是否深度复制
    b.extend(a, false); // 验证是否覆盖对象已有属性, 传true或者不传则覆盖, 传false则不覆盖(b的name,还是b的名字)
    b.arr[0].ele1 = 'b'; // 如果修改后不影响a,就是深度复制
    console.log({'b': b}); // ele1 : 'b'
    console.log({'a': a}); // ele1 : 'a的arr属性第一个元素'

    // 验证多继承
//    var c = {};
//    c.extends(a, b);
//    console.log(c);
</script>
</body>
</html>