前言

记一下JS原型的知识

原型

假如有下面的代码

1
2
3
4
5
6
function Person(name = "sena", age = 16) {
this.name = name;
this.age = age;
}

let person = new Person();

原型的关系是这样的

image-20210206210435476

原型链

通过 __proto__ 作为桥梁连接起来的一系列原型就是原型链

image-20210206211213804

1
2
3
4
5
6
7
8
9
10
function Person(name = "sena", age = 16) {
this.name = name;
this.age = age;
}

let person = new Person();

console.log("person的原型", Reflect.getPrototypeOf(person));
console.log("object的原型", Reflect.getPrototypeOf({}))
console.log("object原型的原型",Reflect.getPrototypeOf(Reflect.getPrototypeOf({})));

输出结果是

image-20210206211845022

继承

es6为我们提供了非常好的继承模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Person {
constructor(name = "sena", age = 16) {
this.name = name;
this.age = age;
}
}

class Worker extends Person {
constructor(name = "sena", age = 16) {
super(name, age);
}
}
Worker.prototype.company = "Google"

let worker = new Worker();
let person = new Person();

console.log("worker的原型", Reflect.getPrototypeOf(worker));
console.log("worker原型的原型", Reflect.getPrototypeOf(Reflect.getPrototypeOf(worker)))
console.log("worker原型的原型和person的原型比较", Reflect.getPrototypeOf(Reflect.getPrototypeOf(worker)) === Reflect.getPrototypeOf(person));
console.log("person的原型", Reflect.getPrototypeOf(person));
console.log("object的原型", Reflect.getPrototypeOf({}))
console.log("object原型的原型",Reflect.getPrototypeOf(Reflect.getPrototypeOf({})));

image-20210206212932277

我们可以从babel转化后的代码中看出这种继承是怎么实现的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
"use strict";

function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
_setPrototypeOf(subClass, superClass);
}

function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}

var Person = function Person(name, age) {
if (name === void 0) {
name = "sena";
}

if (age === void 0) {
age = 16;
}

this.name = name;
this.age = age;
};

var Worker = function (_Person) {
_inheritsLoose(Worker, _Person);

function Worker(name, age) {
if (name === void 0) {
name = "sena";
}

if (age === void 0) {
age = 16;
}

return _Person.call(this, name, age) || this;
}

return Worker;
}(Person);

Worker.prototype.company = "Google";
var worker = new Worker();
var person = new Person();

概括一下就是

  • 创建一个父类型的对象temp,并且把对象的constructor属性设置成子类型的构造函数
  • 把创建的父类型对象temp设置成子类型构造函数的prototype
  • 把子类型构造函数的__proto__指向父类型

自己写一个inherit函数可以写成这样

1
2
3
4
5
function inherit(sub, sup) {
sub.prototype = Object.create(sup.prototype);
sub.prototype.constructor = sub;
Object.setPrototypeOf(sub, sup);
}

奇怪的东西增加了

有这么一张非常有趣的图

img

大部分东西都在上面讲过了

只有一个东西要提一下,那就是所有函数的__proto__都指向Function.prototype

1
Object.__proto__ === Function.prototype // true

image-20210206221238308

那就随便提提这个,对象的prototype指向undefined

image-20210206221548828

为什么要有super

看图看图,super初始化了对象并且使用父构造函数来为this绑定属性

image-20210301221820094

image-20210301221744867

后记

别骂了,我自己都觉得水)

FAQ & Ref

图解原型和原型链