JS扫盲之原型链

原型链是JS基础知识之一,翻阅那么多的文章,不如自行总结一下,温故而知新。

关于原型链,绕不开几个关键词,prototype,proto,constructor,new等,这里总结下。

如有错误,欢迎斧正。

  1. prototype是函数身上的属性,__proto__是对象身上的属性,constructor是对象身上的属性

  2. 实例化对象的__proto__指向的是创建该实例的原型对象,实例原型的constructor会是构造函数,实例原型的__proto__指向的是上一级,如果没有其它的对象原型,那就会是Object的实例原型。

    关于这点,可以参考下面这张图,摘自网上。

  1. constructor这个构造函数,存在于两个地方,一个是es6类写法下的构造函数,一个就是如上对象的构造函数属性。es6 class本身就只是个语法糖,底层原理还是原型链,因此都是一个意思,即构造函数即创建该实例的函数。
  2. 原型链指的是继承链条上的各个对象,而不是函数。

原型链的好处

区分于类继承方式的一种继承,比较灵活,比如B.prototype=new A(),当我们创建B的实例即可拥有A的方法。

测试题

收集以下几道题来测试下理解。

题1

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
function Fn(){
var a = 12
this.getName = function(){
console.log('private getName')
}
}

Fn.prototype.getName = function (){
console.log('public getName')
}

var fn = new Fn()
var fn1 = new Fn()
// 1,2
console.log(fn.a)
console.log(fn.getName())
// 3,4,5
console.log(fn.getName === fn1.getName)
console.log(fn.__proto__.getName === fn1.__proto__.getName)
console.log(fn.__proto__.getName === Fn.prototype.getName)
//6,7
console.log(fn.hasOwnProperty ===Object.prototype.hasOwnProperty)
console.log(fn.constructor === Fn)
/* 输出
* undefined
* private getName
* false
* true
* true
* true
* true
*/

题2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function P() {}
var p1 = new P();
P.prototype.age = 18;
P.prototype = {
constructor: P,
name: 'zz'
};
P.prototype.num = 20;
P.prototype.age = 20;
console.log(p1.name);
console.log(p1.age, 'dd');
console.log(p1.num);
var p2 = new P();
console.log(p2.name);
/**
* 输出
* undefined
* 18 dd
* undefined
* zz
*/

题3

1
2
3
4
5
6
function test() {}
console.log(test.prototype.constructor.constructor);
/**
* 输出
* [Function: Function]
*/

写在最后

理解这些基本的概念,才是写好代码的基础。

参考资料