10分钟搞懂 js 原型

原型很简单,10 分钟就能搞懂!!!

函数

先来看一下上古时期的工作中我们是如何定义函数的,直接使用 function 关键字来声明

js 复制代码
function fun() {}

但是有的时候我们会发现函数也会用下面的这种格式来定义

js 复制代码
function Fun() {}

除了第二个 函数名的首字母大写之外 ,本质上两者毫无区别

函数名首字母大写的意义

当我们需要将一个函数作为 构造函数 使用时,通常会将函数名首字母大写,为了看起来规范一些,仅此而已

实例化

构造函数 使用 new 关键字可以创建出不同的 实例(实例的本质就是一个对象),就好比说:你没有女朋友,但是你可以准备一个构造函数 new 很多女朋友出来,就是这个意思!

开造

  • 构造函数(女朋友构造器):
js 复制代码
function GirlFriend() {}
  • 创建第一个 gf1 (实例对象)
javascript 复制代码
const gf1 = new GirlFriend()

gf1.name = '小美'
gf1.age = 18

console.log(gf1)  // {name: '小美', age: 18}
  • 创建第二个 gf2 (实例对象)
javascript 复制代码
const gf2 = new GirlFriend()

gf2.name = '小丽'
gf2.age = 19

console.log(gf2) // {name: '小丽', age: 19}

关联

  • GirlFriend 是一个 构造函数
  • gf1gf2 是通过 new GirlFriend 创建出来的两个 实例对象

那如何将 实例对象构造函数 联系在一起呢?

  • 实例对象 上会默认存在一个属性叫做 __proto__,这里记作 隐式原型
  • 构造函数 上会默认存在一个属性叫做 prototype,这里记作 **显示原型 **

通常我们所说的 原型对象 也就是指这里的 prototype原型对象 上的 constructor属性可以直接访问该 构造函数 (这里建议手动打印观察一下)

默认情况下,实例对象__proto__ 指向 构造函数prototype,如果你想访问某个实例的原型对象,就可以通过如下关系来进行访问

javascript 复制代码
console.log(GirlFriend.prototype.constructor) // ƒ GirlFriend() {}
gf1.__proto__ === GirlFriend.prototype // true
gf2.__proto__ === GirlFriend.prototype // true

访问

当我需要访问 实例对象 上存在的属性,比如 name 时:

javascript 复制代码
console.log(gf1.name) // '小美'
console.log(gf2.name) // '小丽'

当我需要访问 实例对象 上不存在的属性,比如 feature 时:

javascript 复制代码
console.log(gf1.feature) // undefined
console.log(gf2.feature) // undefined

因为没有这个属性,自然而然就会打印 undefined

但如果说我想添加一个共同的属性给所有被 实例化的对象 时,我该如何去处理呢?

  • 上面已经说明,被同一个 构造函数 创建出来的 实例对象 ,默认情况下他们的 隐式原型 都会指向该构造函数的 显示原型 ,也就是 GirlFriend.prototype,因此我只需要在往这个原型上去添加就好
javascript 复制代码
GirlFriend.prototype.feature = 'beautiful'

此时再次访问实例上的 feature属性,最终即可得到正常的打印

javascript 复制代码
console.log(gf1.feature) // beautiful
console.log(gf2.feature) // beautiful

如果说我想单独给 gf1 添加不一样的 feature 再访问呢

javascript 复制代码
gf1.feature = 'pretty'

console.log(gf1.feature) // pretty
console.log(gf2.feature) // beautiful

但是,为什么我给 显示原型 添加的属性可以直接通过实例对象进行访问呢?

原理

  1. 每一个被 构造函数 创建的 实例对象 都是一个全新的 对象 ,我们可以为该对象添加本身特有的属性
  2. 当我们尝试访问 实例对象 上的某个属性时,如果存在则会直接返回该属性的值;如果不存在,就会沿着 实例对象__proto__ 继续向上访问,如果查找到则会返回该属性的值,如果没有找到,则会返回 undefined

