美文网首页
引用类型之对象(面向对象03)

引用类型之对象(面向对象03)

作者: 倾国倾城的小饼干 | 来源:发表于2018-04-03 11:20 被阅读0次

    什么是继承

    大多数使用继承不外乎是为了获得两点好处,代码的抽象和代码的复用。
    代码的抽象不用说了,交通工具和汽车这类的例子数不胜数,在传统的语言中(java)代码的抽象更多是使用接口来实现,而试验继承更多的是为了代码的复用。
    怎么复用的?打个比方,classa继承了classb,classa便拥有了classb的公有和私有的变量和方法,便是classb将这些属性和方法直接copy给classa。这样便实现了继承。因此我们可以这样说,继承实际上是一种类与类之间的copy行为。从另一个方面来说,js的数据类型分文基本数据类型和引用数据类型,我们在对数据进行复制的时候,如果这个数据是基本数据类型那很好办,直接赋值就好,如果在使用js对对象或数组进行操作的时候,经常要将数组进行备份,事实证明如果只是简单的将它赋值其他变量,那么我们只要更改其中的任何一个,其他的也会跟着改变,这就导致了问题的发生。

    js中的继承

    在js中没有类的概念,只有对象。虽然,现在人们经常使用class关键字,这让js看起来似乎是拥有了“类”,可表面看到的不一定是本质,class只是一块糖,嚼碎了才知道里面其实还是原型链那一套。因此,js中的继承只是对象与对象之间的继承。反观继承的本质,继承便是让子类拥有父类的一些属性和方法,那么在js中便是让一个对象拥有另一个对象的属性和方法。
    所以,这给我们一条十分清晰的思路。js中如何实现继承?只需让一个对象拥有另一个对象的属性和方法,这就实现了。

    浅拷贝

    既然让一个对象拥有另一个对象的属性和方法,首先想到的便是粗暴的方式,直接将对象的属性和方法强制copy到另一个对象。

    var person={
        name:'cj';
        age:22;
    }
    var programer={
        language:'js'
    }
    function extend(p,c){
        var c={};
        for(var prop in p){
            c[prop]=p[prop]
        }
    }
    

    局限性:如果person加上一个adress对象即address{home:'home address'}programer.address.home='home'即改变时,person.address.home也跟着改变,因为两个对象指向的是同一个地址,拷贝的只是引用,也就是浅拷贝。

    深拷贝
    var person={
        name:'cj';
        age:22;
        adderss{name:'home address'}
    }
    var programer={
        language:'js'
    }
    function extend(p,c){
        var c={};
        for(var prop in p){
            if(typeof p[prop] ==='object'){
                c[prop]=p[prop].constructor===Array?[]:{};
                extend(p[prop],c[prop])
            }else{c[prop]=p[prop]}
        }
    }
    

    深拷贝用递归的方式来复制子对象里面的所有属性和方法,直到子子属性为基本数据类型。

    原型链继承

    如何使用原型链来实现继承呢?这要归功于js中的委托机制。
    当我们获取一个对象的某个属性时。比如a.b,会默认调用一个内置的方法,这个内置的方法就是:
    在当前对象中查找,找不到则委托给当前对象的proto。再找不到则委托给protoproto直到object.prototype中也没有找到,则返回undefind。
    因此,我们想让对象a拥有对象b的属性和方法,即对象a继承对象b,只需要把b赋值给a的proto。利用属性的查找的委托机制,实现了a也拥有了b的属性和方法。
    前面提到,proto是个内置隐藏属性,设计的本意是不可被读取和修改的,那么我们如何利用原型链来建立继承关系?js提供了new关键字。new关键字实现了a.proto=A.prototype这样只需把a的构造函数的prototype连接到b 就行了。

    function A(){
        
    }
    var b={
        show:function(){
            console.log('这是来自b的方法')
        }
    }
    A.prototype=b
    A.prototype.constructor=A
    var a=new A()
    a.show//这是来自b的方法
    

    核心:原型链继承子类只是继承了父类的原型链上的属性,并且在创建子类的时候不能向父类的构造函数传递参数。

    call继承
    function Parent(){
        this.x=100;
        this.y=199
    }
    Parent.prototype,fn=function(){}
    function Child(){
        this.a=100;
        Parent.call(this)
    }
    var p=new Parent();
    var c=new Child();
    console.log(p)//Parent{x:100,y:199}
    console.log(c)//Child{d:100,x:100,y:199}
    

    这很好理解,在子类的构造函数中,改变父类的this指向,改变为子类的实例,同时运行父类方法,这样父类中的this.x就变成了子类的实例.x。这样只能继承父类的私有属性和方法。

    call继承和原型继承集合在一起。

    ===》无论是私有还是公有的属性都拿到了。

    function Parent(){
        this.x=100;
    }
    Parent.prototype.getx=function(){}
    function Child(){
        Parent.call(this)
    }
    Child.prototype=new Parent();
    Child.prototype.constructor=Child;
    var p=new Parent();
    var c=new Child();
    console.log(c)
    
    create继承
    var b={c:1}  
    var a=Object.create(b)
    console.log(a.c)//1
    

    那么create继承是怎样实现地呢?

    var p={name:'cj'}
    function create(p){
        var ins;
        function F(){
            F.prototype=p;
            ins=new F();
            return ins;
        }
    }
    var c=create(p)
    c.name==>'cj'
    

    上例中ins.__proto__=F.prototype又因为F.prototype=p所以c.name==>'cj'

    继承

    1. 继承的作用

    继承可以使一个对象直接使用另一个对象的方法和属性。

    1. 代码的区别

    //方法1
    function People(name, sex){
        this.name = name;
        this.sex = sex;
        this.printName = function(){
            console.log(this.name);
        }
    }
    var p1 = new People('饥人谷', 2)
    
    //方法2
    function Person(name, sex){
        this.name = name;
        this.sex = sex;
    }
    
    Person.prototype.printName = function(){
        console.log(this.name);
    }
    var p1 = new Person('若愚', 27);
    

    区别: 第二种方法将公有的属性放在Person的prototype上,当再创建一个对象实例的时候就不用像第一种方法那样把printName再创建一遍,而是从原型中调用就可以了。

    1. Object.create的作用

    Object.create() 方法会使用指定的原型对象及其属性去创建一个新的对象。
    兼容性:

    1. hasOwnProperty

    作用:hasOwnPerperty是Object.prototype的一个方法,可以判断一个对象是否包含自定义属性而不是原型链上的属性,hasOwnProperty是JavaScript中唯一一个处理属性但是不查找原型链的函数。
    语法:obj.hasOwnProperty(prop)(prop为要检测的属性名称)

    1. call的作用

    function Person(name, sex){
        this.name = name;
        this.sex = sex;
    }
    function Male(name, sex, age){
        Person.call(this, name, sex);    //在子类的构造函数中,改变父类的this指向,改变为子类的实例,同时运行父类方法,这样父类中的this.x就变成了子类的实例.x。这样只能继承父类的私有属性和方法。
        this.age = age;
    }
    
    1. 补全代码

    function Person(name, sex){
        this.name=name;
        this.sex=sex;
    }
    
    Person.prototype.getName = function(){
        console.log(this.name)
    };    
    
    function Male(name, sex, age){
       Person.call(this,name,sex)
       this.age=age
    }
    Male.prototype=Object.create(Person.prototype)
    Male.constructor=Male;
    Male.prototype.getAge = function(){
       console.log(this.age)
    };
    var ruoyu = new Male('若愚', '男', 27);
    ruoyu.printName();
    

    相关文章

      网友评论

          本文标题:引用类型之对象(面向对象03)

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