学习笔记9--继承

原型链继承、

ECMAScript主要依靠原型链实现继承
利用原型让一个引用类型继承另一个引用类型的实例和方法。让子类原型对象等于超类对象的实例。

function SuperType() {
        this.property = "super";
    }

    SuperType.prototype.getSuperValue = function() {
        return this.property;
    }

    function SubType() {
        this.subProperty = "sub";
    }

    //让SubType原型对象等于SuperType的实例,
    //此时SubType的原型对象的constructor指向SuperType,因为SubType的原型指向了SuperType的原型;
    SubType.prototype = new SuperType();

    SubType.prototype.getSubValue = function() {
        return this.property;
    }

    var subInstance = new SubType();
    console.log(subInstance.getSuperValue());//super

默认原型

所有的引用类型默认通过原型链继承Object,所有函数的默认原型都是Object实例。

确定原型和实例的关系

instanceof操作符,检测实例所在的原型链是否出现过某个构造函数。用来检测constructor.prototype 是否存在于参数 object 的原型链上。

语法
object instanceof constructor 参数 object 要检测的对象. constructor 某个构造函数 
    console.log(subInstance instanceof SubType);//true
    console.log(subInstance instanceof SuperType);//true
    console.log(subInstance instanceof Object);//true

isPropertyOf()方法用于测试一个对象是否存在于另一个对象的原型链上。

    console.log(SubType.prototype.isPrototypeOf(subInstance));//true
    console.log(SuperType.prototype.isPrototypeOf(subInstance));//true
    console.log(Object.prototype.isPrototypeOf(subInstance));//true

给原型添加的方法一定要放在替换原型的语句之后。


原型链的问题

问题1,原型对象中包含引用类型被共享,对引用类型属性的操作会影响所有实例该属性。
问题2,创建子类型的实例时,不能向超类型的构造函数传递参数。

    function SuperType() {
        this.colors = ["yellow", "blue", "red"];
    }

    function SubType() { }

    //此时SubType.prtotype变成了SuperType的一个实例,因此拥有一个colors属性,定义在原型对象中的这个colors属性被所有SubType实例共享
    SubType.prototype = new SuperType();

    var sub1 = new SubType();

    sub1.colors.push("newColor");

    var sub2 = new SubType();

    console.log(sub1.colors);// ["yellow", "blue", "red", "newColor"]

   //被影响
    console.log(sub2.colors);// ["yellow", "blue", "red", "newColor"]

借用构造函数

可以解决原型链问题
在子类型构造函数中调用超类构造函数,其实函数只不过是在特定环境中执行代码的对象,通过apply()或call()方法执行构造函数。

    function SuperType(name) {
        this.colors = ["yellow", "blue", "red"];
    }

    //超类原型上定义属性
    SuperType.prototype.sayName = "hh";

    function SubType() {
        //执行超类构造函数,每个SubType的实例会拥有各自的colors属性的副本
        SuperType.call(this);
    }

    var sub1 = new SubType();
    sub1.colors.push("newColor");

    var sub2 = new SubType();

    console.log(sub1.colors);// ["yellow", "blue", "red", "newColor"]
    console.log(sub2.colors);// ["yellow", "blue", "red"]

    //超类原型定义的属性子类不可见
    console.log(sub1.sayName);//undefined

借用构造函数的问题:方法都在构造函数中定义,因此函数复用就无从谈起了。在超类原型上定义的属性子类不可见

组合继承

使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,即通过在原型上定义方法实现了函数的复用,又保证每个实例都有自己的属性。

    function SuperType(name) {
        this.name = name;
        this.colors = ["yellow", "blue", "red"];
    }

    SuperType.prototype.sayName = function () {
        console.log(this.name);
    };


    function SubType(name, age) {
        //通过构造函数继承
        SuperType.call(this, name);
        this.age = age;
    }

    //通过原型链继承
    SubType.prototype = new SuperType();
    SubType.prototype.constructor = SubType;
    SubType.prototype.sayAge = function () {
        console.log(this.age);
    }

    var sub1 = new SubType("xixi", 29);
    sub1.colors.push("newColor");
    console.log(sub1.colors);// ["yellow", "blue", "red", "newColor"]
    sub1.sayName();//xixi
    sub1.sayAge();//29


    var sub2 = new SubType("haha", 18);
    console.log(sub2.colors);// ["yellow", "blue", "red"]
    sub2.sayName();//haha
    sub2.sayAge();//18

组合继承会调用两次超类构造函数。一次在创建子类原型时,另一次是在子类型构造函数内部。

原型式继承

基于已有的对象创建新对象

    //道格拉斯.克罗福德给出如下函数
    function object(o) {
        //创建一个临时构造函数
        function F() {}

        //将传入的对象作为这个构造函数的原型
        F.prototype = o;

        return new F();
    }

eg.


    var person = {
        name: "Jack",
        friends: ["f1", "f2"]
    };

    var anotherPerson = object(person);
    anotherPerson.name = "Tom";
    anotherPerson.friends.push("f3");

    var yetAnotherPerson = object(person);
    yetAnotherPerson.name = "Jerry";
    yetAnotherPerson.friends.push("f4");

    console.log(person.friends);//["f1", "f2", "f3", "f4"]

Object.create(proto, [propertiesObject])

proto
    新创建对象的原型对象。
propertiesObject
    可选。如果没有指定为 undefined。
    这些属性对应Object.defineProperties()的第二个参数: 每个属性都是通过自己的描述符定义的。
    这个方式指定的属性会覆盖原型对象上的同名属性。

