原型
对于一个JavaScript对象来说,什么是原型。一个非常直接的理解,对象的__proto__属性所指向的即为该对象的原型。有如下代码,灰色框中的部分即为对象person的原型。

而除了通过__proto__获得对象的原型之外,在ES6之后,对象的原型还可以通过Object.getPrototypeOf()获得,该方法要传入的参数为要返回其原型的对象。
let a = {}
Object.getPrototypeOf(a)

a.__proto__ === Object.getPrototypeOf(a)这一结论。
另外,相应地,设置某个对象的原型可以通过Object.setPrototypeOf(),该方法要传入的参数为要设置原型的对象,以及该对象的新原型。在这之前,如果我们需要设置对象的原型,需要a.__proto__ = 某个对象这样编写。原型是JavaScript对象中被创建时就带有的一个对象,虽然如此,原型并不是一个固定的值,根据具体对象而动态变化。需要说明的是,__proto__并不是EcmaScript标准中的一部分,只是浏览器中的实现。而刚刚说到的get和set是方法ES2015标准中的。另外:
proto不应该与构造函数 func 的 prototype 属性相混淆。被构造函数创建的实例对象的 [[prototype]] 指向 func 的 prototype 属性。Object.prototype 属性表示 Object 的原型对象。

__proto__属性指向其构造函数的prototype属性,也因此,截图中的a.__proto__ === func.prototype。而对象的__proto__属性一般是直接指向Object的原型对象,即a.__proto__ === Object.prototype。
那么,prototype又是什么意思呢,通过上面提到的等式,我们可以发现都是这样一个等式的,即对象.__proto__ === 函数.prototype。
let n = new Number(1)
// 我们使用以上代码声明了Number类型的变量n,
// 可得出 n.__proto__ === Number.prototype
n 不是一个数值类型吗,为什么是对象。其实,他是一个包装对象。在这其中起作用的就是new操作符,该操作符一般和构造函数搭配使用。所以上面提到的Number是个函数没毛病,等式也是正确的。简单理解一下就是,__proto__是对象的属性,prototype是函数的属性。
对象是 JavaScript 语言最主要的数据类型,三种原始类型的值——数值、字符串、布尔值——在一定条件下,也会自动转为对象,也就是原始类型的“包装对象”。
所谓“包装对象”,就是分别与数值、字符串、布尔值相对应的Number、String、Boolean三个原生对象。这三个原生对象可以把原始类型的值变成(包装成)对象。
这三个对象作为构造函数使用(带有new)时,可以将原始类型的值转为对象;作为普通函数使用时(不带有new),可以将任意类型的值,转为原始类型的值。
原型链
前面说到对象的原型即是__proto__属性所指向的地方。但对象的原型是否还有原型呢,在部分情况下是有的。如果说原型是本地的,那么原型链可以理解为云端的。

__proto__属性中还有一个__proto__,而第二个__proto__属性和原型一部分中的是一样的。所以有这样的等式person.__proto__ === a.__proto__.__proto__。此外,二者也都还相等于Object.prototype。
这就是原型链,即一个对象的中所有__proto__属性串联的链。Object.prototype.__proto__ === null,这就是原型链的终点,为null。
原型链存在的意义就在于将一类对象中共有的属性/方法串联起来,而不必每个对象都自己持有一份中。
这里结合上一节原型中说到prototype是什么,说为什么Object.prototype.__proto__是原型链的终点。因为Object可以说是其他一切对象的构造函数,见下代码。
Function instanceOf Object // true
Array instanceOf = Object // true
let person = {name: 'sam'}
person instanceOf Object // true
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
万物由他而来,也终归于他。