JS原型与原型链|对象继承与实例底层原理

JS原型与原型链|对象继承与实例底层原理

原型是JavaScript面向对象的底层实现机制。JS没有传统语言的静态类,依靠原型完成属性、方法共享与继承。实例方法复用、class语法、instanceof类型判断全部构建在原型体系之上。

读懂原型与原型链,才能看懂对象实例底层逻辑,分辨各种继承方案优缺点,排查对象属性访问相关bug,是JS从语法基础迈向底层进阶的重要分水岭。


一、原型核心原理概述

每一个函数都自带 prototype(显式原型) ;每一个对象实例都自带 proto(隐式原型)。实例的 proto 指向构造函数的 prototype。

核心关系:实例.proto === 构造函数.prototype

原型的核心价值:多个实例共用原型上的方法,不需要每个实例复制一份函数,节省内存开销。

复制代码

// 构造函数 function Person(name) { this.name = name; } // 在原型上挂载共享方法 Person.prototype.sayHi = function() { console.log(`你好,我是${this.name}`) } const p1 = new Person("小明") const p2 = new Person("小红") p1.sayHi() p2.sayHi() // p1 和 p2 使用同一个 sayHi 函数,内存只存一份 console.log(p1.sayHi === p2.sayHi) // true


二、new 关键字底层执行流程

使用 new 创建对象实例,浏览器内部自动执行4步逻辑:

    1. 创建一个空普通JS对象 {}
    1. 将空对象的 proto 指向构造函数的 prototype
    1. 绑定this,执行构造函数内部代码,为新对象添加实例属性
    1. 如果构造函数没有手动返回对象类型,则自动返回新建的实例对象
复制代码

function Car(brand) { this.brand = brand } const car1 = new Car("比亚迪") console.log(car1.__proto__ === Car.prototype) // true


三、原型链查找机制

读取对象属性、方法时会触发原型链向上查找,赋值属性不会触发原型链。

  • 优先在对象自身查找,找到直接返回

  • 自身找不到,沿着 proto 向上访问原型对象

  • 持续向上查找,直到 Object.prototype

  • Object.prototype.proto 等于 null,到达链尾;整条链找不到返回 undefined

复制代码

const obj = {} // obj -> Object.prototype -> null console.log(obj.toString) // toString 来自 Object原型

注意:给对象做属性赋值,只会给当前对象新增属性,不会修改原型对象上面的属性。


四、继承实现方案

方案一:原型链继承

将子类构造函数prototype指向父类实例实现继承。

复制代码

function Animal(type) { this.type = type } Animal.prototype.eat = function() { console.log("动物进食") } function Dog(){} Dog.prototype = new Animal("犬科") Dog.prototype.constructor = Dog // 修正构造器指向 const dog = new Dog() dog.eat()

缺点:父类引用类型属性被全部实例共享;无法向父构造函数传参。

方案二:组合继承(传统工程经典方案)

借用构造函数 + 原型继承结合,解决原型链继承缺陷。

复制代码

function Animal(type) { this.type = type } Animal.prototype.eat = function() { console.log("动物进食") } function Dog(type) { Animal.call(this, type) // 借用父构造函数生成实例独有属性 } Dog.prototype = new Animal() Dog.prototype.constructor = Dog const dog = new Dog("犬科") console.log(dog.type) dog.eat()

方案三:ES6 class extends 继承

class只是原型的语法糖,底层依旧基于原型机制,简化手写继承代码。

复制代码

class Animal { constructor(type) { this.type = type } eat() { console.log("动物进食") } } class Dog extends Animal { constructor(type) { super(type) // 调用父类构造函数,必须写在this访问之前 } } const dog = new Dog("犬科") dog.eat()


五、constructor 构造器属性

prototype原型对象自带constructor,默认指向对应的构造函数,用来标记实例由哪个函数创建。

复制代码

function User(){} const u = new User() console.log(u.constructor === User) // true

开发踩坑:如果直接完整覆盖prototype对象,constructor属性会丢失,需要手动重置。


六、三种类型检测方式与区别

  • instanceof:沿着原型链做判断,检查构造函数prototype是否出现在实例原型链上,仅适合引用类型。

  • Object.prototype.toString.call():精准检测JS内置类型,可以区分数组、普通对象等。

  • typeof:适合原始类型判断;null返回object,无法区分数组与普通对象。

复制代码

console.log(dog instanceof Dog) // true console.log(Object.prototype.toString.call([])) // "[object Array]" console.log(typeof null) // "object"


七、原型工程实践规范(企业规范)

  • 实例独有的属性写在构造函数this上;多个实例共享的方法挂载prototype,节约内存。

  • 原型上尽量不要存放数组、对象这类引用类型,会出现实例之间互相污染。

  • class是语法糖,底层依旧原型,不要当成传统静态类。

  • 业务尽量避免直接操作 proto;优先使用Object.getPrototypeOf / Object.setPrototypeOf。


八、开发高频避坑总结

  • prototype属于函数 ;__proto__属于实例对象,二者不要混淆。

  • 只有读取属性才走原型链,赋值不会向上修改原型。

  • instanceof结果可以被人为修改原型伪造,不能作为100%可靠类型判断。

  • 原型链层级不要过深,层级过多会增加属性查找性能开销。

  • class继承子类constructor内部,super必须前置调用,否则this无法初始化直接报错。


九、写在最后

原型与原型链是JavaScript面向对象底层根基。JS依靠原型实现属性共享与继承,class、实例、instanceof全部建立这套体系之上。

弄懂原型链,才能够读懂内置对象方法、各类继承写法、框架组件继承逻辑,突破JavaScript底层进阶门槛。

相关推荐
拉格朗日(Lagrange)1 小时前
【第2 章】WorkBuddy 从入门到高手
开发语言·python
yujunl1 小时前
在U9C订单列表上开放多个按钮层叠的问题解决
开发语言
喆星时瑜1 小时前
Win10/11 安装 R 与 RStudio 详细图文教程
开发语言·r语言·安装
JustHappy1 小时前
「vConsole MCP🛠️」我让 AI 直接看见任何 H5 的日志和请求帮你 debug
前端·javascript·程序员
心中有你02142 小时前
【路径规划】A*寻路算法最通俗易懂讲解(C语言完整实现+详细注释)
c语言·开发语言·算法
言乐62 小时前
Python自动去除水印
开发语言·python·django·virtualenv·pygame
大圣编蚕2 小时前
C语言入门:基本语法汇总
c语言·开发语言
czq_26867194872 小时前
Python打卡第31天
开发语言·python
invicinble2 小时前
python 编程语言 认识维度
开发语言·数据库·python