js必会知识点一,带你彻底认识原型和原型链,网易面试这样问?

前言

对前端开发工程师来说,熟悉掌握JS这门语言是必须的,其中,有两个必须要会的知识点就是原型和原型链。我们都知道,在JS语言中可以通过使用对象来模拟类,创建实例并使用继承等面向对象的概念。可是,JS又并不是一门完全面向对象编程的语言,所以它是如何实现继承机制的呢?这就是我接下来要和大家说的内容啦,下面我们一起来了解一下,相信看完之后你可以对他们有更加深入的了解。

构造函数

在这之前,我们先来聊一聊构造函数,看一段代码:

js 复制代码
//构造函数
function Car(owner,color){
    this.name = 'BMW'
    this.lang = 4900
    this.height = 1400
    this.owner = owner
    this.color = color
}
//创建实例对象
var car = new Car('BMW','red')
var car2 = new Car('宝马','black')
console.log(car);
console.log(car2);

如上述代码结果所示,JS通过构造函数创建了两个实例对象,但是其中有一个问题,就是这两个实例对象是不是存在一些相同的属性,那要是创建多个实例,岂不是每个实例都会执行一遍相同的代码,影响代码效率,所以为了解决这个问题,于是JS就设计出了原型,用来存储构造函数公共的属性和方法。同时,回到上面的问题,JS是如何实现继承机制的呢?可以通过原型来实现的。

原型

定义:原型(prototype)是函数天生就具有的属性,它定义了构造函数制造出的对象的公共祖先。我来解释一下这段话,就是JS的每个函数在创建的时候,都会天生自带一个prototype属性,指向该函数的原型对象。如下图所示:

Car.prototype 打印出来的那个对象就是原型对象,它是Car构造函数制造出的对象的公共祖先,其中里面默认会有一个constructor属性,指向的就是该函数,这恰恰让函数和它的原型对象之间联系起来了。如下图:

这里有个要注意的地方了,原型属性是只有函数才有的,我们可以来测试一下。

可以看到,非函数并没有prototype 这个属性,打印的都是undefined ,只有函数才有原型(prototype)属性。

那接下来我们再来看一段代码:

js 复制代码
//所有实例共享的公共属性和方法
Car.prototype.name = 'BMW'
Car.prototype.lang = 4900
Car.prototype.height = 1400
Car.prototype.sing = function(){
    console.log(this.owner + '是帅哥');
}

//构造函数
function Car(owner,color){
    this.owner = owner
    this.color = color
}

//创建实例对象
var car = new Car('小米','red')
var car2 = new Car('小露','black')

console.log(car.name) //打印BMW
car.sing() //打印小米是帅哥

看到打印结果或许有人就有疑惑了,为什么我们构造出来的car实例对象,它可以调用到Car构造方法上原型对象的属性和方法呢?难道不是只有通过构造函数里面的this赋值得到的属性和方法才会被创建的实例继承吗?为什么在Car构造函数定义的sing方法也可以被car实例所调用执行呢?是不是实例对象继承到了它的构造函数上原型对象的属性和方法?这里就需要引出下一个重要的概念了------原型链。

原型链

我们在上文说到,每个函数在创建的时候,会天生自带一个prototype 属性,而实例对象没有这个属性,但是每个通过构造函数 创建出来的对象,会天生自带一个__proto__属性,而它会指向该实例对象的构造函数的原型对象。这么说可能感觉会有点晕,说白了就是实例对象的__proto__属性会指向它的构造函数原型。 我们可以用代码测试一下:

可以看到打印结果为true,是不是就说明了对象会有个__proto__属性并且指向它的构造函数原型。而上文提到的构造函数原型是不是默认存在一个constructor属性指向的是该构造函数。那我们来捋一捋这两句话,是不是就说明了实例对象有一个__proto__属性,然后__proto__属性里面还有一个constructor 属性,constructor属性指向实例对象的构造函数。是不是有点绕,我们直接代码打印一下结果

我们是不是可以看到实例p对象里面的__proto__属性有一个constructor 属性,指向了p的构造函数Car()。所以就说明了实例对象会隐式继承到它的构造函数的原型对象上的属性和方法。

你以为到这就完了吗?其实还不够,看到这里,有聪明的小伙伴或许就发现了,那Car.prototype不也是一个对象吗,那它是不是也会有一个__proto__属性呢?

对的,可以想到这里小伙伴真是太棒啦!给你点赞鼓掌 👍。

