简单粗暴地理解js原型链--js面向对象编程
2026/7/3 7:40:45
网站开发
人是人他妈生的妖是妖他妈生的。人和妖都是对象实例而人他妈和妖他妈就是原型。原型也是对象叫原型对象。2人他妈和人他爸啪啪啪能生出一堆人宝宝、妖他妈和妖他爸啪啪啪能生出一堆妖宝宝啪啪啪就是构造函数俗称造人。3人他妈会记录啪啪啪的信息所以可以通过人他妈找到啪啪啪的信息也就是说能通过原型对象找到构造函数。4人他妈可以生很多宝宝但这些宝宝只有一个妈妈这就是原型的唯一性。5人他妈也是由人他妈他妈生的通过人他妈找到人他妈他妈再通过人他妈他妈找到人他妈他妈……这个关系叫做原型链。6原型链并不是无限的当你通过人他妈一直往上找最后发现你会发现人他妈他妈他妈……的他妈都不是人也就是原型链最终指向null。7人他妈生的人会有人的样子妖他妈生的妖会有妖的丑陋这叫继承。8你继承了你妈的肤色你妈继承了你妈他妈的肤色你妈他妈……这就是原型链的继承。9你谈对象了她妈让你带上房产证去提货你若没有那她妈会问你妈有没有你妈没有那她妈会问你妈她妈有没有……这就是原型链的向上搜索。10你会继承你妈的样子但是你也可以去染发洗剪吹就是说对象的属性可以自定义会覆盖继承得到的属性。11虽然你洗剪吹了染成黄毛了但你不能改变你妈的样子你妈生的弟弟妹妹跟你的黄毛洗剪吹没一点关系就是说对象实例不能改动原型的属性。12但是你家被你玩火烧了的话那就是说你家你妈家你弟们家都被烧了这就是原型属性的共享。13你妈外号阿珍邻居大娘都叫你阿珍儿但你妈头发从飘柔做成了金毛狮王后隔壁大婶都改口叫你包租仔这叫原型的动态性。14你妈爱美又跑到韩国整形整到你妈他妈都认不出来即使你妈头发换回飘柔了但隔壁邻居还是叫你金毛狮王子。因为没人认出你妈整形后的你妈已经回炉再造了这就是原型的整体重写。尼玛你特么也是够了 Dont BB Show me the codefunction Person (name) { this.name name; } function Mother () { } Mother.prototype { //Mother的原型 age: 18, home: [Beijing, Shanghai] }; Person.prototype new Mother(); //Person的原型为Mother //用chrome调试工具查看提供了__proto__接口查看原型这里有两层原型各位还是直接看chrome好一点。 var p1 new Person(Jack); //p1:Jack; __proto__:{__proto__:18,[Beijing,Shanghai]} var p2 new Person(Mark); //p2:Mark; __proto__:{__proto__:18,[Beijing,Shanghai]} p1.age 20; /* 实例不能改变原型的基本值属性正如你洗剪吹染黄毛跟你妈无关 * 在p1实例下增加一个age属性的普通操作与原型无关。跟var o{}; o.age20一样。 * p1下面多了个属性age而__proto__跟 Mother.prototype一样age18。 * p2只有属性name__proto__跟 Mother.prototype一样 */ p1.home[0] Shenzhen; /* 原型中引用类型属性的共享正如你烧了你家就是烧了你全家的家 * 这个先过下文再仔细唠叨一下可好 * p1Jack,20; __proto__:{__proto__:18,[Shenzhen,Shanghai]} * p2Mark; __proto__:{__proto__:18,[Shenzhen,Shanghai]} */ p1.home [Hangzhou, Guangzhou]; /* 其实跟p1.age20一样的操作。换成这个理解: var o{}; o.home[big,house] * p1Jack,20,[Hangzhou,Guangzhou]; __proto__:{__proto__:18,[Shenzhen,Shanghai]} * p2Mark; __proto__:{__proto__:18,[Shenzhen,Shanghai]} */ delete p1.age; /* 删除实例的属性之后原本被覆盖的原型值就重见天日了。正如你剃了光头遗传的迷人小卷发就长出来了。 * 这就是向上搜索机制先搜你然后你妈再你妈他妈所以你妈的改动会动态影响你。 * p1Jack,[Hangzhou,Guangzhou]; __proto__:{__proto__:18,[Shenzhen,Shanghai]} * p2Mark; __proto__:{__proto__:18,[Shenzhen,Shanghai]} */ Person.prototype.lastName Jin; /* 改写原型动态反应到实例中。正如你妈变新潮了邻居提起你都说你妈真潮。 * 注意这里我们改写的是Person的原型就是往Mother里加一个lastName属性等同于Mother.lastNameJin * 这里并不是改Mother.prototype改动不同的层次效果往往会有很大的差异。 * p1Jack,[Hangzhou,Guangzhou]; __proto__:{jin,__proto__:18,[Shenzhen,Shanghai]} * p2Mark; __proto__:{jin,__proto__:18,[Shenzhen,Shanghai]} */ Person.prototype { age: 28, address: { country: USA, city: Washington } }; var p3 new Person(Obama); /* 重写原型这个时候Person的原型已经完全变成一个新的对象了也就是说Person换了个妈叫后妈。 * 换成这样理解var a10; ba; a20; ca。所以b不变变得是c所以p3跟着后妈变化与亲妈无关。 * p1Jack,[Hangzhou,Guangzhou]; __proto__:{jin,__proto__:18,[Shenzhen,Shanghai]} * p2Mark; __proto__:{jin,__proto__:18,[Shenzhen,Shanghai]} * p3:Obama;__proto__: 28 {country: USA, city: Washington} */ Mother.prototype.no 9527; /* 改写原型的原型动态反应到实例中。正如你妈他妈变新潮了邻居提起你都说你丫外婆真潮。 * 注意这里我们改写的是Mother.prototypep1p2会变但上面p3跟亲妈已经了无瓜葛了不影响他。 * p1Jack,[Hangzhou,Guangzhou]; __proto__:{jin,__proto__:18,[Shenzhen,Shanghai],9527} * p2Mark; __proto__:{jin,__proto__:18,[Shenzhen,Shanghai],9527} * p3:Obama;__proto__: 28 {country: USA, city: Washington} */ Mother.prototype { car: 2, hobby: [run,walk] }; var p4 new Person(Tony); /* 重写原型的原型这个时候Mother的原型已经完全变成一个新的对象了人他妈换了个后妈 * 由于上面Person与Mother已经断开联系了这时候Mother怎么变已经不影响Person了。 * p4:Tony;__proto__: 28 {country: USA, city: Washington} */ Person.prototype new Mother(); //再次绑定 var p5 new Person(Luffy); // 这个时候如果需要应用这些改动的话那就要重新将Person的原型绑到mother上了 // p5:Luffy;__proto__:{__proto__: 2, [run,walk]} p1.__proto__.__proto__.__proto__.__proto__ //null你说原型链的终点不是null Mother.__proto__.__proto__.__proto__ //null你说原型链的终点不是null看完基本能理解了吧现在再来说说 p1.age 20、p1.home [Hangzhou, Guangzhou] 和 p1.home[0] Shenzhen 的区别。 p1.home[0] Shenzhen; 总结一下是 p1.object.methodp1.object.property 这样的形式。p1.age 20; p1.home [Hangzhou, Guangzhou];这两句还是比较好理解的先忘掉原型吧想想我们是怎么为一个普通对象增加属性的var obj new Object(); obj.namexxx; obj.num [100, 200];这样是不是就理解了呢一样一样的呀。那为什么 p1.home[0] Shenzhen 不会在 p1 下创建一个 home 数组属性然后将其首位设为 Shenzhen呢 我们还是先忘了这个想想上面的obj对象如果写成这样 var obj.name xxx, obj.num [100, 200]能得到你要的结果吗 显然除了报错你什么都得不到。因为obj还未定义又怎么能往里面加入东西呢同理p1.home[0]中的 home 在 p1 下并未被定义所以也不能直接一步定义 home[0] 了。如果要在p1下创建一个 home 数组当然是这么写了p1.home []; p1.home[0] Shenzhen;这不就是我们最常用的办法吗而之所以 p1.home[0] Shenzhen 不直接报错是因为在原型链中有一个搜索机制。当我们输入 p1.object 的时候原型链的搜索机制是先在实例中搜索相应的值找不到就在原型中找还找不到就再往上一级原型中搜索……一直到了原型链的终点就是到null还没找到的话就返回一个 undefined。当我们输入 p1.home[0] 的时候也是同样的搜索机制先搜索 p1 看有没有名为 home 的属性和方法然后逐级向上查找。最后我们在Mother的原型里面找到了所以修改他就相当于修改了 Mother 的原型啊。