JavaScript 原型与继承机制详解:__proto__、prototype 与 constructor

作者:代码拾荒时间:2026-10-23 06:59:51浏览:375

本文详细解析 JavaScript 中的原型与继承机制。重点区分 __proto__ 与 prototype 的作用,解释 constructor 属性的归属与修改限制,并介绍 ECMAScript 2015 规范中推荐的 Object.getPrototypeOf 等标准 API,帮助开发者深入理解对象属性查找与继承原理。

参考文献

JavaScript 原型与继承的核心机制解析

JavaScript 原型与继承的核心机制解析

__proto__ 属性详解

__proto__ 属性详解

在 JavaScript 中,除 null 和 undefined 外的所有数据类型均具备 __proto__ 属性。该属性定义了对象的隐式原型链:当访问对象自身不存在的属性时,引擎会沿 __proto__ 指向的对象继续查找,直至找到对应属性或到达链尾(返回 undefined)。

我们将 __proto__ 所指向的对象定义为该对象的原型。通过修改对象的 __proto__ 属性,可以动态改变对象继承的属性或方法。

__proto__ 修改示例


// 修改一个Number类型的值的原型
const num = 1;
num.__proto__.name = "My name is 1";
console.log(num.name); // My name is 1
 
// 修改一个对象的原型
const obj = {};
obj.__proto__.name = "dreamapple";
console.log(obj.name); // dreamapple

需要注意的是,尽管多数浏览器支持 __proto__,但它仅在 ECMAScript 2015 规范中才被正式标准化,旨在统一浏览器行为并确保兼容性。直接修改 __proto__ 性能较差,因此推荐获取原型时使用 Object.getPrototypeOf 或 Reflect.getPrototypeOf,设置原型时使用 Object.setPrototypeOf 或 Reflect.setPrototypeOf。

prototype 属性解析

prototype 属性解析

prototype 属性通常仅存在于函数对象中。任何可作为构造器(constructor)的函数都包含此属性,即只要函数能通过 new 操作符生成新对象,该函数必然拥有 prototype 属性。由于用户自定义函数均可通过 new 实例化,因此它们都具备 prototype 属性。

prototype 属性示例


// 函数字面量
console.log((function(){}).prototype); // {constructor: ƒ}
 
// Date构造器
console.log(Date.prototype); // {constructor: ƒ, toString: ƒ, toDateString: ƒ, toTimeString: ƒ, toISOString: ƒ, …}
 
// Math.abs 不是构造器,不能通过new操作符生成一个新的对象,所以不含有prototype属性
console.log(Math.abs.prototype); // undefined

prototype 与 __proto__ 的关系

prototype 的核心作用在于:通过 new 生成的新对象,其 __proto__ 属性将指向该构造函数的 prototype 属性。

原型链指向关系示例


// 其中F表示一个自定义的函数或者是含有prototype属性的内置函数
new F().__proto__ === F.prototype // true
 
// 通过函数字面量定义的函数的__proto__属性都指向Function.prototype
(function(){}).__proto__ === Function.prototype // true
 
// 通过对象字面量定义的对象的__proto__属性都是指向Object.prototype
({}).__proto__ === Object.prototype // true
 
// Object函数的原型的__proto__属性指向null
Object.prototype.__proto__ === null // true
 
// 因为Function本身也是一个函数,所以Function函数的__proto__属性指向它自身的prototype
Function.__proto__ === Function.prototype // true
 
// 因为Function的prototype是一个对象,所以Function.prototype的__proto__属性指向Object.prototype
Function.prototype.__proto__ === Object.prototype // true

constructor 属性解析

constructor 属性解析

constructor 属性标识对象的构造函数。除 null 和 undefined 外,JavaScript 所有数据类型均包含此属性,可通过代码验证其存在。

constructor 属性验证示例


null.constructor // Uncaught TypeError: Cannot read property 'constructor' of null ...
undefined.constructor // Uncaught TypeError: Cannot read property 'constructor' of undefined ...
 
(true).constructor // ƒ Boolean() { [native code] }
(1).constructor // ƒ Number() { [native code] }
"hello".constructor // ƒ String() { [native code] }

constructor 的归属与修正

严格来说,对象的 constructor 属性并非直接存在于对象本身,而是位于其原型链上(多级继承时需手动修正原型的 constructor 属性)。

构造函数与 constructor 的关系


const F = function() {};
// 当我们定义一个函数的时候,这个函数的prototype属性上面的constructor属性指向自己本身
F.prototype.constructor === F; // true

原始类型 constructor 的只读性

对于 JavaScript 的原始类型(string、number、boolean、null、undefined、symbol,其中 symbol 新增于 ECMAScript 2015),其 constructor 属性是只读的,不可直接修改。

原始类型 constructor 修改示例


(1).constructor = "something";
console.log((1).constructor); // 输出 ƒ Number() { [native code] }

手动修改原型 constructor

若确实需要修改原始类型的 constructor 属性,技术上可行,但通常不推荐此类操作。

手动修改 constructor 示例


Number.prototype.constructor = "number constructor";
(1).constructor = 1;
console.log((1).constructor); // 输出 number constructor

上述修改方式仅为技术演示,实际开发中不建议使用。

以上是对 JavaScript 原型和继承机制的详细介绍,希望能帮助读者深入理解。如有任何疑问,欢迎留言交流,小编将及时回复。感谢大家对本站的支持!

作者最新文章