在传入一个参数的情况下,与object的行为相同。

    var person = {
        name: "Jack",
        friends: ["f1", "f2"]
    };

    var anotherPerson = Object.create(person);
    anotherPerson.name = "Tom";
    anotherPerson.friends.push("f3");

    var yetAnotherPerson = Object.create(person);
    yetAnotherPerson.name = "Jerry";
    yetAnotherPerson.friends.push("f4");

    console.log(person.friends);//["f1", "f2", "f3", "f4"]

传入两个参数

    var person = {
        name: "Jack",
        friends: ["f1", "f2"]
    };

    var anotherPerson = Object.create(person, {
        name: {
            value: "Tom"
        }
    });

    console.log(anotherPerson.name);//Tom

寄生式继承

创建一个仅用于封装继承过程的函数。内部创建一个对象,并增强该对象,最后返回该对象。

    //接收一个对象
    function createAnother(original) {
        var clone = object(original);//创建一个新对象,任何能够返回新对象的函数都适用于此模式
        clone.sayHi = function() { //增强
            console.log("hi");
        }
        return clone;
    }

eg.

    var person = {
        name: "Jack",
        friends: ["f1", "f2"]
    };

    var anotherPerson = createAnother(person);
    anotherPerson.sayHi();//hi

寄生组合式继承

组合继承调用两次超类构造函数。

function SuperType(name) {
        this.name = name;
        this.colors = ["yellow", "blue", "red"];
    }

    SuperType.prototype.sayName = function () {
        console.log(this.name);
    };


    function SubType(name, age) {
        //通过构造函数继承
        SuperType.call(this, name);
        this.age = age;
    }

    //通过原型链继承
    SubType.prototype = new SuperType();//第一次调用超类构造函数,SubType.prototype内含有name和colors属性。
    SubType.prototype.constructor = SubType;

    var sub = new SubType("Jack", 29);//第二次调用超类构造函数,sub实例对象又会创建name和colors属性。

通过寄生组合式继承,可以只调用一次超类构造函数。思路:不必为了指定子类型的原型调用超类构造函数。

    function inheritPrototype(subType, superType) {
        //创建超类对象原型的副本
        var prototype = object(superType.prototype);
        prototype.constructor = SubType;
        subType.prototype = prototype;
    }

    function SuperType(name) {
        this.name = name;
        this.color = ["yellow", "blue", "red"];
    }

    superType.prototype.sayName = function() {
        console.log(this.name);
    }

    function SubType(name, age) {
        SuperType.call(this, name);//只调用一次超类构造函数
        this.age = age;
    }

    inheritPrototype(SubType, SuperType);

    SubType.prototype.sayAge = function() {
        console.log(this.age);
    }
全部评论

相关推荐

昨天 22:20
已编辑
门头沟学院 golang
27届,bg为四非本211硕,如题,导师不放实习,且每周至少一次线下组会(工作日),从研一上开始实习,然后我组在研一下引入了打卡机五段大厂分别是:美团到店、美团服务零售、快手电商、字节TikTok、字节CapCut。目前要结束我的第五段实习了(不会再刷第六段,好好搞学校的事,还有秋招)本来一直告诉自己的是“所有委屈到了终点再说”,过去告诉自己的终点自然还没到,但我觉得自己仿佛已经到了另一个终点,有感而发,写了这篇文章也许你会觉得为啥不尝试问问导师能不能实习,或者用其他让自己舒服的手段,我只能说,这很复杂,有导师的人自然会懂,这种一开始就把“利益冲突”摆明面上的招几乎就是不可能成功———————————————————我到底是怎么实习的?骗hr自己满勤,然后没有捷径,就是每周往返,第一段去的是北京美团,而学校在江苏,因此需要一周一次北京江苏往返,因为实习钱少,所以坐的基本是绿皮,难以入睡,下车后就是长达2小时的地铁去公司,地铁站上靠着人睡觉周末做什么?基本在做导师的科研or横向,学习的话很多时候就是尽力在晚上回到出租屋的时候学,这很难维持,但只能不断push自己如何破解打卡机?直接把打卡机偷了,或者使用指纹膜(当然我很早就做好了无法破解的准备,那就是找个长三角实习,每天早起去打卡完坐高铁去实习,从每周高铁往返变成每天)导师会压力吗?非常压力,实习的时候非常害怕微信弹出他的消息,PTSD了,有时候一周要往返两次学校,每次都跟要死了一样,之前真是情绪崩溃好几次,哈哈哈哈平时往返怎么平衡工作?我本来很晕车,为了不耽误公司和导师的进度,从车上一看电脑就头晕、吐,到后面可以随意在高铁、地铁、出租车上Coding,甚至不会再因为往返感到心累了,哈哈哈哈这一路已经淬炼出比较坚强的内心了,已经数不清多少次坐末班高铁从学校回公司,多少次凌晨6点爬起来赶车过去我会把这些当作是我人生的弯路,但现在,这些已经成为我宝贵的经验了。往后,我想我也能真正允许各种不好的情况出现了,因为我会真正把它当作我要解决的问题,而非抱怨,这又何尝不是终点呢?要照顾好身体,我不管怎么往返,一直非常在乎身体,会让自己睡够8小时,最近几星期培养早睡早起到公司健身后去工作的习惯,我觉得好身体很关键
布布永不言弃:简历里写的快手,实际实习的是很短的,也不会真的在秋招的时候写到简历上,但从给我的感悟上看,这个实习确实很有用。稍微标题党了,见谅各位
美团工作强度 2446人发布
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务