前言
在javascript中万物皆对象,也就是说数组,字符串也是对象,这里的对象不是指数据类型,而是一种概念。要知道字符串,数组,对象Object身上都有一些方法,那么这些方法从何而来呢,就是来自于他们的构造函数对象,比如创建一个数组可以用Array构造函数 new Araay()来创建,字符串和对象也同理。创建对象的方式一般有声明或者构造形式来创建的。
下面让我们来逐步了解什么是原型
通过下面的例子我们来理解什么是原型,用构造的形式创建一个字符串a和一个数组b还有一个对象c,大家可以在控制台运行打印以下代码看一下,和平时用字面量创建出来的变量有什么不一样。
let a = new String('zhangsan');
console.log(a)
let b = new Array([1,2,3]);
console.log(b);
let obj = new Object();
obj.value = '我是一个对象';
console.log(obj);
a的打印结果为:
b的打印结果为:
c的打印结果为:
测试过的同学会发现变量多了一个属性[[Prototype]]或者__proto__的属性(这两个相等只是写法不一样),__proto__是对象里面的属性,当对象创建以后__proto__就会被生成,即__proto__是对象内置的属性。(第一次展开)
那么prototype和__proto__属性是什么呢?
prototype和__proto__是原型,它们是一个对象,我们也称为原型对象。其中__proto__是隐式原型,prototype是显式原型
看上面的代码块和打印结果,由此得出
变量a的原型是String(__proto__属性值为String),因为是由new String()创建的。
变量b的原型是Array(__proto__属性值为Array),因为是由new Array()创建的。
变量c的原型是Object(__proto__属性值为Object),因为是由new Object()创建的。
a,b,c都是由不同的对象生成的,他们的对象也有原型。继续点开(a,b第二次展开)__proto__会发现变量a,b的__proto__原型也有__proto__原型并且值为Object,继续展开(a,b第三次展开)会发现里面已经没有__proto__属性了,然而点开变量c(c第二次展开)的__proto__原型却没有__proto__属性,让我们回过头来观察一下,是不是第一次展开c的时候,它的__proto__属性值就为Object了(这个过程不放图片了,大家可以自己试试看)。
由此可以得出结论,a,b,c的原型顶点为Object,是他们的老祖宗,a,b,c的__proto__属性的时候指向原型对象(祖宗),构造a,b,c的对象有prototype属性指向原型对象(祖宗),原型对象有constructor属性指向构造a,b,c的对象。
constructor属性
这是原型指向构造函数的属性。
可以简单理解为单细胞繁殖,祖宗细胞分裂繁殖出一代细胞,一代繁殖出二代,二代可以拿着基因([[prototype]])一层层找祖宗认亲,一代细胞拿着基因(prototype)可以找祖宗认亲,祖宗拿着基因(constructor)找一代细胞。
那么什么是原型链呢?
实例对象在查找某一属性的时候,如果查找不到就会沿着__proto__属性查找,直到最顶层,这样层层深入查找的过程就是原型链。