注意

为了更加清晰的了解原型,这里我们再提及 js 中几个比较关键的点

普通对象 - object
  • 只要是一个普通对象object,就可以用 new Object() 来实例化(Object() 是一个内置的构造函数 ),也就是说,所有的对象字面量都是 Object() 的实例
  • Object 作为构造函数,Object.prototype 指向一个具体的 原型对象 ,该 原型对象 作为对象的实例,它的 __proto__ 值为 null,因而 Object.prototype.__proto__ = null 时也就走到了 原型的尽头
javascript 复制代码
const obj = {}
const obj1 = new Object()

console.log(obj.__proto__ === obj1.__proto__)  // true
console.log(obj1.__proto__ === Object.prototype) // true
console.log(Object.prototype.____proto__) // null

回到上面那个例子,当我要访问 实例对象 gf1 上的属性时:

  • 如果该属性存在,就会直接返回对应的值
  • 如果该属性不存在,就会沿着 gf1.__proto__ 进行查找,本质上查找的就是 GirlFriend.prototype 这个对象
    • 如果该属性存在,就会直接返回对应的值
    • 如果该属性不存在,那么 GirlFriend.prototype 作为 Object实例对象 ,其本身也是存在 __proto__ 属性的,所以会沿着 GirlFriend.prototype.__proto__来进行查找,本质上查找的就是 Object.prototype
      • 如果该属性存在,就会直接返回对应的值
      • 如果不存在,就会查找接着查找 Object.prototype.__proto__ ,此时 Object.prototype.__proto__ 值为 null ,最终没有找到该属性,打印 undefined

这个顺序很好理解

  1. gf1.xx
  2. gf1.__proto__.xx
  3. gf1.__proto__.__proto__.xx
  4. gf1.__proto__.__proto__.__proto__.xx

当最终 __proto__null 都没有找到时就会打印 undefined

因此,沿着 __proto__ 访问对象属性构成的这一条链也就是平时所说的 原型链

特殊对象 - function
  • function 也算是一类特殊的对象,因此可以直接通过属性的形式来进行变量的访问

  • 已经内置了 Function() 构造函数 ,因而 所有函数 都算作是 Function实例对象

    • Function 作为 构造函数 时,可以访问其 prototype 属性
    • Function 作为 实例对象 时,可以访问其 __proto__ 属性
javascript 复制代码
// 在 Function 这里就是:我实例化了我寄几
console.log(Function.__proto__ === Function.prototype) // true
console.log(Function.prototype.constructor === Function) // true
  • 内置的 Object() 也是一个函数,因此 Object 也是我 Function实例对象
javascript 复制代码
console.log(Object.__proto__ === Function.prototype) // true

经典图示

相关推荐
小白小白从不日白4 分钟前
react 组件通讯
前端·react.js
罗_三金15 分钟前
前端框架对比和选择?
javascript·前端框架·vue·react·angular
Redstone Monstrosity22 分钟前
字节二面
前端·面试
东方翱翔29 分钟前
CSS的三种基本选择器
前端·css
Fan_web1 小时前
JavaScript高级——闭包应用-自定义js模块
开发语言·前端·javascript·css·html
yanglamei19621 小时前
基于GIKT深度知识追踪模型的习题推荐系统源代码+数据库+使用说明,后端采用flask,前端采用vue
前端·数据库·flask
千穹凌帝1 小时前
SpinalHDL之结构(二)
开发语言·前端·fpga开发
dot.Net安全矩阵1 小时前
.NET内网实战:通过命令行解密Web.config
前端·学习·安全·web安全·矩阵·.net
叫我:松哥1 小时前
基于Python flask的医院管理学院,医生能够增加/删除/修改/删除病人的数据信息,有可视化分析
javascript·后端·python·mysql·信息可视化·flask·bootstrap
Hellc0071 小时前
MacOS升级ruby版本
前端·macos·ruby