您当前的位置:首页 >> 奇闻
JavaScript ——原型与原型链之"葵花宝典"
发布时间:2019-09-07
 

JavaScript —— 极简主义


JavaScript ——原型与原型链之

点关注,不迷路~

紧接着开启上篇文章中提到的“原型与原型链”之旅,这也是面试尝尝被问到的问题,也是考察基础面老不牢固,理解深不深刻的问题。本文尽力用最简练的语言,最短的篇幅,实现最深刻的理解,努力做到“一针见血”。

JavaScript ——原型与原型链之

原型链关系图

首先,需要明确的一点是,JavaScript是基于“原型”继承的,而不是基于类继承的。文章路线:构造函数——>prototype——>__proto__——>constructor——>原型链。

1、构造函数

作用: 用来创建对象

function Person(name) {
this.name = name;
}
let person = new Person('Monica');
let name = person.name;
console.log(name);
结果: Monica

即: Person ——> person (创建关系)

2、构造函数的prototype属性

特点: prototype是函数所特有的属性,只有函数有该属性。

2.1) 构造函数与实例原型之间的关系

Person.prototype.skill = "eat";
let person1 = new Person('Monica');
let person2 = new Person('Liliy');
let skill1 = person1.skill;
let skill2 = person2.skill;
console.log(skill1, skill2);
继承结果: eat eat
JavaScript ——原型与原型链之

构造函数与实例原型的关系图

即: 构造函数的prototype属性指向实例的原型。

3、实例的 __proto__属性

3.1) 实例与实例原型之间的关系

即: person 与 Person.prototype 之间的关系。

person.__proto__ === Person.prototype
结果: true
JavaScript ——原型与原型链之

实例与实例原型的关系图

So, you will be find 实例对象和构造函数都可以指向原型,那么问题来了——实例原型是否有属性指向构造函数或者实例呢?

1) 实例原型是不可能指向实例的,因为原型只有一个,而实例是可以new出来多个,它指向哪一个是呢?它头脑肯定很混乱,选哪个都不是,谁都不得罪,那干脆哪个它都不选。

2) 实例原型是可以指向构造函数的,就是即将要讲的——实例原型的constructor属性。

4、实例原型的constructor属性

4.1) 实例原型与构造函数之间的关系

特点: construcotr,每个实例原型都有一个constructor属性指向构造函数。

Person === Person.prototype.constructor
结果: true
JavaScript ——原型与原型链之

实例原型与构造函数间的关系

5、原型链

上一篇文章已经介绍过沿原型链查找,为了文章的完整性,再次着重介绍一下。

当读取实例的属性时,如果未找到该属性,就会去实例原型中查找,如果还找不到,就去找原型的原型查找,一直找到最顶层为止。那么,原型的原型又是什么呢?as we all know,原型也是一个对象(prototype对象),既然是对象,我们就可以用new Object()的方式来创建它;你会发现,原型对象是通过Object构造函数生成的;那么,同理,它的__proto__指向构造函数Object的prototype。原型链关系图可以更新为:

JavaScript ——原型与原型链之

原型链关系图

那么,问题又来了,Object.prototype的原型又指向谁呢?答案是: null。而且null就是我们上文所说的顶层,查到这里就不会再继续查了,查到就返回对应的属性值,查不到就返回undefined。原型链关系图(蓝色的线)最终更新为:

JavaScript ——原型与原型链之

原型链关系图

扩展

person.constructor === person.__proto__.constructor === Person.prototype.constructor === Person
根据以上推导得出:
person.constructor === Person
获取对象原型的方法:
Object.getPrototypeof(person) === Person.prototype

总结: prototype是函数的属性,__proto__是对象的属性。

6、特殊——Function和Object的原型和原型链

从上文我们知道构造函数与实例原型的关系,如下:

JavaScript ——原型与原型链之

构造函数与实例原型的关系

所以可以推导出:

JavaScript ——原型与原型链之

推导图(一)

JavaScript ——原型与原型链之

推导图(二)

重点——理解并谨记三句“葵花宝典”:

第一句,Object为函数,所以是Function的实例;

JavaScript ——原型与原型链之

Function构造函数与Object间的关系

第二句,Function.prototype为对象,所以是Object实例;

JavaScript ——原型与原型链之

Object构造函数与Function间的关系

第三句,所有构造器都来自于Function.prototype,包括根构造器Object及Function自身;

JavaScript ——原型与原型链之

Function构造函数与自身间的关系

Tips:

1) 函数或构造函数都具有prototype属性,Function构造函数除外,Function没有prototype属性!!!

2) 所有函数对象的proto都指向Function.prototype, 包括根构造器自身;

函数.proto === Function.prototype
// 适用于声明式函数、函数表达式和内置函数,全部为 true
Person.__proto__ === Function.prototype
Number.__proto__ === Function.prototype
Number.constructor == Function
Boolean.__proto__ === Function.prototype
Boolean.constructor == Function
String.__proto__ === Function.prototype
String.constructor == Function
Object.__proto__ === Function.prototype
Object.constructor == Function
Function.__proto__ === Function.prototype
Function.constructor == Function
Array.__proto__ === Function.prototype
Array.constructor == Function
RegExp.__proto__ === Function.prototype
RegExp.constructor == Function
Error.__proto__ === Function.prototype
Error.constructor == Function
Date.__proto__ === Function.prototype
Date.constructor == Function

3) Math,JSON的proto是Object.prototype,因为它们是以对象形式存在的,不使用new。

Math.__proto__ === Object.prototype
Math.construrctor == Object
JSON.__proto__ === Object.prototype
JSON.construrctor == Object

总结:原型和原型链的内容较多,同时不是特别容易理解;不过,通过讲解相信前半部分的内容大家都可以轻松的理解吸收掉了;至于特殊那部分的内容,看第一遍可能有点懵逼,因为这里是需要大家能够沉下心来好好琢磨一下才能够理解的内容;加油,共勉之!!!

点关注,不迷路~