所有的内置构造函数(Array、Function、Object…),它的 prototype 属性值都是定义好的内置原型对象,所以从这些内置构造函数创建的对象都默认继承自内置原型,可使用内置的属性。
所有的自定义函数,它的 prototype 属性值都是 new Object(),所以所有从自定义构造函数创建的对象,默认的原型链为 (空对象){} ---- Object.prototype。
所有的引用类型(数组、对象、函数),__proto__ 属性指向它的构造函数的prototype值,不手动破坏构造函数、原型之间的默认关系时
所有的引用类型(数组、对象、函数),如果不手动破坏原型链,构造函数、原型、实例对象三者之间有默认的关联。
对象的标识在 Java 中,由于对象都是从对应的类实例化出来的,因此类本身就可以做为对象的标识,用于区分不同对象是否同属一个类的实例。运算符是 instanceof。
在 JavaScript 中,虽然也有 instanceof 运算符,但由于并没有类的概念,虽然有类似的构造函数、原型的概念存在,但由于这些本质上也都是对象,所以很难有某个唯一的标识可以来区分 JavaScript 的对象。
下面从多种思路着手,讲解如何区分对象:
instanceof在 Java 中,可以通过 instanceof 运算符来判断某个对象是否是从指定类实例化出来的,也可以用于判断一群对象是否属于同一个类的实例。
在 JavaScript 中有些区别,但也有些类似:
var b = {} function A() {} A.prototype = b; var a = new A(); if (a instanceof A) { //符合,因为 a 是从A实例化的,继承自A.prototype即b console.log("true"); } function B() {} B.prototype = b; var c = new B(); if (c instanceof A) {//符合,虽然c是从B实例化的,但c也同样继承自b,而A.prototype指向b,所以满足 console.log("true"); } if (c instanceof Object) {//符合,虽然 c 是继承自 b,但 b 继承自 Object.prototype,所以c的原型链中有 Object.prototype console.log("true"); }在 JavaScript 中,instanceof 运算符的左侧是对象,右侧是构造函数。但他们的判断是,只要左侧对象的原型链中包括右侧构造函数的 prototype 指向的原型,那么条件就满足,即使左侧对象不是从右侧构造函数实例化的对象。
也就是说,在 JavaScript 中,判断某些对象是否属于同一个类的实例,不是根据他们是否是从同一个构造函数实例化的,而是根据他们的构造函数的 prototype 指向是不是相同的。
通过这种方式来区分对象有点局限是:在浏览器中多个窗口里,每个窗口的上下文都是相互独立的,无法相互比较。
isPrototypeOfinstanceof 是判断的对象和构造函数两者间的关系,但本质上是判断对象与原型的关系,只是刚好通过构造函数的 prototype 属性值做中转。
那么,是否有可以直接判断对象和原型两者的操作呢?
这个就是 isPrototypeOf 的用法了:左边是原型对象,右边是实例对象,用于判断左边的原型是否在右边实例对象的原型链当中:
Object.prototype.isPrototypeOf(b);但它跟 instanceof 有个本质上的区别,instanceof 是运算符,而 isPrototypeOf 是 Object.prototype 中的方法,由于基本所有对象都继承自这个,所以基本所有对象都可以使用这个方法。
instanceof 和 isPrototypeOf 更多使用的场景是用于判断语句中,如果需要主动对某个对象获取它的一些标识,可以使用接下来介绍的几种方式:
typeof在 JavaScript 中数据类型大体上分两类:原始类型和引用类型。
原始类型对应的值是原始值,引用类型对应的值为对象。
对于原始值而言,使用 typeof 运算符可以获取原始值所属的原始类型。
对于函数对象,也可以使用 typeof 运算符来区分:
所以它的局限也很大,基本只能用于区分原始值的标识,对于对象,自定义对象,它的结果都是 object,无法进行区分。
对象的类属性在对象一节中,介绍过,对象有一个类属性,其实也就是通过 Object.prototype.toString() 方法可以获取包含原始类型和引用类型名称的字符串,对其进行截取可以获取类属性。
相比于 typeof,它的好处在于可以区别所有的数据类型的本质,包括内置引用对象(数组、函数、正则等),也可以区分 null。
局限在于,需要自己封装个工具方法获取类属性,但这不是难点,问题在于,对于自定义的构造函数,都是返回 Function,而很多对象其实是通过构造函数创建出来的,所以无法区分不同的构造函数所创建的对象。
constructor 的 name 属性constructor 是对象的一个属性,它的值是继承自原型的取值。而原型该属性的取值,在不手动破坏对象的原型链情况下,为创建对象的构造函数。