一篇文章让你在面试中思维如游龙——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实例对象可以访问到Personprototype,就是因为p对象继承了Personprototype__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语言内核、编写高效和可维护代码的基础。

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

相关推荐
浮华似水11 分钟前
简洁之道 - React Hook Form
前端
正小安2 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
小飞猪Jay3 小时前
C++面试速通宝典——13
jvm·c++·面试
_.Switch4 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光4 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   4 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   4 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web4 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常4 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇5 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器