原型与原型链,你真的学废了吗?

649 阅读3分钟

「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战

前言

关于原型与原型链,可能准备过面试的同学都能够说出个一二,但有点时候还是模棱两可,总是喜欢用 可能, 大概, 也许 这样不确定的词,让面试官觉得你的基础不勾选扎实。

究其原因,还是因为没有真正对这块知识掌握的不够牢固,没有彻底搞明白prototype、 __proto__、 constructor三者之间的关系。笔者也存在这样的问题,所以想通过这样的方式来梳理一下三者的关系,这次彻底搞懂原型和原型链。

基础概念

ECMAscript将原型链作为实现继承的主要方法。基本原理是利用原型链实现一个对象继承另一个对象的属性和方法。 示例代码:

function FOO(){};
const f = new FOO();

【构造函数】用来初始化新对象的函数叫构造函数。 示例中的FOO()函数就是构造函数。

【实例对象】通过 new 关键字创建的对象叫实例对象。示例中的f。

【原型对象及prototype】构造函数有一个prototype属性,它指向实例对象的原型。常使用原型对象来实现继承。

【constructor】原型对象有constructor属性,指向原型对象的构造函数。

constructor.pngproto__proto__ 属性像是指针,指向构造函数的原型对象。

proto.png

其实我们这里只是讲了一个通过new关键字生成实例对象的特例。

具体__proto__的指向和生成实例的方式有关,下面就具体讲下。

不同浏览器对原型链的实现会有细微的差别。本篇文章均以chrome浏览器的实现为基础。

构造实例对象的方式决定 __proto__ 的指向

  1. 通过构造函数和new构建
function FOO(){};
const f = new FOO();

由构造函数创建的对象,其__proto__指向其构造函数的原型对象。

f.__proto__ === FOO.prototype
// true
  1. 对象字面量构造的对象
const person = {
    name: 'amingxiansen',
    sex: 'male'
};

__proto__指向Object.prototype。

等同于:

const person = new Object({
    name: 'amingxiansen',
    sex: 'male'
});

结果:

person.__proto__ === Object.prototype
// true

所以严格来讲,1 和 2 可以算作是同一种情况。

  1. 通过Object.create()创建
const person1 = {
    name: 'amingxiansen',
    sex: 'male'
}

const person2 = Object.create(person1);

这里person2的 __proto__ 指向person1。

person2.__proto__ === person1
// true

在没有Object.create函数的日子里,人们是这样做的:

Object.create = function(p) {
    function f(){}
    f.prototype = p;
    return new f();
}

这样就能保证新构建的对象的__proto__指向生成它的对象了。

图解

之前一直搞不清prototype__proto__的区别,其实可以简单理解为: 构造函数.prototype === 实例对象.__proto__,他们都指向同一个原型对象。

贴上一位掘友提供的图示

image.png

总结

  • 所有对象都有一个属性 __proto__ 指向一个对象,也就是原型
  • 每个对象的原型都可以通过 constructor 找到构造函数,构造函数也可以通过 prototype 找到原型
  • 对象之间通过 __proto__ 连接起来,这样称之为原型链。当前对象上不存在的属性可以通过原型链一层层往上查找,直到顶层 Object 对象,再往上就是 null 了

其实理解其原理之后也没有那么难!

下回不怕面试官再问原型和原型链了!

补充

__proto__

绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 Person.prototype 中,实际上,它是来自于 Object.prototype ,与其说是一个属性,不如说是一个 getter/setter,当使用 obj.__proto__ 时,可以理解成返回了 Object.getPrototypeOf(obj)。

写在最后

我是前端Surpeman,一个热爱分享的表单工程师。如果觉得本文还不错,记得三连+关注,说不定哪天就用得上!您的鼓励是我坚持下去的最大动力❤️。

参考资源:

  1. juejin.cn/post/693449…
  2. www.zhihu.com/question/34…