JavaScript 深入原型及原型链

lxf2023-05-04 00:55:45

老话说的好JavaScript中万物皆对象,那么每个对象都有原型,而js的诸多特性都是利用原型来实现的,原型、原型链也是面试当中最常问的知识点之一, 今天就让我们来深入探讨一下原型和原型链~

原型

首先我们来看什么是原型 我们首先看会下 MDN 我们的描述

JavaScript 深入原型及原型链

  • 这其中也写了原型链,备注当中写的对象关系,如果顺着这个关系捋,其实就是原型链,原型链我们一会再说

获取原型

  • 原型的操作无非两个部分,一个是获取,一个是设置首先我们来看如何获取一个对象的原型
  • 首先我们声明一个对象
const a = { res: 1 }
console.log('a', a)
# Object.getPrototypeOf(a) 这是对象提供的获取原型的方法, 这里打印的其实就是下面的 【prototype】

打印如下:

JavaScript 深入原型及原型链
这里我们看到一个属性[[ prototype ]], 这个就是我们所说的原型, 原型当中包含几个属性,这几个方法大家可以 自己到 MDN 上进行相关的了解, 这里我简单介绍一些,一个是 hasOwnProperty

  • hasOwnProperty

返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。 这个还涉及到继承, MDN 上的解释是这样的:

JavaScript 深入原型及原型链 JavaScript 深入原型及原型链

const arr = [1, 2, , 3]
arr.forEach((item) => {
  console.log('forEach', item)
})
for (let i = 0; i < arr.length; i++) {
  console.log('for循环', arr[i], arr.hasOwnProperty(i))
}

大家可以看一下这段代码, 这里涉及到数组空位, 这个我在前面的文章有过分享,想详细了解的可以去看一下, 那么对象属性也是同理的, 我们获取一个对象自身属性的时候,就需要用到这个属性, 去过滤掉原型上的属性。 JavaScript 深入原型及原型链

  • constructor

这个方法返回该属性的构造函数,我们这个是一个对象,所以会返回 Object, 这个还涉及到一个数据类型检测,在数据类型检测的时候,一个 instanceof

const a = { res: 1 }
console.log('a', a instanceof Object)
const arr = [1, 2, , 3]
console.log('arr', arr instanceof Object)
console.log('arr', arr instanceof Array)

上面这几个大家应该都知道结果了, 肯定是返回 true, 所以使用这个方法检测类型会有弊端,原因就是其是沿着原型链查找,数组的第一级原型是 Array, 再向上 就是 Objcet 了, 函数也是一样, 第一级是 Function ,再上一级是 Objcet , 一会大家可以看一下我的图形关系.

设置原型

原型的关系其实主要是从我们的类来扩展的,那么肯定就会涉及到继承, 这里只例举一种原型继承~

class Parent {
  constructor() {
    this.parent = 100
  }
}
class children extends Parent {
  constructor() {
    super()
    this.children = 1
  }
}

const rea = new children()
console.log('rea', rea)

打印如下:

JavaScript 深入原型及原型链
这里会修改子类的原型,子类原型实际上就是父类的实例,继承这一块我之前也有文章有说,大家可以自行去了解~

  • 那么另外一种设置原型的方法,就是 ObjectsetPrototypeOf 了,我们先来看一下 MND 给出的解释:

JavaScript 深入原型及原型链 下面是用过 这个方法实现的一种伪继承, 这种继承方式首先使用了 call 然后修改了原型, MDN 也给出了所有关于继承的 demo 包括一些性能问题也都指出~

function Human(name, level) {
  this.name = name;
  this.level = level;
}

function SuperHero(name, level) {
  Human.call(this, name, level);
}

Object.setPrototypeOf(SuperHero.prototype, Human.prototype);

// Set the `[[Prototype]]` of `SuperHero.prototype`
// to `Human.prototype`
// To set the prototypal inheritance chain

Human.prototype.speak = function () {
  return `${this.name} says hello.`;
}

SuperHero.prototype.fly = function () {
  return `${this.name} is flying.`;
}

const superMan = new SuperHero('Clark Kent', 1);
console.log(superMan.fly()) // Clark Kent is flying.
console.log(superMan.speak()) // Clark Kent says hello.

原型链

原型的查找关系组成了原型链,原型链上有原型,这两个是一种包含关系。 我们来看一下 其官方概念:

JavaScript 深入原型及原型链 这里我们看到, 其实核心就是 protoprototype 的关系~ 也可以称之为 从任何一个数据类型出发,使用__proto__串联起来的对象链状结构
这里我们需要先了解对象访问机制:

  • 当访问一个对象成员的时候,访问顺序:

    自身查找,如果有直接使用 没有 -----> 到__proto__上查找,有直接使用,没有 -----> 就按照原型链结构继续去__proto__上查找 ...... -----> 最终一定能找到顶级原型(Object.prototype),有就使用,没有返回undefined

JavaScript 深入原型及原型链 其最关键的关系,我已经总结成上面这张图形的这个样子, 大家可以观察一下, 从中间的 自定义构造函数A 出发, 另外下面还有一个子类,这个子类B 继承自中间的 A ,他们的 主要由三者构成, 1、实例对象 2、 构造函数 3、原型对象, 这三者之间相互关系由线条构成, 最终都走向 null 也就是 Object 原型对象之后的下一个指针。 这个图有什么不明白的地方,欢迎留言一起探讨~

本网站是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 本网站还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 除此之外,本网站还拥有一个活跃的社区,您可以在社区中与其他前端开发者交流技术、分享经验、解决问题。我们相信,社区的力量可以帮助您更好地成长和进步。 在本网站中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!