先给出名词的定义:
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相同。
image.png
注:
__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); // true

console.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


DiracKeeko
125 声望2 粉丝