你真的明白javascript中的原型和原型链了吗

文章开头说的话

首先你必须明白(或者记住)的JavaScript常识:浏览器

  1. 在JavaScript中每一个函数都有一个prototype属性
  2. 在JavaScript中每一个对象都有一个__proto__属性
  3. 在JavaScript中函数是一等公民,即函数也是对象

prototype和__proto__

prototype究竟是个啥呢?下面看下这段代码,咱们慢慢来函数

// Animal是个构造函数,因此有prototype属性
function Animal(){}
// 在prototype上定义eat方法
Animal.prototype.eat = function(food){
  console.log("it is eating " + food);  
}
// 构造函数实例化a1
const a1 = new Animal();
// 构造函数实例化a2
const a2 = new Animal();
// 调用实例的方法
a1.eat("food");
a2.eat("food");

从上面的代码中,咱们能够看到:spa

  1. 函数的prototype指向一个对象
  2. 函数实例化后的对象能够获取prototype指向对象的方法(和属性)

那他们以前的关系是怎么样的呢?
图片描述prototype

从图中咱们能够看到:code

  1. Animal的prototype指向一个对象
  2. Animal的实例经过__proto__关联到Animal的prototype指向的对象

用官方术语说,就是:对象

  1. 函数的prototype所指向的对象就是该函数建立的实例的原型(即:a2和a2的原型是Animal.prototype)

那么问题来了,什么是原型呢?
在JavaScript中,每一个对象(null除外)在建立的时候都会与之关联另一个对象,对象和原型之间经过__proto__进行关联blog

原型的做用

在上面的代码中,咱们能够看到实例对象中并无eat方法,可是每一个实例对象均可以调用eat方法,那中间的过程是怎样的呢?图片

  1. 当咱们调用实例对象(a1和a2)的方法(eat)的时候,若是找到则直接调用实例对象的方法或者属性;若是找不到,就会查找与之关联的原型上是否有这个方法,若是这个原型没有,就会继续向上查找该原型的原型(原型的原型后面探讨)

原型的原型

在上面咱们提到了若是在原型上找不到相应的属性或者方法,就会在原型的原型上查找,那么什么是原型的原型呢?ip

  1. 首先在文章开头咱们说每一个对象都有原型,而原型也是对象,因此原型也是有原型的(听起来有点绕)
  2. 那以前代码的Animal.prototype的原型指向哪里呢(即Animal.prototype.__proto__)指向谁呢?这里Animal.prototype是JavaScript内置构造函数Object生成的呢,那是否是应该指向Object.prototype呢?答案是是的。
  3. 那Object.prototype也是对象,它的原型呢?Object.prototype.__proto__指向哪一个对象呢?答案是:null;即:
Object.prototype.__proto__ === null // true
// 表示若是查找属性的时候到Object.prototype时仍是没有就中止,没有了

最后画张图:
图片描述原型链

原型链

注意到上图中的蓝色线条部分了吗,这就是大名鼎鼎的原型链。

补充的知识

  1. constructor: 这个是原型中的自带属性,指向构造函数
  2. __proto__: 这个属性实际上是浏览器实现的,不是标准的访问原型的方式;ES5中规定的正式方法是:Object.getPrototypeOffang'fa
Object.getPrototypeOf(a1) === Animal.prototype // true

以上知识,最终的图以下:
图片描述

思考题:

  1. 在文章开头咱们说过函数也是对象,既然是对象就有原型,那Animal的原型指向谁呢?
  2. Function.prototype === Function.__proto__ 是true吗?
相关文章
相关标签/搜索