第一个重要知识:JS 公式
-
对象.proto === 其构造函数.prototype
-
JS 唯一公式,如果不会就套公式
第二个重要知识:根公理
-
Object.prototype 是所有对象的(直接或间接)原型
-
加了一个直接或间接,所谓公理就是规定好的
第三个重要知识:函数公理
-
所有函数都是由 Function 构造的
-
任何函数
.__proto__ === Function.prototype
-
任意函数有
Object / Array / Function
拨乱反正
乱一
- XXX 的原型
{name:'frank'} 的原型
[1,2,3] 的原型
Object 的原型
- 解读
Object 的原型是
Object.__proto__
:对
Object 的原型是 Object.prototype
:错
- 错在哪
「的原型」等价于
「.__proto__」
中文的「原型」无法区分 __proto__
和 prototype
所以我们只能约定,原型默认表示 __proto__
只不过 __proto__
正好等于某个函数的 prototype
乱二
- 我觉得矛盾了 [1,2,3] 的原型是 Array.prototype
你有说 Object.prototype 是所有对象的原型
那为什么 Object.prototype 不是 [1,2,3] 的原型
- 错在哪 原型分两种:直接原型和间接原型
对于普通对象来说,Object.prototype 是直接原型
对于数组、函数来说,Object.prototype 是间接原型
乱三
- Object.prototype 不是根对象
- 理由: Object.prototype 是所有对象的原型
Object 是 Function 构造出来的
所以,Function 构造了 Object.prototype (错误! Function只是构造了一个存根对象地址的属性,仅此而已)
推论,Function 才是万物之源啊!
- 错在哪: Object.prototype 和 Object.prototype 对象 的区别
对象里面从来都不会包含另一个对象
接下来我们要把 JS 世界的建造顺序理清楚
JS 世界的构造顺序
- 创建根对象
#101
(toString),根对象没有名字 - 创建函数的原型
#208
(call /apply),原型__proto__
为#101
- 创建数组的原型
#404
(push/pop),原型__proto__
为#101
- 创建 Function
#342
,原型__proto__
为#208
- 用 Function.prototype 存储函数的原型,等于
#208
- 此时发现 Function 的
__proto__
和 prototype 都是#208
- 用 Function 创建 Object
- 用 Object.prototype 存储对象的原型,等于
#101
- 用 Function 创建 Array
- 用 Array.prototype 存储数组的原型,等于
#404
- 创建 window 对象
- 用 window 的 'Object' 'Array' 属性将 7 和 9 中的函数命名
- 记住一点,JS 创建一个对象时,不会给这个对象名字的
JS 世界的构造顺序(续)
-
用 new Object() 创建 obj1 new 会将 obj1 的原型
__proto__
设置为 Object.prototype,也就是#101
-
用 new Array() 创建 arr1 new 会将 arr1 的原型
__proto__
设置为 Array.prototype,也就是#404
-
用 new Function 创建 f1 new 会将 f1 的原型
__proto__
设置为 Function.prototype,也就是#208
JS 世界的构造顺序(续)
-
自己定义构造函数 Person,函数里给 this 加属性 Person 自动创建 prototype 属性和对应的对象
#502
-
在 Person.prototype
#502
上面加属性 -
用 new Person() 创建对象 p new 会将 p 的原型
__proto__
设为#502
总结
- 构造函数
是用来构造对象的
会预先存好对象的原型,原型的原型是根
new 的时候将对象的 __proto__
指向原型
- 对象 所有对象都直接或间接指向根对象
如果对象想要分类,就在原型链上加一环
用构造函数可以加这一环
- 思考 如果加了一环之后,想再加一环怎么办
以后会在「继承」里讲