就我今天的学习来说,JS中比较重要的就是原型、以及原型链,它们的定义如下:
原型:每一个构造函数(例如Object)都有一个属性 prototype 来指向其原型对象。
对象:对于任意对象来说,都有一个属性__proto__来指向其缔造者的原型对象,这里的对象通常指通过构造函数new出来的一个实例对象,有它自己的属性和方法。
原型对象:对于原型对象来说,通常有一个属性constructor来指向其构造函数,也就是说,这个原型对象是属于哪一个构造函数的。
下面来了解一下为什么会出现原型对象:
在学习JS高级之前,通常不会了解到这个名词,所以要弄懂它存在的意义是什么:
实例对象有属性和方法,通过构造函数可以设置对象的公有属性,但实例对象的方法通常是不相同的,但每一次创建对象添加不同的方法就需要不断开辟空间,很浪费内存,所以设置出一个原型对象来存储这些方法:当我们通过实例对象来调用方法时,会先在实例对象中寻找方法名并执行,如果没有,就到实例对象中寻找方法名并执行;这样就可以节约空间,不用再通过堆栈的方式来存储这样的复杂数据类型。
这里涉及到了复杂数据类型的存储以及new关键字创建对象的流程:
(1)简单数据类型和复杂数据类型的存储:
当数据为简单数据类型时,直接在栈中开辟空间存入变量即可;
当数据为复杂数据类型时,直接在栈中不能存储,需要现在栈中开辟空间存储地址(堆中真正存储内容地方的地址),再将这个地址指向堆中存储内容的地方,需要内容时直接调用地址指向即可;也就是说真正存储内容的地方是堆而非栈。
(2)new关键字创建对象的流程:
1.new 构造函数可以在内存中创建了一个空的对象
2.this 就会指向刚才创建的空对象
3.执行构造函数里面的代码 给这个空对象添加属性和方法
4.返回这个对象
下面回归正题 说说原型链:
首先一定要有一个构造函数 这里用Stu举例:
Stu构造函数通过new关键字创建了stu实例对象:
那么根据上面的总结,构造函数有prototype属性来指向其原型对象,而每一个对象都有__proto__属性指向其原型对象,那么一定会有一个原型对象:如下图
还有一个属性constructor 是属于原型对象,那么把图完善一下就是:
那么说所有的对象都有一个属性__proto__那么原型对象是不是对象呢?答案是肯定的。
所以上图还是不完全的:
因为Object构造函数是自带的,所以不用我们自己定义;
且因为Object构造函数已经代表了整个文档的顶级,所以其原型对象再去查找__proto__属性所指向的原型对象是查不到的。