先给出名词的定义:
1、实例对象-被new进去对象称之为实例对象

例如: const p1 = new Person()p1就是实例对象

2、一般对象-未经new,间接申明的对象是一般对象

例如:const p2 = { name: "John" }p2就是一般对象

3、prototype, 中文翻译:原型对象
4、__proto__ ,中文翻译:原型 (英文能够读作dunder proto)

因为原型对象和原型容易混同,下文间接应用prototype 和 _proto(__proto__的简写)来行文,

为什么要理解js中的原型链:
JS中没有类的概念,为了实现继承(让一个实例对象领有不属于本身的属性或办法),通过 __proto__将实例对象和实例对象的prototype分割起来组成原型链,就能够让对象拜访到不属于本人的属性。

也就是说拜访一个实例p1的办法A,这个实例p1上不存在,则通过p1.__proto__上溯到p1构造函数Person的prototype(即上溯到Person.prototype),如果Person.prototype上仍然没找到办法A,则在Person.prototype的_proto上持续找,通过Person.prototype.__proto__持续上溯(Person.prototype.proto === Object.prototype)...

看上面的代码

function Person(name) {  this.name = name;}Person.prototype.sayHello = function() {  console.log(`Hello, ${this.name}!`);}const p1 = new Person("Mike");p1.sayHello(); // "Hello, Mike!"console.log("Person.prototype->", Person.prototype);console.log("p1.__proto__->", p1.__proto__);console.log("getPrototypeOf(p1)->", Object.getPrototypeOf(p1));console.log(Person.prototype === p1.__proto__); // true

下面这段代码的后果展现了:
对于一个构造函数,和通过构造函数new进去的对象,构造函数的prototype与实例对象的_proto雷同。

注:
__proto__是非规范的属性,未在ECMAScript 6规范中定义,但简直所有的古代浏览器都反对 __proto__属性。为了规范性,能够应用 Object.getPrototypeOf(obj) 办法来获取对象的_proto。

再看上面这段代码

const p2 = { name: "John" }; console.log(p2.__proto__); // [Object: null prototype] {} -> 是一个空对象{} console.log(p2.__proto__ === Object.prototype); // trueconsole.log(Object.prototype.__proto__); // null

一般对象的_proto值是 [Object: null prototype] {}

Object.prototype.__proto__ === null 这是原型链的重点

那么构造函数与Object有什么关联?
console.log(Person.prototype.__proto__ === Object.prototype); // true

其余:
1、prototype属性只存在于函数上,而__proto__ 存在于所有对象上。

留2个问题
console.log(Object.__proto__ === Object.prototype); // true or false? why?
console.log(Function.__proto__ === Function.prototype); // true or false?

同步更新到本人的语雀
https://www.yuque.com/dirackeeko/blog/bggcmd8fcib3uyvt