JS 原型和原型链详解

前言

原型和原型链是JavaScript语言重要的概念,理解了这个重要的概念,有助于我们更好地开发和阅读优秀框架源码。

原型

为什么需要原型呢?

我们先来看一个简单的例子:

js 复制代码
function Student(name, age){
  this.name = name
  this.age = age
  this.say = function() {
    console.log(`我是${this.name},今年${this.age}岁`)
  }
}
const stu1 = new Student('小明', 8)
const stu2 = new Student('小红', 9)
stu1.say()
stu2.say()

这种做法有一个严重的缺陷,就是每个学生对象中都拥有一个say方法,对于每个学生实例而言,say方法 是完全一样的,没必要为每个学生实例单独生成一个。所以需要原型。

原型、隐式原型 和实例

先来看看下面的关系图:

1. 原型

每个函数都会自动附带一个属性prototype,,这个属性的值是一个普通对象,称之为原型对象

2. 实例

通过new产生的对象称之为实例(instance)。

由于JS中所有对象都是通过new产生的,因此,严格来说,JS中所有对象都称之为实例

3. 隐式原型

每个实例都拥有一个特殊的属性__proto__,称之为隐式原型,它指向构造函数的原型。

所以,为什么使用原型?

当访问实例成员时,先找自身,如果不存在,会自动从隐式原型中寻找

这样一来,我们可以把那些公共成员,放到函数的原型中,即可被所有实例共享。

上面的例子我们就可以来这么改了:

js 复制代码
function Student(name, age){
  this.name = name
  this.age = age
}
Student.prototype.say = function() {
  console.log(`我是${this.name},今年${this.age}岁`)
}
const stu1 = new Student('小明', 8)
const stu2 = new Student('小红', 9)
stu1.say()
stu2.say()

原型链

首先,我们要了解两个基本原则

  1. 所有对象(null、undefined除外)都有隐式原型__proto__
  2. 只有函数才有原型对象prototype

我们以之前的代码为例,看看下面的最简单关系:

我们一步一步来拓展这个图,

  1. 首先,要知道所有的自定义函数(比如上面的Student函数)都是Function函数的实例:
  1. 一般情况下,对象都是通过new Object创建的。也就是说,一般对象的隐式原型都是Object原型。原型对象(比如上面的:Student函数原型)也是一般对象,不过虽然Object原型也是对象,但它的隐式原型就指向null。
  1. 针对第一点,实际上所有的函数(包括Object函数、Function函数)都是Function函数的实例:
  1. 针对第一点,Function函数原型也是对象,所以其隐式原型也指向了Object原型

到此,我们的原型链关系图就算完成了。

那么,有什么用呢?

当读取对象成员时,会先看对象自身是否有该成员,如果没有,就依次在其原型链上查找。

通过原型链,一个对象可以继承其原型对象上的属性和方法,甚至继承更远的上层原型。这使得对象可以共享和重用代码,实现了继承和代码的扩展。

原型链相关其他的方法

Object.getPrototypeOf()

__proto__是一个非标准的获取对象原型的方法,ES5新增了获取对象的原型对象方法:Object.getPrototypeOf(val)。

js 复制代码
function Foo() {}
const foo = new Foo()

console.log(Object.getPrototypeOf(foo) === foo.__proto__) // true
console.log(Object.getPrototypeOf(foo) === Foo.prototype) // true

Object.setPrototypeOf()

通过Object.setPrototypeOf(val, proto)设置对象的原型。

比如:

js 复制代码
const obj = {a: 1}
Object.setPrototypeOf(obj, null)

就可以设置一个对象为干净的对象。

当然,也可以使用const obj = object.create(null)来创建。

isPrototypeOf

isPrototypeOf方法 是 Object函数的下的一个方法,用于判断当前对象是否为另外一个对象的原型,如果是就返回 true,否则就返回 false。

js 复制代码
function Foo() {}
const foo = new Foo()
console.log(Foo.prototype.isPrototypeOf(foo)) // true
console.log(Object.prototype.isPrototypeOf(foo)) // true

const arr = []
console.log(Array.prototype.isPrototypeOf(arr)) // true
console.log(Object.prototype.isPrototypeOf(arr)) // true
相关推荐
结局无敌7 分钟前
React Native for OpenHarmony 实战:三方库 react-native-progress-steps 的鸿蒙化适配指南
javascript·人工智能·深度学习·react native·react.js·harmonyos
tryCbest14 分钟前
第三篇:JavaScript 基础语法全解 + TaskFlow 逻辑实现
javascript·前端知识
after you23 分钟前
【无标题】
前端·javascript
酷炫码神25 分钟前
Day 6|ES6+ 语法:把现代 JS 写顺手,从解构到 map / filter / reduce
前端·javascript·es6
晓得迷路了1 小时前
栗子前端技术周刊第 150 期 - Stack Overflow 开发者调查结果、TanStack Start 1.0...
javascript·css·后端
TYC91 小时前
Mac创建Vue3+TypeScript或者React+TypeScript项目
前端·javascript·typescript
持敬chijing11 小时前
白盒测试与代码审计-js登录逆向实战
javascript·网络·安全·web安全·网络安全·网络攻击模型
优选资源分享12 小时前
PicGo v3.0.3 新版 | 开源免费图床工具
javascript·笔记·electron
ShineWinsu13 小时前
对于JavaScript:JavaScript基础语法的解析
开发语言·前端·javascript·面试·web·基础语法·循环
普通人613 小时前
php+html+canvas实现树状打开的结构
开发语言·javascript·html5·1024程序员节