JS面试题之详解prototype、__proto__、constructor

前言

关于原型链的问题一直都有,虽然每次需要用到的时候能快速回顾和掌握,但也难免会遗漏一两个重点,顾特写此博客,记录知识也分享知识!

相关知识点

知识点一:__proto__和constructor属性是对象所独有的,prototype属性是函数所独有的,但函数同时也是一种对象。
知识点二:通过构造函数创建的对象的原型指向构造函数的prototype属性。
知识点三:只有.prototype对象才实际拥有constructor属性,其他对象都是通过原型链,即__proto__属性间接获得(null也算一种数据类型,这里不算对象)
知识点四:new操作符调用构造函数时经历的过程

  • 1.创建一个对象
  • 2.将构造函数的作用域赋给新对象,此时this指向新对象
  • 3.执行构造函数中的代码,为新对象添加属性
  • 4.返回对象
    (知识点四此次说得不太完整,详细请点击阅读JS面试题之详解new操作符)
    知识点五:Object是最顶层对象,Object的原型对象Object.prototype为null
    知识点六:Function()是最顶层函数,Function()的constructor属性为Function()本身

以上知识点可能一开始看有点懵,但是不重要,接下来都会重点讲解,看到最后再回头来看这里,肯定会感觉豁然开朗。

开始讲解

相信很多人一直听到原型链,但是具体又说不清楚是什么,说不清楚__proto__和prototype之间的关系,其实所有的数据都放在prototype属性中,__proto__是用来连接prototype属性的,也就是所谓的链。
现在正式开始! 让我们从如下一个简单的例子展开讨论,并配以相关的图帮助理解:
我们先从最简单的例子开始讨论

function Foo() {...};
let f1 = new Foo();

虽然是简简单单的两行代码,它们背后的关系如下图所示:
在这里插入图片描述
说明:
图的最左边即为例子代码;
图的中间部分即为它们之间的联系;
右下角为图例,
红色箭头表示__proto__属性指向、
绿色箭头表示prototype属性的指向、
棕色实线箭头表示本身具有的constructor属性的指向,
棕色虚线箭头表示继承而来的constructor属性的指向;
蓝色方块表示对象,浅绿色方块表示函数(同时也是对象)。
你可能看不懂这张图,但是没关系,上面都是一些总结性的内容,以下开始分点讲解。

1.proto

下图为只有__proto__属性的关系图
在这里插入图片描述
回顾知识点二,五,六
第一,这里我们仅留下 proto 属性,它是对象所独有的,可以看到__proto__属性都是由一个对象指向一个对象,即指向它们的构造函数的prototype原型对象,__proto__属性的作用就是当访问一个对象的属性时,
理解方式一:如果该对象内部不存在这个属性,那么就会去它的__proto__属性所指向的那个对象(可以理解为父对象)里找,如果父对象也不存在这个属性,则继续往父对象的__proto__属性所指向的那个对象(可以理解为爷爷对象)里找,如果还没找到,则继续往上找…直到原型链顶端null(可以理解为原始人。。。),再往上找就相当于在null上取值,会报错(可以理解为,再往上就已经不是“人”的范畴了,找不到了,到此结束,null为原型链的终点),
理解方式二:可以从代理的方式理解,如果该对象内部不存在这个属性,那么就会去它的__proto__属性所指向的那个对象里找(可以理解为上级代理,相当于自己没货,去上级代理那里拿货),如果上级代理也不存在这个属性,则继续往上级代理的__proto__属性所指向的那个对象里找(可以理解为上上级代理,相当于上级代理也没货,它得去上上级代理那里拿货),如果还没找到,则继续往上找…直到原型链顶端null(可以理解为厂家,如果厂家都没货,那就为null,就会报错,到此结束,null为原型链的终点),
由以上这种通过__proto__属性来连接对象直到null的一条链即为我们所谓的原型链。(__proto__只起连接作用,数据都存在prototype属性里面)
  其实我们平时调用的字符串方法、数组方法、对象方法、函数方法等都是靠__proto__继承而来的。之后会专门一篇讲解slice-splice-split-join-substr-substring-slice方法的文章和一篇讲解bind-call-apply方法的文章。

2.prototype属性

接下来我们看 prototype 属性:
在这里插入图片描述
回顾知识点一,prototype属性,它是函数所独有的,它是从一个函数指向一个对象。它的含义是函数的原型对象,也就是这个函数(其实所有函数都可以作为构造函数)所创建的实例的原型对象,由此可知:f1.proto === Foo.prototype,它们两个完全一样。prototype属性的作用就是让该函数所实例化的对象们都可以找到公用的共享的属性和方法。任何函数在创建的时候,其实会默认同时创建该函数的prototype对象。

3.constructor属性

在这里插入图片描述
constructor属性也是对象才拥有的,它是从一个对象指向一个函数,含义就是指向该对象的构造函数,每个对象都有直接或者间接的构造函数(本身拥有或继承而来,继承而来的要结合__proto__属性查看会更清楚点,如下图所示),从上图中可以看出Function这个对象比较特殊,它的构造函数就是它自己(因为Function可以看成是一个函数,也可以是一个对象),所有函数和对象最终都是由Function构造函数得来,所以constructor属性的终点就是Function这个函数。
在这里插入图片描述

在这里插入图片描述

最后

希望这篇博客对大家能有所帮助,如果对你有所帮助,麻烦点赞支持一下,谢谢!
此文为参考 原文 而写,为感谢原文作者的付出,特出附上原文连接

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript 中,每个对象都有一个 __proto__ 属性,指向其构造函数的原型对象。而每个函数都有一个 prototype 属性,指向该函数实例化出来的对象的原型对象。 __proto__ 属性是一个指针,指向该对象的构造函数的原型对象。通过 __proto__ 属性可以访问原型对象中的属性和方法。这个属性在 ES6 中已经被标准化,可以用 Object.getPrototypeOf() 来获取对象的原型。 prototype 属性是函数的一个特殊属性,指向一个对象。当函数用作构造函数创建实例对象时,该对象的原型会指向构造函数的 prototype 属性指向的对象。也就是说,该对象可以访问构造函数原型对象中的属性和方法。 举个例子: ``` function Person(name) { this.name = name; } Person.prototype.sayHello = function() { console.log(`Hello, my name is ${this.name}`); } const p = new Person('Tom'); console.log(p.__proto__ === Person.prototype); // true console.log(Person.prototype.constructor === Person); // true console.log(p.constructor === Person); // true ``` 在这个例子中,我们定义了一个构造函数 `Person`,并给其原型对象添加了一个 `sayHello` 方法。我们通过 `new` 关键字实例化了一个 `Person` 对象 `p`。这个对象的 `__proto__` 属性指向了 `Person.prototype`,因此我们可以通过 `p.__proto__.sayHello()` 或者 `Person.prototype.sayHello.call(p)` 来调用 `sayHello` 方法。同时,我们也可以通过 `Person.prototype` 来访问 `Person` 构造函数原型对象中的属性和方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值