TS判断一个值是否为数组类型
instanceof 用于检查对象是否属于特定类或构造函数的实例,返回的是一个布尔值。
const arr: any[] = [];
const isArray = arr instanceof Array;
console.log('使用instanceof判断',isArray)
Array.isArray 用于检查一个值是否为数组类型,返回的是一个布尔类型
const isArray: boolean = Array.isArray(arr); //true
Array.prototype.isPrototypeof
const obj:object = {}
const arr: any[] = [];
const isPrototype: boolean = Array.prototype.isPrototypeOf(obj); //false
const isPrototype: boolean = Array.prototype.isPrototypeOf(arr); //true
备注:Array.prototype.isPrototypeOf 方法主要用于检查对象是否继承了数组的原型,而不是判断对象是否为数组类型,其返回一个布尔值,如果 obj 是数组的实例或继承自数组的原型,则返回 true,否则返回 false。
看下面一个例子:
interface MyObject extends Array<any> {}
const myObj: MyObject = Object.create(Array.prototype);
myObj.push(1, 2, 3);
在上述示例中,我们通过定义一个 MyObject 接口来表示 myObj 对象,它扩展了 Array 类型,这样我们就可以在 myObj 对象上使用数组的属性和方法。使用类型断言 const myObj: MyObject = Object.create(Array.prototype); 将 myObj 声明为 MyObject 类型,表示它是继承自数组原型的对象。
打印数组如下:
Array { '0': 1, '1': 2, '2': 3, length: 3 }
console.log(Array.prototype.isPrototypeOf(myObj)); // true
console.log(Array.isArray(myObj)); // false
console.log(myObj instanceof Array); // true
至于为什么,那就需要了解一下isArray的实现原理:
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
我再解释一下:当我们使用 Object.create(Array.prototype) 创建对象 myObj 时,myObj 成为了一个继承了数组原型的新对象。它继承了数组原型上的方法和属性,包括 push、pop、length 等。
然而,Array.isArray 方法的实现原理是基于 JavaScript 的内部特性,它不仅仅依赖于对象是否继承了数组原型,还会检查对象是否具有内部的特殊属性 [[Class]]。只有当对象的 [[Class]] 属性为 “Array” 时,Array.isArray 才会返回 true。
对于真正的数组对象,它们的 [[Class]] 属性会被设置为 “Array”,这是 JavaScript 引擎的内部行为。这样,Array.isArray 就可以准确地判断一个值是否为数组。
然而,通过 Object.create(Array.prototype) 创建的对象 myObj 并不具有 “Array” 的 [[Class]] 属性。它的 [[Class]] 属性为 “Object”,因为它本质上仍然是一个对象。
因此,尽管 myObj 继承了数组原型上的方法,可以调用 push 方法并具有类似数组的行为,但它不满足 Array.isArray 对于数组类型的判断条件,因为它的 [[Class]] 属性不是 “Array”。所以 Array.isArray(myObj) 返回 false。
这个行为巧妙地区分了真正的数组和仅仅继承了数组原型的对象。它让我们能够更准确地判断一个值是否为数组类型,。
Object.getPrototypeOf 方法用于获取指定对象的原型(即该对象继承的原型对象)
Object.getPrototypeOf(arr) === Array.prototype //true
Object.getPrototypeOf 方法会返回指定对象的原型对象。它是通过访问对象的 [[Prototype]] 属性来获取原型。[[Prototype]] 属性存储了对象的原型引用。
Object.prototype.toString
Object.prototype.toString.call(arr) //[object Array]
Object.prototype.toString.call(obj) //[object Object]
综上,isArray和Object.prototype.toString判断的是最准确的。
番外:typeof相关内容
typeof 运算符可以判断以下类型:
“undefined”:未定义的变量或未赋值的变量。
“boolean”:布尔值。
“number”:数值。
“string”:字符串。
“symbol”:符号类型(ES6 引入)。
“function”:函数。
“object”:对象(包括数组、对象字面量、null、以及特殊的内置对象如 Date、RegExp 等)。
但是,typeof 运算符存在一些限制和特殊情况。例如,对于 null 类型和数组类型,typeof 运算符会返回 “object”,无法细分具体的类型,也就是说用来判断基本数据类型还可以,判断引用类型不太好使。
Object.prototype.toString.call() 方法可以判断几乎所有的数据类型,包括基本类型和复杂类型。它会返回一个类似于 “[object Type]” 的字符串,其中 “Type” 表示具体的数据类型,例如 “[object Array]”、“[object Object]”、“[object Date]” 等,但是,使用 typeof 和 Object.prototype.toString.call() 时,对于自定义的对象类型,都会返回 “[object Object]”,无法准确判断具体的自定义类型。这时可以通过其他方式,如 instanceof 运算符或构造函数来进行更精确的判断。
下面是Object.prototype.toString失灵的例子:
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
}
// 创建一个person实例
const person: Person = new Person("John");
// 使用 typeof 和 Object.prototype.toString.call()
console.log(typeof person); // "object"
console.log(Object.prototype.toString.call(person)); // "[object Object]"
完结!!