原型以及原型链底层探究

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 等,如果没有原型,则可以将所有类型创建时的属性写死固定好,这也能满足我们的需求。

但是这样做有两个缺陷

  1. 【内存浪费】 每次创建对象、数组以及其他类型时,这些固有属性都会开辟新的内存,造成内存的浪费
  2. 【不支持自定义】若是想给不同的数据类型自定义公用方法或者属性,需要自己封装创建方法,或者是定义别的公用方法(挂载到window上等)

prototype__proto__ 的设计要点

  1. prototype 会开辟一块内存,__proto__ 则指向这个内存
  2. prototype在所有函数中都会存在,用户可以自定义自己需要的构造函数
  3. 用户可以修改原始构造函数的 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 自定义继承

你可能感兴趣的:(JS,原型,__proto__,prototype,javascript,Object)