一篇文章让你在面试中思维如游龙——JavaScript原型和原型链的介绍

前言

在JavaScript中,原型(Prototype)机制是一种核心特性,它支撑着面向对象编程的基本概念,如继承和对象属性的查找规则。理解原型、原型链以及隐式原型(__proto__)的概念对于深入掌握JavaScript的运行机制至关重要。

正文

下面,我将一步步的让你明白JavaScript中原型和原型链,不学会不要钱!

1. 原型(Prototype)

每个JavaScript函数都有一个特殊的属性叫做prototype。

这个属性是一个对象,用于存储所有通过该函数作为构造函数创建的实例所共享的属性和方法。\

这样说的有点笼统,我们来看一下这个例子

js 复制代码
Person.prototype.like='听歌'

function Person() {
    this.name = '田总'
}
let p = new Person()

console.log(p.like)

我们现在往Person构造函数的原型上添加了like属性为听歌,我们发现其对象能够输出为

我们再试验一下,给Person对象p的like属性删除了,看看结果

js 复制代码
Person.prototype.like='听歌'

function Person() {
    this.name = '田总'
}
let p = new Person()
delete p.like
console.log(p.like)

依旧能够输出"听歌"

并且在我们修改p.like='撸铁'时,输出变为了

简而言之,原型对象定义了一个特定类型的所有实例应该具有的属性和行为。

例如,当我们使用new关键字基于某个构造函数创建新对象时,这个新对象会自动链接到构造函数的prototype上,从而能够访问到原型上的属性和方法。

划重点!函数的原型(Prototype)我们称为显式原型!

为什么是显式原型,那是不是还有别的原型?

隐式原型

每个对象都有一个内部属性__proto__,它指向该对象的原型。我们称为隐式原型

举个例子:我们写一个构造函数

js 复制代码
function Son() {
    this.name = 'Tom'
}

然后new一个新的对象:

js 复制代码
let son = new Son()

那么在new这个对象的过程中,v8引擎会进行这么几项事情:

js 复制代码
 var this = {
            name:'Tom'
        }
        this.__proto__ = Person.prototype
        return this

生成一个新对象,然后把构造函数中的属性传给新对象,然后将构造函数的显式原型传给对象的隐式原型。最后返回这个对象给实例对象。

也就是说,实例对象的隐式原型其实就是其构造函数的显式原型

当一个实例对象尝试访问一个属性或方法时,如果该属性或方法不在实例本身上定义,JavaScript引擎会继续在其关联的原型对象上查找。这意味着,通过构造函数创建的所有对象都可以"继承"原型上的属性和方法。需要注意的是,实例对原型的这种访问是隐式的,并且原型属性是只读的,意味着实例不能直接修改原型上的属性,但可以通过覆盖实例自身的同名属性来达到类似效果。

这就是为什么在上面我们的p实例对象可以访问到Person的prototype,就是因为p对象继承了Person的prototype为__proto__

了解了显式原型和隐式原型,我们来了解一下原型链

原型链的概念源于JavaScript引擎在查找对象属性时的机制。如果在当前对象上找不到某个属性,引擎会继续在其__proto__属性所指向的对象(即其原型对象)上查找,这个过程会递归进行,直到找到该属性或者遇到null(标志着原型链的终点)。这种链式的查找方式确保了对象可以从其祖先那里继承属性和方法,构成了JavaScript中继承的核心逻辑。

我们在创造实例对象时,它具有一个隐式原型__proto__它继承于其构造函数的显示原型prototype。

那么在JavaScript中,万物皆为对象 ,所以其构造函数,也是一个对象,对象就有其隐式原型,指向其构造函数的构造函数的显式原型,原型也是对象,它也有隐式原型

是不是有点懵了

来看一下这一段代码

js 复制代码
 Grand.prototype.lastName = '张'

    function Grand(){
        this.name = '三'
    }
    Father.prototype = new Grand()
    function Father() {
        this.age = 40
    }
    Son.prototype = new Father()
    function Son() {
        this.like='coding'
    }
    let son = new Son()
    console.log(son.lastName)

最后输出的是什么?

这个就是它的原型链,一层一层归属于上一级,最后搜索到底层Grand.prototype找到lastName输出

Grand的显式原型prototype就是最底层吗,并不是,prototype是一个对象,那么它就有自己的__proto__它指向创建其对象的Object.prototype,而Object.prototype也是一个对象,它也有隐式原型,Object也是由一个function创造出来的......

开始套娃

而Grand函数也是一个对象,它也有其隐式原型,指向函数的显示原型Function.prototype

回到一开始继续套娃

最后,这么一张图诞生了

超级无敌套娃图

它会一直套娃下去吗,其实并不会,到了Object.prototype的__proto__其实就会指向null了

原型链的魅力,你现在了解了吗

所有对象都有原型吗?

我们一直都说,JavaScript万物皆为对象,那么是不是所有对象都有原型呢?

不是

并非所有JavaScript对象都有原型。通过Object.create(null)创建的对象是一个特例,它没有原型链------它的__proto__为null。这意味着该对象不继承自Object.prototype,也不具备任何默认的原型属性和方法,如toString()或hasOwnProperty()。这样的对象常用于需要纯净、无污染对象的场景,比如构建某些特定的数据结构或实现特定的安全需求。

总结

JavaScript的原型机制提供了一种灵活而强大的方式来实现对象间的继承和属性共享。理解原型、原型链以及隐式原型的概念,是深入JavaScript语言内核、编写高效和可维护代码的基础。

求点赞评论收藏,有问题随时私信博主!

相关推荐
其实防守也摸鱼1 小时前
个人学习 Pwn 思路:从基础到漏洞利用的进阶路径
大数据·前端·人工智能·chrome·算法·安全·网络安全
朱涛的自习室2 小时前
212 个需求、22 万行代码:Agent 接管开源项目的 19 天
android·前端·人工智能
aZhe的全栈知识分享2 小时前
AI 还原 Figma 效果总达不到预期?先别急着让它写代码
前端·后端·面试
review445432 小时前
Codex Hooks 入门实战:生命周期事件、matcher 与5分钟跑通一个钩子
前端·agent·vibecoding
函数小陈2 小时前
阿里云部署DSH与RAM完成运维
前端·后端
用户499335025072 小时前
JS 作用域劫持的死穴:动态 this 穿透,以及 AST 怎么救
前端
IT_陈寒3 小时前
React的setState真是个演员,你以为它同步其实在装睡
前端·人工智能·后端
Fuyo_11194 小时前
C++ 运行时多态与虚函数机制全面剖析【面试重点】
开发语言·c++·面试
孟健4 小时前
Claude Code 同需求写两版对比:装不装 frontend-design 差多远?
前端·ai编程·claude
IT规划师5 小时前
一文讲透五种发布机制:滚动、蓝绿、金丝雀、红黑与 AB
后端·面试