深入理解JavaScript原型与原型链

深入理解JavaScript原型与原型链

在JavaScript中,原型(prototype)是一个核心概念,它不仅关乎对象的创建方式,还深刻影响着对象间的继承机制。本文将深入探讨原型的内涵、原型链的工作原理,以及为什么并非所有对象都拥有原型。

原型基础

每个JavaScript函数都自动配备了一个名为prototype的属性,这个属性是一个对象,用来定义当通过该函数作为构造函数创建新对象时,这些新对象(即实例)所共享的属性和方法。简而言之,原型就是构造函数创造实例的蓝图或原型模板。例如:

js 复制代码
function Person(name) {
    this.name = name;
}

Person.prototype.sayHello = function() {
    console.log("Hello, my name is " + this.name);
};

在这个例子中,Person.prototype.sayHello定义了一个所有Person实例都可以访问的方法。

实例对象与原型的关系

当我们使用构造函数创建一个新对象时,这个新对象会自动链接到构造函数的原型对象上。这种链接是通过每个实例对象内部的特殊属性[[Prototype]](通常可访问的形式为__proto__,尽管不推荐直接使用)实现的。这意味着,实例对象可以访问其构造函数原型上的所有属性和方法,这一过程是隐式的,并且对于开发者来说是只读的。

js 复制代码
Person.prototype.like = '听歌'
function Person() {
    this.name = '田总'
}
let p = new Person()
p.like = '撸铁'

console.log(p.like); // 输出 撸铁

创建了Person的一个实例p,并为其显式地设置了一个同名属性like,值为'撸铁'。由于实例属性优先级高于原型属性,当访问p.like时,它会返回实例自身的like属性值,即'撸铁'

Constructor属性

每个实例对象都有一个constructor属性,它指向创建该实例的构造函数,这对于理解对象的来源非常有用。

js 复制代码
function Car() {
    this.name = 'su7'
}
let car = new Car()
console.log(car.Constructor);// 输出: [Function: Car]

// 实例对象通过constructor来记录我是由谁创建的

在JavaScript中,每个由构造函数创建的对象都会自动获得一个constructor属性,该属性指向创建该对象的构造函数。因此,当你打印car.constructor时,它会显示出Car构造函数本身,这表明car对象是由Car构造函数创建的。

原型链的奥秘

原型链 是JavaScript实现继承的主要机制。当访问一个对象的属性或方法时,如果该对象本身没有定义该属性或方法,JavaScript引擎会继续在其[[Prototype]]指向的对象中寻找,这个过程会一直向上追溯,直到找到该属性或方法,或者到达原型链的末端(null)。这个链式查找的过程确保了对象可以从其祖先那里继承属性和方法。

并非所有对象都有原型?

通常情况下,JavaScript中的每个对象都会有一个原型链,因为就连Object.prototype自身(所有对象原型的最终源头)也有一个null作为其原型,形成了原型链的终点。然而,有一种特殊情况:通过Object.create(null)创建的对象没有原型。这意味着该对象既没有继承自Object.prototype的默认方法(如toString()),也无法通过原型链查找机制获取任何属性或方法。这种对象常用于需要一个"纯净"对象,避免污染全局原型链的场景。

js 复制代码
let a = {
    num: 1
}

let b = Object.create(null);

这段代码在v8引擎中运行,对象a有原型,对象b由于通过Object.create(null)创建,所以该对象没有原型。

结论

原型和原型链是JavaScript实现面向对象编程和继承的核心机制。它们提供了一种灵活且高效的方式来管理对象的属性与方法,同时也允许我们通过构造函数和原型链来模拟经典的类继承模式。理解原型链的运作原理,特别是认识到并非所有对象都默认拥有原型这一特例,对于深入掌握JavaScript语言的精髓至关重要。在实际开发中,合理运用原型链,可以编写出结构清晰、易于维护的代码。

相关推荐
开心就好20252 分钟前
UniApp开发应用多平台上架全流程:H5小程序iOS和Android
后端·ios
悟空码字15 分钟前
告别“屎山代码”:AI 代码整洁器让老项目重获新生
后端·aigc·ai编程
小码哥_常25 分钟前
大厂不宠@Transactional,背后藏着啥秘密?
后端
奋斗小强25 分钟前
内存危机突围战:从原理辨析到线上实战,彻底搞懂 OOM 与内存泄漏
后端
over6971 小时前
从 LLM 到全栈 Agent:MCP 协议 × RAG 技术如何重构 AI 的“做事能力”
面试·llm·mcp
小码哥_常1 小时前
Spring Boot接口防抖秘籍:告别“手抖”,守护数据一致性
后端
进击的尘埃1 小时前
Vue3 响应式原理:从 Proxy 到依赖收集,手撸一个迷你 reactivity
javascript
心之语歌1 小时前
基于注解+拦截器的API动态路由实现方案
java·后端
None3211 小时前
【NestJs】基于Redlock装饰器分布式锁设计与实现
后端·node.js
willow1 小时前
JavaScript数据类型整理1
javascript