JS 原型和原型链

原型指针__proto__

一上来先看两行代码

var obj = {}
obj.toString()

第一行代码很简单,JavaScript 会在堆内存中创建一个空对象,把空对象在内存空间中的地址赋值给 obj 这个变量。

我们现在要分析这里的第二行代码,声明的空对象 obj,它调用的方法 toString 是从哪里来的呢?

JavaScript 先在 obj 内部寻找是否有一个叫 toString 的方法,显然并没有找到。然后会去它的 __proto__ 这个属性指向的对象中再去找。 我们可以在浏览器的控制台将 obj.__proto__ 这个属性指向的对象输出到屏幕上来观察一下:

obj.__proto__ 中就能找到 toString 这个方法。再画个简图。来分析一个这他们在内存中的关系

在 JavaScript 中每个对象都拥有一个原型对象,而指向该原型对象的内部指针则是__proto__。通过它,对象可以从中继承原型对象的属性。

原型对象 prototype

在上面的代码中var obj = {},这是一个字面量的写法。它是等价于下面这种写法的

var obj = new Object()

这里是用 Object 这个构造函数来创建一个实例对象,我们看看这行代码的输出结果是 true

Object.prototype === obj.__proto__ // true

再来画图分析 CE541897-AF16-4BE4-90EC-19FB893D8DD4

函数的 prototype 这个属性,它指向一块内存,这个内存里面有共用属性 __proto__指向同一块内存。prototype__proto__的不同点在于:prototype 是构造函数的属性,而 __proto__ 是对象的属性

结合上面的知识,再来看原型链 🔗

原型链作为 JS 实现继承的主要方法,其基本思想是利用原型让一个引用类型继承另一个引用类型中的属性和方法。 每个构造函数都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针(constructor),而构造函数创建的实例都包含一个指向原型对象的内部指针(__proto__)。

理清「原型链」和「作用域链」这两个概念

  • 作用域链的作用主要用于查找标识符,当作用域需要查询变量的时候会沿着作用域链依次查找,如果找到标识符就会停止搜索,否则将会沿着作用域链依次向后查找,直到作用域链的结尾。
  • 而原型链是用于查找引用类型的属性,查找属性会沿着原型链依次进行,如果找到该属性会停止搜索并做相应的操作,否则将会沿着原型链依次查找直到结尾。    

参考链接