这篇文章主要是学习一下JavaScript中的难点------原型和原型链
咱们学习一门编程语言,必然要使用它完成一些特定的功能,而面向对象的语言由于符合人类的认知规律,在这方面作得很好,今天我以JS为例,探索一下JS不一样于其余面向对象的语言的地方-------原型和原型链
javascript
function Person(){ //构造函数 }
以上Person
就是一个构造函数,能够用来生成小明
小红
等等人类的实例。java
var person = new Person() //构造出一个对象 person.name = 'xiaoming' console.log(person.name) // 'xiaoming'
那原型在哪呢,认识原型先认识一下prototype
属性git
先看一段代码github
Person.prototype.name = 'god' var person2 = new Person() console.log(person2.name) //person2的名字是啥呢???
从上面三行代码,猜一猜person2的名字是啥,没错,就是god
面试
person2没有本身规定名字,可是Person构造函数的prototype上绑定了name,因此由Person构造函数构造的实例对象都默认有一个god
的名字。编程
以上就是构造函数和原型之间的关系,构造函数内部的prototype属性指向了实例对象原型的地址。数组
name
。上面红框是Person实例的原型,若是不直观的话,下面直接看Array实例的原型浏览器
红框的都是你们熟悉的数组的方法吧,他们都放在数组的共有属性里面。编程语言
上面的两幅原型图里面,咱们居然发现有共同点,都有一个熟悉 constructor
属性,待会研究一下这个属性。函数
如今,咱们已经知道了构造函数和原型的关系了,那person
person2
这些实例对象和原型有啥关系呢
__proto__
属性每个构造的实例对象,内部有一个__proto__
属性,它指向了实例原型,存的是原型的地址。
person.__proto__ === Person.prototype true
__proto__
是对象的属性,并且是浏览器强逼着ECMAScript
加上的这个规范。以上是构造函数、实例、实例原型之间的关系,不过方向是单向的,哪能不能让它循环起来呢,原型可不能够指向构造函数或者实例呢?
constructor嘛
构造函数、实例、实例原型之间的关系的方向能够循环的关键就在这里了。咱们一直叫构造函数,构造函数的,为何这么叫呢,对,就是这个原型里面的constructor
属性。
constructor
属性指向 构造函数Person === Person.prototype.constructor true
上面就是经典的铁三角了。
对象.__proto__ === 构造函数.prototype
而Person这个构造函数也是对象,那么
Person.__proto__ === ???
上面的问号填啥呢,咱们按公式填空,应该是构造函数.prototype
,Person构造函数的构造函数是谁呢?没错,就是Function
。
Person.__proto__ === Function.prototype true
在控制台验证确实如此。
因此有些之前的疑惑也解开了
Array.__proto__ === Function.prototype true String.__proto__ === Function.prototype true
构造函数.prototype
也是对象啊,它指向谁__proto__
属性Person.prototype.__proto__ === ???
问号填什么呢,原型是由谁构造的呢,咱们想到了全部对象的根----------Object
在控制台验证以下
Person.prototype.__proto__ === Object.prototype true Array.prototype.__proto__ === Object.prototype true String.prototype.__proto__ === Object.prototype true
既然引出了Object,咱们来看一下全部对象的祖宗的原型吧
Object.prototype.__proto__ === null true
前面咱们看到了Function构造方法构造除了全部的函数,包括普通的构造函数。
那么他自身也是一个函数,因此也是由Function构造函数构造的。因此由总结的公式能够知道
Function.__proto__ === Function.prototype
并且,下面这个很重要,易错
Function.prototype === Object.__proto__ //哈哈,这个老别扭了吧,还给你倒过来写,很容易错的
解释:Object也是构造函数啊,属于对象。Object构造函数也是由Function把它构造出来的,因此是结果是true
- 当你new一个构造函数的时候,建立一个函数实例,那么 『
函数实例.__proto__ === 该构造函数.prototype
』- 全部的函数都是由
Function
构造出来的,那么 『被构造出来的其余函数.__proto__ === Function.prototype
』- 全部的构造函数的原型对象都是由Object构造出来的,那么 『
全部的构造函数.prototype.__proto__ === Object.prototype
』
instanceof
运算符的实质首先这有几个题
Object instanceof Function Function instanceof Object Function instanceof Function Object instanceof Object
true
虽然 instanceof
运算符算是咱们的老朋友了,不过背后是咋判断的呢
规范是这么写的
object instanceof constructor参数
object
要检测的对象.
constructor
某个构造函数
instanceof
运算符用来检测constructor.prototype
是否存在于参数object
的原型链上
Object instanceof Function
,Object.__proto__ === Function.prototype
为true
,解决Function instanceof Object
, Function.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototype
为true
,解决。Function instanceof Function
,Function.__proto__ === Function.prototype
为true
,解决Object instanceof Object
, Object.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototype
为true
,解决只要上面的推导,任一环节你写错或者压根写不出来(在今天以前我也是瞎搞,运气好了蒙对了),说明你就不是真懂原型链,面试问到稍微变形的题仍是易错。
Function
Object
构造函数也是对象
原型对象等全部对象都由Object构造
这四个点。
Object
Function
你把它们当作构造函数或者对象,结果不一样的。不一样的场合,换不一样的角度去认识它们,事物具备两面性。大概就是背了多年的同一性,巴拉巴拉一堆的哲学原理吧。__prto__属性
有一条链子,找呀找呀,一直找到Object.prototype
为止感谢 冴羽大神和若愚大神的 文章。