美文网首页
面向对象之继承

面向对象之继承

作者: 年过古稀的Coder | 来源:发表于2018-02-23 14:57 被阅读0次

    内置对象

    • js提供的已经定义好的对象
    • Array,Date,Boolean,RegExp,String,Number(常用)
    • 同时js定义好了对应的一些构造函数
    • 字符串,数字等基础类型数据是没有属性和方法的
    • ??那么我们平时创建了一个字符串(非字符串对象)的时候,为什么可以调用他的length,indexOf的美好属性或方法??
    • 上面问题的答案就是:包装对象

    包装对象

    • 当我们去调用字符串,数字,布尔值这三种基础数据类型的属性和方法的时候,他们本身是不具备属性和方法的,但是js内部,会自动的去调用他们对象的构造函数,然后把他们的值作为参数进行传入,然后执行对应属性或方法,并把结果进行返回
    • 包装对象一个有三个:
      string,Number,Boolean

    方法

    toString()

    • Object对象prototype下的一个方法
    • 所有对象都继承该方法
    • toString()自定义改写
    Array.prototype.toString = function() {
            var result = 0;
            for (var i=0; i<this.length; i++) {
                result += this[i];
            }
            return result;
        }
    
        alert([1,2,3]);
    
        function Person() {
    
        }
    
    //    Person.prototype = new Object();
    
        var p1 = new Person();
        console.log(p1);
    

    hasOwnProperty()

    • 判断某个属性(方法)是否是某个对象自有的,就是非原型链上的
     function Person() {
            this.name = 'motao';
        }
        Person.prototype.x = 100;
    
        var p1 = new Person();
    
        console.log( p1.hasOwnProperty('name') );
        console.log( p1.hasOwnProperty('x') );
    

    constructor

    • 属性:返回某个对象的构造函数
    • 可以重写~
        var a = [1,2,3];
    //    a.constructor = 1;
        console.log(a.constructor == Array);
    

    instanceof

    • 运算符
    • 判断一个对象是否是某个构造函数的实例化对象
    var arr = [1,2,3];
        
        console.log(arr instanceof Array);
    

    继承

    function DragLimit(element) {
            // 调用Drag函数,并把Drag中this指向DragLimit的this
            Drag.call(this, element);
    }
    
    • 如果我们是通过赋值的形式进行继承的话,那么会有问题,因为现在是对象赋值,那么DragLimit.prototype的修改会影响Drag.prototype
    • 我们可以把Drag.prototype中的属性和方法一个个的赋值给DragLimit.prototype
    • 为了方便,我们可以使用forin来批量动态的处理这些属性和方法
    • forin不只是会把Drag.prototype自身的属性循环出来,还会把一些原型链上的属性和方法也循环出来
    • 我们也可以 DragLimit.prototype = new Drag();
    • ES6的话可以更方便的解决这个问题
    class DragLimit extends Drag {
        //extends 可以继承 Drag的所有,包括原型链上的
        //然后在这里可以直接修改DragLimit原型上的属性(方法),并且不会随之改掉它所继承的Drag的原型上的属性(方法);
        this.move {
            
        }
    }
    

    类式继承

    直接克隆,但是如果对象下面的属性包含对象的话,传递的是地址

    当改变克隆到的新对象的值得时候,也会改变原有对象的值

    <script>
        /*
        * 类式继承
        * */
    
        function Person() {
            this.name = 'motao'
        }
        Person.prototype.eat = function() {
            console.log('eat');
        };
    
        function Teacher() {
            Person.call(this);
        }
    
        // 引用了
    //    Teacher.prototype = Person.prototype;
    
        /**
         * 让Teacher的prototype指向Person的一个实例对象,这样的话Teacher的prototype和Person的prototype就没有直接的引用关系,但是因为Teacher的prototype是Person的一个实例,那么Teacher的prototype自动会查找Person的prototype
         *
         * 通过Teacher的prototype可以找到Person的prototype下,但是Teacher的prototype和Person的prototype又没有直接的关系
         */
        Teacher.prototype = new Person();
    
        var mt = new Teacher();
        console.log(mt);
        mt.eat();
    
    //    mt.eat => mt.__proto__.eat => Teacher.prototype.eat => new Person().eat => new Person().__proto__.eat => Person.prototype.eat
    </script>
    
    graph LR
    Teacher.prototype.eat-->new&nbspPerson&lt&gt.eat
    new&nbspPerson&lt&gt.eat-->new&nbspPerson&lt&gt.__proto__.eat
    new&nbspPerson&lt&gt.__proto__.eat-->Person.prototype.eat
    

    原型继承

    <script>
        /*
        * 和类式继承有点像
        * */
    
        var obj = {
            x: 100
        };
    
        function Foo() {}
        Foo.prototype = obj;
    
        var obj2 = new Foo();
    
        console.log(obj2.x);
    </script>
    

    深度继承

    通过一个个的把原型的属性(方法)的值传给新建的一个函数extend里的newObject,并且返回,从而在深度继承的时候 var 新对象 = new extend(要继承的对象)

    改变新的值得时候 不会改变原有的值

    <script>
        var obj1 = {
            x: 10,
            y: 20,
            attr: {a: 1},
            arr: [1,2,3],
            z: null
        };
    
    //    var obj2 = {};
    //    for (var property in obj1) {
    //        obj2[property] = obj1[property];
    //    }
    //    console.log(obj2);
    //    obj2.x = 100;
    //    console.log(obj2);
    //    console.log(obj1);
    
        // obj2.arr 和 obj1.arr 是同一个地址
    //    obj2.attr.b = 2;
    //    console.log(obj2.attr);
    //    console.log(obj1.attr);
    
        var obj2 = extend(obj1);
        console.log(obj2);
        obj2.attr.b = 2;
        console.log(obj2.attr);
        console.log(obj1.attr);
    
        function extend(originObject) {
            // 根据originObject的原始类型来对新对象进行对应的初始化,保证进来什么格式出去就是什么格式
            var newObject = Array.isArray(originObject) ? [] : {};
            for (var property in originObject) {
                // 如果当前数据是对象的话,那么就需要进行深度克隆
                // 注意:typeof来判断数据类型是有一个小的问题的,null的typeof结果也是object,所以需要排除null值的深度克隆
                if (typeof originObject[property] == 'object' && originObject[property] !== null) {
                    // 核心:递归克隆
                    newObject[property] = extend(originObject[property]);
                } else {
                    newObject[property] = originObject[property];
                }
    
            }
            return newObject;
        }
    </script>
    

    注意

    • 如果我们尝试给字符串、数字、布尔值增加自定义的属性和方法的时候,是无效的
    • 当一个字符串被申明以后,其值就不会发生改变,除非重新覆盖,所以我们把字符串称为字符串常量

    原型链

    (查找c的话)
    (person是me的构造函数)

    me.c --> me.__proto__.c
    me.__proto__.c --> me.__proto__.__proto.c
    

    ||

    me.c --> person.prototype.c
    person.prototype.c --> person.prototype.__proto__.c
    

    ||

    me.c --> person.prototype.c
    person.prototype.c --> object.prototype.c
    

    相关文章

      网友评论

          本文标题:面向对象之继承

          本文链接:https://www.haomeiwen.com/subject/aprxxftx.html