1. prototype
prototype
:所有 __proto__
都继承于prototype
;也是原型继承的基石,有它才有原型以及原型链;也是原型链的顶点。
// 所有对象的 __proto__ 都继承于构造函数的 prototype
let obj = new Object()
obj.__proto__ === Object.prototype // true
let fn = new Function()
fn.__proto__ === Function.prototype // true
2. __ proto__
__proto__
:对象的原型,是对象的特有属性;继承于构造函数的 prototype
。每个__proto__
下面又会有一个__proto__
,这样层层嵌套就形成了原型链(顶层为null
)。
注意:虽然__proto__
为对象的特有属性,但是函数也会有__proto__
属性,因为函数也是一种特殊的对象(js 万物皆对象)。
// 原理链的尽头为 null
let obj = {}
console.log(obj.__proto__.constructor) // 构造器,指向构造函数 Object
console.log(obj.__proto__.__proto__) // null
3. Function 与 Object 之间的关系
构造函数(只列举 Object 以及 Function)
Object()
:对象的构造函数,所有字面量以及 new 形式声明的对象;都是由Object 构造函数生成Function()
:函数的构造函数,所有字面量以及 new 形式声明的函数(除箭头函数外),都是由 Function 构造函数生成的;并且所有内置函数以及构造函数(包括 Function 本身),都是由 Function 构造出来的注意:Function 比较特殊,它的原型等于他的prototype
Function.__proto__ === Function.prototype
先说结论:Function 与 Object 之间存在相互继承的关系
为什么呢?如下
// 第一: Object 是由 Function 构造出来
Object.__proto__ === Function.prototype
// 第二: Function 的原型中又存在 __proto__对象,对象又是 Object 生成的,他们任意一方在 prototype 中定义了属性后,对方都能通过原型链访问到
Object.__proto__ === Function.prototype // true
Function.__proto__.__proto__ === Object.prototype // true
/* ----- -------- --------- ------- ---- */
Function.prototype.fn = function () {}
Object.fn // function fn () {}
Object.prototype.obj = {}
Function.obj // {}
4. 原型链为何设计为__proto__ 和 prototype
很多时候,我们在创建对象、数组、函数时,我们希望它们能有一些共有属性或者方法,比如 valueOf
toString
等,如果没有原型,则可以将所有类型创建时的属性写死固定好,这也能满足我们的需求。
但是这样做有两个缺陷
- 【内存浪费】 每次创建对象、数组以及其他类型时,这些固有属性都会开辟新的内存,造成内存的浪费
- 【不支持自定义】若是想给不同的数据类型自定义公用方法或者属性,需要自己封装创建方法,或者是定义别的公用方法(挂载到window上等)
prototype
和 __proto__
的设计要点
prototype
会开辟一块内存,__proto__
则指向这个内存prototype
在所有函数中都会存在,用户可以自定义自己需要的构造函数- 用户可以修改原始构造函数的
prototype
,可以定义不同数据类型的公用方法,并且不同数据类型之间不会相互影响
5. 现实应用
5.1 定义公用方法
目前想创建一个公共方法库,名为$plugins
,并且可以让使用者直接使用 this
调用这个公共方法,还不会因指向问题而出错。
let obj = {}
// 定义对象的顶层 prototype
Object.prototype.$plugins = { fn: () => { console.log('调用成功') } }
// 尝试在不同环境下,不同的指向调用公共方法
this.$plugins.fn() // 调用成功
window.$plugins.fn() // 调用成功
$plugins.fn() // 调用成功
obj.$plugins.fn() // 调用成功
5.2 自定义继承
略