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

相关推荐
GuWenyue15 小时前
从零搭建用户管理系统!60分钟搞定RESTful接口+Bootstrap语义化首页
前端·后端
蜡笔小电芯15 小时前
【Electron】第1章—新建工程(基于 Electron + Vite + JavaScript)
前端·javascript·electron
_xaboy15 小时前
开源Vue组件 FormCreate 使用组件内部方法校验
前端·vue.js·开源
审判长烧鸡15 小时前
【AI问答/前端】前端满天过海局(一)
前端·vue·浏览器
张元清15 小时前
React 指针 Hook:Hover、长按、双击、刮擦和点击外部,告别那些经典 bug
前端·javascript·面试
Csvn15 小时前
前端技术 - WebAssembly
前端·d3.js
咕噜咕噜啦啦15 小时前
从spring到spring boot——JAVA项目开发
java·前端·spring boot·后端·spring
Bigger16 小时前
Agent 循环:AI 助手的思考引擎
前端·ai编程·claude
yqcoder16 小时前
数据的“洁癖”管家:深入解析 JavaScript Set
开发语言·javascript·ecmascript