我们知道JavaScript中的一个函数,当与new一起使用来创建一个对象时,就成为了一个类型,所创建的对象叫作这个类型的实例(instance)。
以Array来作为例子,Array本身是一个函数,当创建多个实例array1、array2、array3... ... 这些实例都拥有push、pop、slice等方法,并且每一个array*实例的这些方法指向的都是同一个函数。
通过下面的例子来证明一下:
var array1 = new Array()
var array2 = new Array()
var res = Object.is(array1.slice, array2.slice) // 比较两对象slice方法
console.log(res) // 输出比较结果
Object.is(obj1, obj2) 可以用来比较两个非数字、非字符串对象是否是同一个对象。
上述代码创建了两个Array实例,然后将两个实例的slice方法进行比较。来看一下运行结果:
true
运行结果为true,说明两个实例的slice方法引用的是同一个函数。为什么两个不同实例的方法会指向背后同一个对象?这背后的原理是什么?
类对象
每一个实例都有一个__proto__属性,对同一种类型的实例来说,他位的__proto__属性指向同一个对象,这个对象叫类对象(class object)。
instance.__proto__ => class object //__proto__指向类对象
为什么要有类对象?我们知道,同一种类型的实例,既有各自不同的属性,也有各自相同的属性。各自不同的属性,存放在各个实例内部;而相同的属性,则提取出来,存在在类对象中。
更具体一点的说就是,成员属性都存储在实例中,成员方法都存在在类对象中。比如,对于Array的slice方法来说,slice方法就存储在Array的类对象中。
有使用实例调用公共方法时,例如:
array1.slice()
JavaScript引擎会首先在array1实际本身寻找slice属性,因为array1没有slice属性,引擎会继续在array1.proto的类对象中寻找,对于Array的slice方法来说,在array1.proto中就能找到。
我们把这种根据proto寻找属性的流程归纳如下:
- 在实例中寻找属性property,如找到则返回该值,否则继续2
- 在实例proto指向的类对象中寻找,找到则返回该值,否则则退出返回空
引用类对象
上说解释了什么是类对象,那该如何引用类对象呢?
对于自定义类型来说,Function.prototype指向的就是类对象,如:
function Point()
{
}
Point.prototype // 这就是类对象
另外通过实例的proto方法也能引用,如:
array1.__proto__ // 这就是类对象
函数中是prototype,而实例中是proto,注意区分。
另外,JavaScript标准推荐使用Object.getPrototypeOf()来获取实例的类对象。如:
Object.getPrototypeOf(array1) // 获取类对象
OK,结束。
什么是继承?什么是继承链?