扫描二维码关注官方公众号
返回列表
+ 发新帖
查看: 120|回复: 0

[转载发布] 简明易懂的原型和原型链教程

[复制链接]
累计送礼:
0 个
累计收礼:
0 个
  • TA的每日心情
    开心
    2025-2-4 02:05
  • 签到天数: 110 天

    连续签到: 2 天

    [LV.6]常住居民II

    2327

    主题

    395

    回帖

    1万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    VIP
    6
    卡币
    10465
    OK点
    16
    推广点
    0
    同能卷
    0
    积分
    13215

    灌水之王

    发表于 2024-2-13 14:29:44 | 显示全部楼层 |阅读模式
    原型是js和c++之类面向对象的语言本质区别所在。
    在js中一切都是对象,js本身并没有类这样的概念,与其说一个对象是类的一个实例,不如说一个对象是另一个对象的克隆。
    具体的,就需要了解prototype属性和__proto__属性了。

    1.Function 对象

    函数对象是很特殊的一类对象, 它比一般的Object对象多出来很多属性。
    对比一下:
    例子1:
    JAVASCRIPT 代码
    1. var fun = new Function();
    2. var obj = new Object();
    复制代码

    用控制台就能发现Function对象拥有比Object对象更多的成员。
    那这些多出来的成员是从哪里来的呢?当然是从Function对象那里找来的。
    在new Function的时候fun肯定从Function那里克隆了一部分内容。
    但是,它是克隆的Function的成员么?乍一看上去Function的成员和fun的成员是一致的,
    但其实真正的源头是Function.prototype,用控制台查看Function.prototype的话就会发现这面也有和Function一样的成员。
    推理一下,如果拷贝的是Function的话,那么fun也应该有何Function一样的prototype,但结果fun的prototype是空的。
    所以说fun在创造的时候是从Function.prototype处拷贝的成员。
    那么如果这个推理是正确的,那么对其他函数对象(比如fun)来说这个克隆规则也一样适用。
    例子2:
    JAVASCRIPT 代码
    1. var people = new Function();
    2. people.age = 80;
    3. people.prototype.age = 24;
    4. var li = new people();
    5. li.age;
    复制代码

    输出: 24;
    结论: a = new b的时候, a会拷贝b的prototype属性中的成员

    2. new的原理
    那么我们可以分析一下new的工作原理
    1. fun拷贝了Function.prototype里的成员
    2. fun修改了这些成员方法中的this指针(这些方法的指针原先是指向Function.prototype的,现在指向了fun)
    3. fun执行了构造器中的内容比如:
    JAVASCRIPT 代码
    1. var people = function(age){this.age = age};
    2. people.age = 80;
    3. people.prototype.age = 24;
    4. var li = new people(44);
    5. li.age;
    复制代码

    那么new出来的成员和原本的成员有关系么
    例子3:
    JAVASCRIPT 代码
    1. var people = new Function();
    2. people.age = 80;
    3. people.prototype.age = 24;
    4. var li = new people();
    5. console.log(li.age);
    6. li.age = 10;
    7. console.log(people.prototype.age);
    8. people.prototype.age = 30;
    9. console.log(li.age);
    复制代码

    输出: 24,24,10
    例子4:
    JAVASCRIPT 代码
    1. var people = new Function();
    2. people.age = 80;
    3. people.prototype.makeCall = function(){console.log('Hello')};
    4. people.prototype.makeCall2 = function(){console.log('Hello 2')};
    5. var li = new people();
    6. li.makeCall = function(){console.log('Hello 3')};
    7. li.makeCall();
    8. people.prototype.makeCall();
    9. people.prototype.makeCall2 = function(){console.log('Hello 4')};
    10. li.makeCall2();
    复制代码

    输出:Hello 3, Hello, Hello 4;
    结论: 通过上面两个例子你会发现,对于在li中重新定义过的成员(比如 makeCall和age)不会受到people.prototype改变的影响
    而未在li中定义过的成员MakeCall2就依然会跟随者people.prototype的改变而改变。
    那这是为什么呢?拷贝的和重新定义的属性有什么不同呢?

    3.原型链
    先介绍一个函数:hasOwnProperty, 这个函数用来判断一个成员是否是这个对象自有的。
    例子5:
    JAVASCRIPT 代码
    1. li.hasOwnProperty('makeCall2');
    2. li.hasOwnProperty('makeCall');
    复制代码

    输出: false, true;
    结论: 显然, makeCall2并没有真正复制到了li上,而只是被li引用了而已。
    那么js又是怎么找到makeCall2的呢?
    这就要谈到__proto__属性了。
    所有的对象都有一个__proto__属性。
    在函数对象的情形下li.__proto__ 可以等价于 people.prototype
    当你访问li的一个成员的时候,js首先会在li的所有自有的成员中寻找。
    比如你在寻找MakeCall2, 但是li并没有这个成员。
    那么js则会转到li.__proto__里去寻找
    假设还没找到则会到li.__proto__.__proto__里寻找,一直到找到或找不到为止。
    这就是js最重要的原型链的原理。


    结论:
    1.a = new b 拷贝的是b.prototype的属性而不是b的属性
    2.a = new b 会导致 a.__proto == b.prototype,__proto__代表了对象的原型, 如果在对象中找不到指定的成员, js会在对象的原型中寻找。
                 本帖来自P1论坛作者沉滞的剑,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:https://rpg.blue/forum.php?mod=viewthread&tid=395774  若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。
    天天去同能,天天有童年!
    回复 送礼论坛版权

    使用道具 举报

    文明发言,和谐互动
    文明发言,和谐互动
    高级模式
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    关闭

    幸运抽奖

    社区每日抽奖来袭,快来试试你是欧皇还是非酋~

    立即查看

    聊天机器人
    Loading...

    QQ|Archiver|手机版|小黑屋|同能RPG制作大师 ( 沪ICP备12027754号-3 )

    GMT+8, 2025-3-10 16:11 , Processed in 0.109462 second(s), 53 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表