4.原型链灵魂7问

92 阅读5分钟

原型 和 原型链

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。看完事件的相关内容,写的一篇笔记。

1 前言

原型: 每个函数天生自带的 prototype 对象数据类型

作用: 由构造函数向 原型上 添加方法, 提供给该构造函数的所有实例使用

为了解决构造函数将方法书写在构造函数体内时造成的资源浪费

原型链:概念: 用 proto 串联起来的对象链状结构

作用: 为了对象访问机制服务(当你访问一个对象成员的时候, 为你提供一些服务)

注意: 只是 proto 串联起来的对象链状结构, 千万不要往 prototype 上靠

万物皆对象

在 JS 内, 任何一个数据类型其实都是对象

函数也是一个对象, 数组也是一个对象, 正则也是一个对象, ... =>

是对象, 就可以存储 键值对

以函数为例,当你书写完毕一个函数的时候,此时 函数数据类型 出现了, 同时该函数名也是一个对象数据类型

重要概念

  1. 每一个函数天生自带一个属性叫做 prototype, 是一个对象数据类型 

  2. 每一个对象天生自带一个属性叫做 proto, 指向所属构造函数的 prototype

  3. 任何一个对象, 如果没有准确的构造函数, 那么看做是 Object 的实例

    即只要是一个单纯的对象数据类型, 都是内置构造函数 Object 的实例

2 灵魂7问

 //创建构造函数
 function Fn(){}
 const fn = new Fn();

问题1: fn 身上的 proto 是谁 ? 

因为 fn 是 Person 的实例,根据 概念1 得到 fn.proto 指向所属构造函数的 prototype

 function Fn(){}
 const fn = new Fn();
 console.log(fn.__proto__ === Fn.prototype);//true

问题2: Fn 的 proto 是谁?

Fn是一个构造函数, 同时也是一个函数, 同时也是一个对象,只要是对象就会有 proto 属性。

JS 内有一个内置构造函数叫做 Function, 只要是函数, 就看做 Function 的实例,任何一个函数数据类型所属的构造函数都是 Function

Fn看做是 Function 的实例,Fn所属的构造函数就是 Function,即Fn.proto 指向 Function.prototype

 function Fn(){}
 const fn = new Fn();
 console.log(Fn.__proto__ === Function.prototype);//true

问题3: Fn.prototype 的 proto 是谁?

Fn.prototype 是函数天生自带的一个对象数据类型,只要是对象就会有 proto 属性

JS 内有一个内置构造函数叫做 Object, 只要是单纯的对象, 都是 Object 的实例。

Fn.prototype 是一个天生的对象数据类型, 并且是一个单纯的对象数据类型,就可以把 Fn.prototype 看做是 Object 的实例

Person.prototype 的 proto 就是 Object.prototype

 function Fn(){}
 const fn = new Fn();
 console.log(Fn.prototype.__proto__ === Object.prototype);//true

问题4: Function 的 proto 是谁?

Function 是一个构造函数, 同时也是一个函数, 同时也是一个对象

只要是对象就会有 proto 属性

JS 内有一个内置构造函数叫做 Function, 只要是函数就是 Function 的实例

Function 自己本身是一个内置构造函数, 本身也是一个函数,而Function 也自己是自己的实例, 自己是自己的构造函数

在 JS 内管 Function 叫做顶级函数,所有Function.proto 就是 Function.prototype

 function Fn(){}
 const fn = new Fn();
 console.log(Function.__proto__ === Function.prototype);//true

问题5: Function.prototype 的 proto 是谁?

Function.prototype 是函数天生自带的一个对象数据类型 ,只要是对象就会有 proto 属性

Function.prototype 是一个天生的对象数据类型, 并且是一个单纯的对象数据类型,把 Function.prototype看做是 Object 的实例  Function.prototype 的 proto 就是 Object.prototype

 function Fn(){}
 const fn = new Fn();
 console.log(Function.prototype.__proto__ === Object.prototype);//true

问题6: Object 的 proto 是谁?

Object 是一个构造函数, 同时也是一个函数, 同时也是一个对象

只要是对象就会有 proto 属性,Object 也是一个函数(内置构造函数), 只要是函数就是 Function 的实例

Object 这个内置函数所属的构造函数依旧是 Function,即Object.proto 就是 Function.prototype

 function Fn(){}
 const fn = new Fn();
 console.log(Object.__proto__ === Function.prototype);//true

问题7: Object.prototype 的 proto 是谁?

Object.prototype 是函数天生自带的一个对象数据类型,只要是对象就会有 proto 属性

在 JS 内, Object 是顶级对象, Object.prototype 是顶级原型

Object.prototype 是唯一一个没有 proto 的对象数据类型,

即 Object.prototype 的 proto 是 null

 function Fn(){}
 const fn = new Fn();
 console.log(Object.prototype.__proto__ === null);//true

3 对象访问机制

当访问对象成员的时候,会首先在自己本身上查找,如果有,直接使用,如果没有,会自动去自己的 proto 上查找。

如果还没有,再去__proto__上查找,一次类推,直顶级原型都没有,返回undefined。

 function Fn(){}
 const fn = new Fn();
 Fn.prototype.a = ()=>{
     console.log('Fn.prototype.a');
     //自定义构造函数的.prototype中添加的内容,给该构造函数的所有实例使用。
 }
 Function.prototype.b = ()=>{
     console.log('Function.prototype.b');
     // Function.prototype中添加的内容,所有函数数据类型都可以使用。
 }
 Object.prototype.c = ()=>{
     console.log('Object.prototype.c');
     // Object.prototype中添加的内容,所有数据类型都可以使用。
 }
 //自定义构造函数的.prototype中添加的内容,给该构造函数的所有实例使用。
 fn.a()//Fn.prototype.a
 ​
 // Function.prototype中添加的内容,所有函数数据类型都可以使用。
 // fn.b();
 // 会报错 TypeError: fn.b is not a function
 ​
 Fn.b();//Function.prototype.b
 Function.b();//Function.prototype.b
 Object.b()//Function.prototype.b
 ​
 // Object.prototype中添加的内容,所有数据类型都可以使用。
 fn.c();//Object.prototype.c
 Fn.c();//Object.prototype.c
 Function.c();//Object.prototype.c
 Object.c()//Object.prototype.c

结论:

Object.prototype中添加的内容,所有数据类型都可以使用。

Function.prototype中添加的内容,所有函数数据类型都可以使用。

自定义构造函数的.prototype中添加的内容,给该构造函数的所有实例使用。

prototype只用于添加,不用于任何访问。