JavaScripts入门篇————js原型的底层原理

前言

之前,我们已经通过学习对象与构造函数了解到v8 在对象中查找属性,会先查找对象自己的属性,找不到再查找原型上的属性,那么该句中的原型到底所指何物,那就是我们今天探讨的主题。在这篇文章中,我们将从原型的基础概念讲起,逐步深入到原型链的工作原理、 proto 与 prototype 的区别,以及如何利用原型实现继承等核心话题。希望通过这篇文章,能帮你彻底揭开 JavaScript 原型系统的神秘面纱。

prototype(显示原型)

protype是函数天生就拥有的一个属性, 我们可以将一些属性和方法挂载在原型上,在创建实例后,实例就可以调用这个属性和方法,我们可以将一些公用的属性和方法添加在原型上,减少构造函数在执行时的性能开销。听起来是不是晦涩难懂,举个代码例子让你深刻理解:

js 复制代码
Array.prototype.abc = function(){
    console.log('abc')
}

const arr = []  //new Array()
arr.unshift(1)
console.log(arr)
arr.abc()

由对象的知识我们认识到,v8在创建一个数组开始时,其实是new了一个对象数组,而该对象中存在一个显示存在的属性即unshift函数,插入1,接着我们自己在原型上自己定义了一个abc方法,从而做到为arr这一基本类型添加操作,输出abc。这就是设计显示原型的方便之处,便于扩展对象功能。

作用体现

再举一个用了显示原型便利实现扩展功能的例子,

js 复制代码
function Car(color){
    // var this = {}  //1
    this.color = color
    this.name = 'su7'
    this.long = 5000
    this.height = 1000
    this.color = color//2


    // this.__proto__ = Car.prototype  //3__proto__是实例对象的显示原型,prototype是构造函数的隐式原型,两个指向同一个对象
    // return this //4

}
const car = new Car('red')
console.log(car)

可以预见,当我们要批量访问car函数时,我们的v8引擎会重复new car函数,使函数内的前几个属性一直被调用,从而失去时间性能。而当我们引入原型时:

js 复制代码
Car.prototype.name = 'su7'  
Car.prototype.long = 5000
Car.prototype.height = 1000
function Car(color){
    // var this = {}  //1
    this.color = color
    this.name = 'su7'
    this.long = 5000
    this.height = 1000
    this.color = color//

}
const car = new Car('red')
car.name = 'benz'
console.log(car)

console.log(car.__proto__)

我们通过在原型上添加属性从而实现了复用,每次new一个car时,这些属性会被"隐藏"在prototype里,可以访问。 通俗的说

prototype 是构造函数的 :制造商的零件库(给所有实例共享用的)

proto(隐式原型)

1.每个对象都有一个隐式的原型__proto__属性,该属性也是一个对象

  1. v8 在访问对象中的一个属性时,会先访问对象中显示存在的属性,如果不存在,会去对象的隐式原型上查找
  2. 实例对象的隐式原型 === 构造函数的现实原型
  3. onstructor 构造器属性,记录该实例对象是由谁创建的,接着看例子 5
js 复制代码
Person.prototype.age = function(){
    console.log('18岁')
}

function Person(){
    this.name = '张三'
}
const p = new Person()
// console.log(p);
p.age()
console.log(p.__proto__===Person.prototype)

可以看到11行打印true,那我们结合代码来拆解原理:

第一步:创建构造函数和原型对象,- p.proto 是实例的「隐形指针」,指向那个仓库 -第 11 行的 === 就是在验证这个指针是否真的指向了仓库 这就是 JavaScript 原型系统的核心原理!即

一表区分:

概念 prototype proto
所属者 构造函数(如 Person ) 实例对象(如 p )
别称 显示原型 隐式原型
作用 存放共享属性/方法的仓库 指向构造函数的 prototype

原型链

说完prototype(显示原型)和__proto__(隐式原型),我们聊聊他们之间查找关系,v8在访问对象中的一个属性时,会先访问对象中的显示存在的属性,如果没有,就会去对象的隐式原型上查找,如果还没有,就顺着隐式原型一直往上找,直到找到null ,这个查找关系,就叫做原型链,通俗的讲,- 一层一层往上找 : 自己没有 → 爸爸 → 爷爷 → ... → null

  • proto 是链条 :把所有原型对象串起来
  • null 是终点 :找到 null 还没找到,就返回 undefined 接下来看一段示例
js 复制代码
GrandFather.prototype.house=function(){
    console.log('汤臣一品')
}

function GrandFather() {
  this.card = '1234567890123456'
}
Father.prototype = new GrandFather()

function Father() {   //{card: '1234567890123456'}
  this.lastName = '张'
}
Child.prototype = new Father( )    //{lastName: '张'}
function Child() {
  this.age = 18
}
                                    //new Object()
const p = new Child() //p.__proto__ = Child.prototype.__proto__ = Object.prototype.__proto__ = null

p.house()

可以看到最后输出的是GrandFather.prototype.house里的函数属性,那么我们来梳理一下逻辑:

console.log(xiaoming.name) // 1. 先找自己 → '小明' ✅

console.log(xiaoming.car) // 2. 自己没有 → 找爸爸 → '特斯拉' ✅

console.log(xiaoming.money) // 3. 爸爸也没有 → 找爷爷 → 1000000 ✅

xiaoming.house() // 4. 继续找 → 爷爷的原型 → '🏠 汤臣一品' ✅

看看原型链结构

console.log(p.proto === Child.prototype) // true

console.log(Child.prototype.proto === Father.prototype) // true

console.log(Father.prototype.proto === GrandFather.prototype) // true

console.log(GrandFather.prototype.proto === Object.prototype) // true(终点前)

console.log(Object.prototype.proto === null) // true(终点!)

接下来看一张原型链图片,理解之后你就能彻底知道这种查找关系背后的逻辑:

过程参考:const f1 = new Foo()

  1. f1.proto = Foo.prototype

  2. Foo.prototype.proto = Object.prototype

  3. Object.prototype.proto = null

  4. Foo.proto = Function.prototype

  5. Function.prototype.proto = Object.prototype

  6. Function.proto = Function.prototype

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄3 天前
JavaScript 隐式全局变量解析
javascript
汉堡大王95273 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大3 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师3 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端