前端 圆形进度图_前端面试题——原型与原型链

前端面试,总是会被问到这样一类问题:

  • 来来来,可以解释下什么是JS中的原型和原型链么?

90bd9ae00a2563af84c969f67be1215d.png

最近,知乎上一个问题总是出现在我的时间线上:面试一个5年的前端,却连原型链也搞不清楚,满口都是Vue,React之类的实现,这样的人该用吗?

虽说,我们不能只凭借一道题,就给面试者盖棺定论。回答者都说的好有道理,道理我们都懂,但是到底什么是原型和原型链呢?

首先,JS是真正的“面向对象”的语言,而其他我们所熟知的例如C++、Java等,严格意义上说,是“面向类”的语言,仔细想想,还真是那么回事儿。其次,JS中,调用构造器之后,对象并不是它原型的一份拷贝,而是被链接到原型上。

Object

我们先看一段代码:

function Person(name){     // 1
    this.name = name;
}

Person.prototype.sayName = function(welcome) {     // 5
	console.log(welcome, this.name);
}

var person1 = new Person('Smiley');     // 9
person1.sayName('Hello');         // 10

在执行这段代码之前,有个东西是一直存在的,就是有些人所说的“原型的原型”。如下图所示,我们用圆形代表function,用方形代表object:

57950dd136c24c60aa8865886ec231fa.png

左边的圆形是Object构造函数,就是我们一般使用var obj = new Object()时最普普通通的的构造函数。右边的方形是Object的prototype,这个东西没有名字(虽然它很重要)。左边有一个箭头指向右边,意味着Object有一个属性叫做prototype,这个属性指向的是右边的那个方块,而向左指的箭头,意味着右边方块的constructor属性是左边的Object构造函数。

这些东西在上面程序运行之前就一直存在的。

构造函数

好的,我们开始看第一行代码,运行第一行代码之后,会生成一个叫Person的构造函数,而这个构造函数的prototype属性,指向的就是它的prototype,如下图方块所示:

233e4441ea6f0435ab7505d0a9b1268f.png

Person与Person.prototype之间的关系,与Object和Object.prototype类似,不同的是,Person.prototype会通过__proto__指向Object.prototype。

接下来看第5行代码:我们在Person.prototype上面添加一个sayName方法,如上图所示,Person.prototype这个方块中有sayName方法。

new调用构造器

最后来看第9行代码,这行代码中,我们new了一个Person的实例,还记得我在《前端面试题——自己实现new》当中提到,使用new这个关键字的时候,JS编译器会做四件事情:

  1. 创建一个新的空的对象
  2. 把这个对象链接到原型对象上,将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
  3. 执行构造函数中的代码(为这个新对象添加属性)
  4. 如果这个函数有返回值,则返回;否则,就会默认返回新对象

3ff67b2fc1e2036f27cd011f3643cb59.png

如下图所示,我们先创建一个person1的空对象,然后把person1通过__proto__指向原型对象,指向构造函数中的代码,person1就获得了一个叫做name的属性,最后返回。

我们最后运行第10行代码:person1.sayName('Hello');

person1上有sayName这个方法么?没有,那么就顺着person1的__proto__向上找,找到Person.prototype。Person.prototype上面有sayName方法么?有的,那么执行这个方法。这个方法内部使用了this.name,那么这个this的指向是什么么?我们需要看sayName的call site,是person1调用的sayName,隐式调用,this就指向person1,而person1的name就是Smiley。

是不是觉得很神奇,最后调用时候使用的属性和方法都是我们希望使用的那个,person1.sayName('Hello')看似很容易理解,JS初学者都能很容易说出最后输出结果,但是这其中的过程,恐怕只有理解了原型和原型链才能真正说明白。

明白了这些之后,我们看几个相等关系:

console.log(Person === Person.prototype.constructor);
console.log(person1.__proto__ === Person.prototype);

我们再也不用死记硬背这个关系了,而是通过上面的图直接可以推到出来。

最后问大家一个问题:console.log(person1.constructor)是什么的呢?怎么找到的呢?

好啦,这就是关于原型和原型链的一些知识 。希望看完这篇文章之后,再也不会为原型和原型链感到头疼,祝大家前端学习一切顺利。

关注我的公众号:前端三剑客

3b6d9ad2eaa60342dce83897e3d60b85.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值