原型与原型链
Contents
为什么要有原型?
首先来看一段简短的代码
|
|
这段代码在浏览器中为什么不报错?
简单解释一下,obj
有一个隐藏的属性,隐藏属性存储了Object.prototype
对象的地址,输入obj.toString()
时发现obj上没有toString的地址,于是就去隐藏属性里面找,最终找到了Object.prototype.toString.
再来看一段代码
|
|
obj
和obj2
有什么联系?
相同点是他们都可以调用.toString()。不同点是他们的地址不同,可以拥有不同的属性。反过来说就是
**XXX.prototype
存储了XXX
对象的共同属性。而这就是原型。**
如果没有原型声明一个对象:
|
|
这显然是不现实的。
原型让你无需重复声明共有属性。省代码,省内存。
每个对象都有一个隐藏属性指向原型,这个隐藏属性就叫__proto__
prototype
和__proto__
区别是什么?
它们都保存着原型的地址,但是prototype
挂在函数上,__proto__
挂在每个新生成的对象上。
原型三大最重要知识
众所周知,JS有三座大山,它们分别是原型、this以及AJAX。这三个知识点是JS的门槛,理解起来需要时间。不理解是正常的,否则JS就真的毫无门槛了。怎么翻过这三座大山呢?反复学反复理解。
要翻过原型这座大山,有三个最重要的知识必须掌握。
一.原型公式
**对象.__proto__
===
其构造函数.prototyoe
**
遇到这类型的题目可以直接用套公式来解决。
二.原型根公理
Object.prototype
是所有对象的(直接或间接)原型
三.函数构造公理
所有函数都是由Function
构造的,即任何函数.__proto__===Function.prototype
,任意函数有Object/Array/Function
基于这三个知识和基础知识,我们可以推出整个JS世界。
JS世界的构造顺序
- 创建根对象
#001(toString)
,根对象没有名字。 - 创建函数的原型
#200(call/apply)
,原型__proto__
为#001
- 创建数组的原型
#300(push/pop)
,原型__proto__
为#001
- 创建
Function#301
,原型__proto__
为#200
- 用
Function.prototype
存储函数的原型,令其等于#200
- 此时发现
Function
的__proto__
和prototype
都是#200
- 用
Funciton
创建Object
函数 - 用
Object.prototype
存储对象的原型,令其等于#001
- 用
Function
创建Array
函数 - 用
Array.prototype
存储数组对象的原型,令其等于#200
- 创建
window
函数 - 用
window
中的'Object''Array'
属性将7和9中的函数命名
记住一点,JS创建一个对象时,是不会给这个对象名字的。
原型与构造函数
所谓构造函数就是用来构造对象的,会预先保存好对象的原型,new的时候将对象__p指向原型。
所有对象都直接或间接指向根对象,对象想要分类时,就可以在原型链上加以换,用构造函数就可以加这一环。
例子:
- 自己定义构造函数X,函数里给this加属性
- X自动创建prototype属性和对应的对象#502
- 在X.prototype#502上面加属性
- 用new X()创建对象x
- new会将x的原__proto__设为#502
原型与原型链终极图示
Author wuyining
LastMod 2022-02-13