☰
JS原型与原型链|对象继承与实例底层原理
2026/10/1 21:30:03 网站建设 项目流程

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对象 {}

  • 2. 将空对象的 __proto__ 指向构造函数的 prototype

  • 3. 绑定this,执行构造函数内部代码,为新对象添加实例属性

  • 4. 如果构造函数没有手动返回对象类型,则自动返回新建的实例对象

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底层进阶门槛。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询