前言
在上篇文章中,我们讲解了一下原型链,并说明了原型和原型链之间的关系。接下来我们深入了解一下原型链,并一起来攻破一道网易的面试题。
我们先来回顾一下:
Ground.prototype.lastName = '贺' function Ground() { } var ground = new Ground() Father.prototype = ground function Father() { this.name = 'jingwei' } var father = new Father() Son.prototype = father function Son() { this.hobbit = 'reading' } var son = new Son() console.log(son.name); console.log(son.lastName);
这里会输出:
- 当访问对象属性时,先找对象显示具有的属性,没找到再去找对象的隐式原型
- 实例对象的隐式原型 === 构造函数的显示原型
- 顺着对象的隐式原型不断地向上查找上一级的隐式原型,直到找到目标或者一直到null,这种查找关系叫做原型链
接下来我们再来看一道例题:
Person.prototype = { name: '菌菌', sayName: function() { console.log(this.name); } } function Person() { this.name = '来颗奇趣蛋' } var p = new Person() p.sayName()
小伙伴思考一下会输出什么?
当我们访问p.sayName()时,先去实例对象p中找显示属性,显示属性并没有sayName,于是从p的隐式原型也就是Person的显示原型中查找,sayName: function() { console.log(this.name);
。然后输出this.name
,此时的关键就在于函数原型中的this
到底指向谁,是指向实例对象p还是指向函数原型呢?
我们来看看输出结果:
我们可以看到,最终输出结果为 来颗奇趣蛋
,所以这道题中的this
应该是指向实例对象p的,所以会输出p中的属性name
。
我们总结一下,函数原型中的this跟构造函数中的this一样,都指向构造函数构造出的实例对象
接下来给大家看一张很厉害很出名的图,它可以帮助我们更好地理解原型链:
这是一张原型链的图,我们先从左上角实例对象f1,f2开始看,f1的_proto_(隐式原型)也就是构造函数的显示原型Foo.prototype
,constructor
在我们原型的文章中有讲过,它是记录对象是由谁创建的,所以Foo.prototype
的创造者为function Foo()
.Foo.prototype
为一个对象,它是由构造函数Object()产生的,所以Foo.prototype
的_proto_为Object.prototype
,而我们上篇文章讲了,Object.prototype
的原型为null,同时也作为原型链的一个终止。
我们知道,函数也是一个对象,那么函数也有它的隐式原型。比如这里的function Object()
,图片上提示了它是由Function()
创造,那么它的_proto就是Function.prototype
。同理,Foo()
也是由Function()
创造,那么它的_proto_也是Function.prototype
.
这些都遵循着 对象的隐式原型 === 构造函数的显示原型规则,但是这张图有一个例外:
就是函数Function()
的隐式原型等于它自身的显示原型,也就是Function.prototype
.
如果小伙伴们看懂了这张图,那么对原型和原型链的理解已经很深了,以后看到原型和原型链那就是秒杀。
接下来我们来看面试题:
网易面试题
所有对象最终都会继承自Object.prototype?
通过对原型和原型链的学习,以及对刚刚讲解的那张图的理解,我们知道对象会顺着自己的隐式原型不断地向上查找,最终会继承到Object.prototype,那么所有的对象都会继承到吗?
Object.create()方法创造对象
let obj2 = Object.create(null)
我们用Object.create()的方法创造一个对象时,传入空null
,这样的话我们就创造出了一个空对象,我们在浏览器中输出一下obj2
Object.create(null) 创建的对象是一个空对象,在该对象上没有继承 Object.prototype 原型链上的属性或者方法
今天的内容就到这啦,如果你觉得小编写的还不错的话,或者对你有所启发,请给小编一个辛苦的赞吧