我们可以这样想,Car.prototype 是一个对象,如果它也是被某一个构造函数实例化创建出来的,那它是不是肯定也会有一个__proto__属性,并且指向它的构造函数的原型。那我怎么知道这个构造函数的原型有没有或者是谁呢,别忘了,我们上面一个代码测试,我们是不是通过可以打印Car.prototype__proto__属性看它的constructor 属性指向谁吖,它指向的是谁就说明谁是Car.prototype的构造函数。

这时我们便可以发现,答案居然是Object! 这时候小伙伴又要问了那Object.prototype 也是一个对象,那它是不是也会有一个__proto__属性,指向一个构造函数原型呢?我们可以来测试一下:

喔哦!我们发现Object.prototype 是有__proto__属性的,但是结果为null,这就说明我们已经找到顶端了。那这个时候我们从头理一下思路,实例对象的__proto__属性指向它的构造函数的原型,而它的构造函数的原型也是一个对象,那它必然也会有一个___proto__属性会指向它的构造函数的原型,这之间不断向上连接,一直到原型对象顶端指向null为止,我们称这种连接关系为原型链。

实例对象不仅会隐式继承到它的构造函数的原型对象,还会继承到它的构造函数的原型对象的构造函数的原型对象里面的属性和方法,一直继承到Object的原型对象中的属性和方法。那我们开始的那个问题现在通过原型链的知识是不是就可以解决啦,相信聪明的你已经学会啦!

补充

刚说了对象存在原型链,那函数也作为一个对象,是否也存在原型链呢?我们试着可以打印它的___proto__属性一探究竟。

我们可以看到函数的___proto__属性有个constructor 指向Function ,说明函数都是由构造函数Funtion()创建的,然后Funtion 函数的原型也是一个对象,其___proto__属性最终也指向Object 的原型,所以这也说明了原型链的尽头也是null

这时候我就要给你们看一张图片了,相信当你们看完我的文章,就可以彻底搞明白这张图了。如果还不明白,欢迎评论!

重点

最后来一道网易面试题

js 复制代码
所有的对象最终都会继承至 Object.prototype?

我们一步一步来分析一下这个问题,首先对象是不是天生自带一个__proto__属性,指向它的构造函数的原型,然后它的构造函数的原型也是一个对象,也有__proto__属性,然后又指向它的构造函数的原型,那最终是不是一定会指向Object的原型**(Object.prototype)**。不出意外的话,我们这么分析好像确实没有一点毛病吼!但是,它还真出了一点意外,确实有一个特例。请看图:

啊?小伙伴们是不是都惊呆了,使用Object.create()创建对象,当我们传入null当做它的参数,它会创建一个干净的空对象,所以它创建的对象不会有原型,也不会有Object 原型对象的任何属性。所以,细心的小伙伴可以发现我上面说了一句话每个通过构造函数创建出来的对象,会天生自带一个__proto__属性,我特意把构造函数加重标记了,还是给自己留了一条后路的,哈哈哈!总结:这题太坑啦!!!大家现在搞明白了嘛,如果小伙伴觉得我的文章写的不错的话,烦请给我一键三连喔~😍该文章仅个人观点,如有不对的看法还请大家指出喔,本人萌新还在加油ing!

相关推荐
吞掉星星的鲸鱼30 分钟前
使用高德api实现天气查询
前端·javascript·css
....49234 分钟前
Vue3 + Element Plus + AntV X6 实现拖拽树组件
javascript·vue.js·elementui·antvx6
花花鱼3 小时前
node-modules-inspector 可视化node_modules
前端·javascript·vue.js
TDengine (老段)4 小时前
TDengine 中的关联查询
大数据·javascript·网络·物联网·时序数据库·tdengine·iotdb
再学一点就睡6 小时前
大文件上传之切片上传以及开发全流程之前端篇
前端·javascript
難釋懷8 小时前
JavaScript基础-移动端常见特效
开发语言·前端·javascript
还是鼠鼠8 小时前
Node.js全局生效的中间件
javascript·vscode·中间件·node.js·json·express
自动花钱机8 小时前
WebUI问题总结
前端·javascript·bootstrap·css3·html5
bst@微胖子8 小时前
Flutter项目之登录注册功能实现
开发语言·javascript·flutter
拉不动的猪9 小时前
简单回顾下pc端与mobile端的适配问题
前端·javascript·面试