理解JS原型以及实现继承

一.理解原型

  当创建了一个函数的时候,就会为该函数创建一个原型对象,并通过prototype属性指向这个原型对象。而且当使用该构造函数创建一个新实例后,该实例内部将包含一个内部属性proto,也指向这个原型对象。

    function Person(name) {
        this.name = name;
        this.likething = ['eat', 'play'];
        this.getName = function () {
            return this.name;
        }
    }

    Person.prototype.getAge = function () {
        return "this prototype method getAge";
    }

    var person1 = new Person("helong");
    var person2 = new Person("jerry");
    console.log(Person.prototype);
    console.log(person1);

下图是JS对象的引用关系图,注意箭头指向的是对象,而不是某个属性。

这里写图片描述

下图为在谷歌浏览器中打印出来的结果:
这里写图片描述

二.实现继承

2.1 使用原型链

  原型链是js实现继承的主要方法,其基本原理就是让一个对象的原型对象等于另一个类型的实例,这样子类型通过搜索原型链便可以调用父类型的属性和方法。

  使用原型链继承存在两个缺点:
  1.原型属性会被所有实例共享,某实例对原型的修改会反应到另一个实例上面。如下代码所示,reader1和reader2实例共享likething和name属性。

  2.在创建子类型的实例时,不能向超类型的构造函数中传递参数。实际上是没办法在不影响其他实例对象的情况下向超类对象传递参数,因为原型是多个实例共享的。
  

    function Person(){
        this.name = 'a default name';
        this.likething = ['eat' , 'play'];
        this.getName = function(){
            return this.name;
        }
    };

    function Reader(){
    }

    Reader.prototype = new Person();
    Reader.prototype.constructor = Reader;

    var reader1 = new Reader();
    var reader2 = new Reader();


    alert(reader1.likething);//eat,play
    reader1.likething.push('code');
    alert(reader2.likething);//eat,play,code

    console.log(Reader.prototype);
    console.log(reader1);

关系图如下:
这里写图片描述

打印结果如下:
这里写图片描述

2.2 借用构造函数(使用call或apply),也叫类式继承

  采用此种方式,两个实例之间分别拥有各自的属性。解决了第一种方式的实例共享问题,而且也可以向构造函数中传递参数。
  缺点在于:
  这个时候在超类的原型中定义的方法就不能被子类所访问到了,如getAge()方法。

    function Person(name){
        this.name = name;
        this.likething = ['eat' , 'play'];
        this.getName = function(){
            return this.name;
        }
    };

    Person.prototype.getAge = function(){
        alert("你妹啊!");
    }

    function Reader(name){
        Person.call(this,name);
    }

    var reader1 = new Reader("何");
    var reader2 = new Reader("龙");

    reader1.getAge();//报错

    console.log(Person.prototype);
    console.log(Reader.prototype);
    console.log(reader1);

这里写图片描述

这里写图片描述

2.3 组合继承

  综合上述两种方式的优缺点,组合继承方式使用原型链方式实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承。
  这样,既通过在原型上定义方法实现方法的复用,又能够保证每个实例都有它自己的属性,而且超类的原型中定义的方法也能被子类所访问到了,
  也就是复用的定义在原型上,私有的定义在构造函数中。
  

    function Person(name , age){
        this.name = name;
        this.age = age;
        this.likething = ['eat' , 'play'],
        this.getName = function(){
            return this.name;
        }
    };

    Person.prototype.getAge = function(){
        return this.age;
    };

    function Reader(name , age){
        Person.call(this,name,age);
    }

    Reader.prototype = new Person("default name");
    Reader.prototype.constructor = Reader;

    var reader1 = new Reader("何", 18);
    var reader1 = new Reader("龙" ,19);

    console.log(Person.prototype);
    console.log(Reader.prototype);
    console.log(reader1);

这里写图片描述

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值