读原型和原型链,通js底层原理
前言
JavaScript 中的原型(prototype)和原型链(prototype chain)是理解该语言中面向对象编程的核心概念之一。
-
原型(prototype) :
- 在 JavaScript 中,每个对象都有一个原型(prototype),它是一个指向另一个对象的引用。这个对象被称为原型对象。
- 当试图访问一个对象的属性时,如果对象本身没有这个属性,JavaScript 就会沿着原型链向上查找,直到找到相应的属性或到达原型链的末尾(即 Object.prototype)为止。
- 可以通过
Object.getPrototypeOf()
方法来获取对象的原型。
-
原型链(prototype chain) :
- 原型链是一种对象之间关系的模型,其中每个对象都有一个指向其原型的引用,从而形成一个链式结构。
- 当试图访问一个对象的属性时,JavaScript 引擎会先在该对象本身的属性中查找,如果没有找到,就会沿着原型链向上查找,直到找到相应的属性或到达原型链的末尾。
- 原型链的最顶端是 Object.prototype,它是 JavaScript 中所有对象的根原型。
原型和原型链的概念使得 JavaScript 中的对象能够共享属性和方法,并且能够实现继承和属性委托等特性。通过原型链,可以实现对象之间的属性和方法的共享和继承,从而有效地提高代码的复用性和可维护性。
prototype,__proto__和constructor的理解
1.函数本身属性
函数也属于对象,我们可以从中看出,其长度是形参的个数,【【scope】】为函数的作用域我们不可访问,但是对浏览器来说非常重要,函数的名字就是它的名字,虽然看起来有点多余了哈。
2.抽取出共同属性给原型对象
我们可以看见,在代码中,除了color和owner是传入参数决定,其他的东西都是固定的,我们就可以把共同拥有的属性或者方法抽出,放在构造函数的原型对象上。
构造函数的原型对象上的属性其实例对象均可使用,但是是隐式的,也就是说,我们打印实例对象的时候也访问不到,必须通过访问属性的方式。
那么下面大家看看这段代码
这个时候我们会发现product会打印‘huawei’但是已经是显性了。为什么呢?因为这个时候的product和原型对象身上的product、并不是一个东西。
因此,我们给出以下三条结论。
3.关于三者的理解
读完下面代码会加深我们的理解
function People(color) {
this.color = color
}
People.prototype.ear = 2
let p = new People('yellow')
console.log(p.__proto__ === People.prototype);
console.log(p.constructor === People.prototype.constructor);
console.log(p.constructor === People);
console.log(p.__proto__.__proto__ === Object.prototype);
console.log(p.__proto__.__proto__.constructor === Object);
最终结果都是true,为什么呢?
-
p.__proto__ === People.prototype
:__proto__
是一个指向对象的原型的属性。在这里,p
是通过People
构造函数创建的,因此它的原型是People.prototype
。所以,这个表达式返回true
。
-
p.constructor === People.prototype.constructor
:constructor
是 JavaScript 对象的一个属性,指向创建该对象的构造函数。People.prototype.constructor
是People
函数本身,因为它是People.prototype
的默认构造函数。因此,p.constructor
也会指向People
,所以这两个是相同的。
-
p.constructor === People
:- 这个表达式检查
p
的构造函数是否是People
。由于p
是通过People
构造函数创建的,因此这个表达式返回true
。
- 这个表达式检查
-
p.__proto__.__proto__ === Object.prototype
:- 由于
p.__proto__
是People.prototype
,那么p.__proto__.__proto__
是People.prototype
的原型。对于大多数构造函数的原型,它们的原型是Object.prototype
。因此,这个表达式是检查People.prototype
的原型是否是Object.prototype
,结果是true
。
- 由于
-
p.__proto__.__proto__.constructor === Object
:- 这里,
p.__proto__.__proto__
是Object.prototype
,这个原型的constructor
是Object
构造函数。因此,这个表达式是检查Object.prototype.constructor
是否是Object
,结果也是true
。
- 这里,
这些结果共同展示了 JavaScript 的原型和原型链如何运作,表明对象的创建者、继承关系,以及构造函数与原型的关系。
4.原型链例子说明
- 首先我们查找son的age,因为son里面有年龄(18),所以我们直接输出。
- 财产属性在father里面,因此son查不到,会到son的对象原型(father的实例对象)上面去找,然后发现是有的。
- 我们可以发现like只有在爷爷那里才有因此,son的对象原型也没有,因此我们找son的对象原型的对象原型,是一个爷爷的实例对象。
- 而say爷爷的实例对象也没有,因此找其对象原型,也就是son的对象原型的对象原型的对象原型,最终我们找到了。
- 因此我们也知道了js的底层查找机制,本质就是实例对象找不到这个属性,就往对象原型上找。一层一层往上,直至找出。像个链状结构,因此被称作原型链。
5.99%的对象都具有原型,也就是其构造函数的原型对象
这是一个面试中最容易出错的问题,那么对象都具有原型嘛?答案是错误的。大部分都有,而上面那种情况是没有的。
6.为什么构造函数的实例对象能继承原型对象的属性和方法
我们可以看出,就是多了一步在创建对象的时候,让实例对象的原型指向了原型对象,因此我们可以访问。
小结
当然!JavaScript 的原型和原型链就像是一个充满惊喜的神秘大陆,让你时而惊叹,时而捧腹大笑。
想象一下,你是一个 JavaScript 冒险者,踏上了原型链的征途。一开始,你创建了一个新对象,就像是造了一艘小船。但这个小船上有个指南针,它指向着你的原型,告诉你往哪儿走。你开始了探险,往原型的方向划去。
一路上,你发现了各种宝藏和怪物。有的宝藏是对象的属性和方法,它们藏在你的小船里,让你更强大;有的怪物则是未知的属性,让你瑟瑟发抖。但别担心,你有一把锋利的剑——__proto__
,可以砍开一切未知。
而原型链就像是一串串连接起来的小岛,你可以从一个小岛跳到另一个小岛,一直往上跳,直到你找到最后的宝藏——Object.prototype
。这个岛上的宝藏就是 JavaScript 中所有对象的根源。
有时候,你会迷失在原型链的迷宫里,一头雾水地不知所措。但别担心,只要记住你的小船始终指向着原型,你就能找到回家的路。
所以,JavaScript 的原型和原型链就像是一场奇妙的冒险,让你体验到探索未知的乐趣,以及发现宝藏的喜悦。愿你在 JavaScript 的世界里,永远充满勇气和好奇心! 当然!JavaScript 的原型和原型链就像是一个充满惊喜的神秘大陆,让你时而惊叹,时而捧腹大笑。
想象一下,你是一个 JavaScript 冒险者,踏上了原型链的征途。一开始,你创建了一个新对象,就像是造了一艘小船。但这个小船上有个指南针,它指向着你的原型,告诉你往哪儿走。你开始了探险,往原型的方向划去。
一路上,你发现了各种宝藏和怪物。有的宝藏是对象的属性和方法,它们藏在你的小船里,让你更强大;有的怪物则是未知的属性,让你瑟瑟发抖。但别担心,你有一把锋利的剑——__proto__
,可以砍开一切未知。
而原型链就像是一串串连接起来的小岛,你可以从一个小岛跳到另一个小岛,一直往上跳,直到你找到最后的宝藏——Object.prototype
。这个岛上的宝藏就是 JavaScript 中所有对象的根源。
有时候,你会迷失在原型链的迷宫里,一头雾水地不知所措。但别担心,只要记住你的小船始终指向着原型,你就能找到回家的路。
所以,JavaScript 的原型和原型链就像是一场奇妙的冒险,让你体验到探索未知的乐趣,以及发现宝藏的喜悦。愿你在 JavaScript 的世界里,永远充满勇气和好奇心!
转载自:https://juejin.cn/post/7366510480478322725