一、数据类型分类
我们知道,JavaScript 中的数据类型分为两大类:
- 原始类型:string, number, boolean, undefine, null, bigint, symbol
- 引用类型:Array, Function, Object, Date
在实际应用中,我们常常需要判断用户输入的值的类型是否符合要求:
js
let myname = 'aa'
function greating(name){
return `hello, I am ${name}
}
console.log(greating(myname));
很显然,greating 函数传入的参数是名字,也就是string类型,那我们就需要用到几种判断数据类型的方法 。
二、typeof 操作符
2.1 基本用法
typeof 可以判断除 null 之外的所有原始类型 ,且所有的引用类型 在typeof中都返回object ,除了function类型
javascript
let s = 'hello';
let num = 123;
let f = true;
let u = undefined;
let n = null;
let sy = Symbol(1);
let big = 123456789012345678901234567890n;
let arr = [];
let obj = {};
let fn = function(){};
console.log(typeof s); // "string"
console.log(typeof num); // "number"
console.log(typeof f); // "boolean"
console.log(typeof u); // "undefined"
console.log(typeof n); // "object" 注意:null 被误判
console.log(typeof sy); // "symbol"
console.log(typeof big); // "bigint"
console.log(typeof arr); // "object"
console.log(typeof obj); // "object"
console.log(typeof fn); // "function" function引用类型被正确判断
2.2 typeof 的原理
typeof 通过检查值的二进制表示来判断类型:
- 二进制前三位为
000的被认为是引用类型(函数类型除外) - 所有的引用类型被转换为二进制前三位都是 0(除了function类型)
- 但
null的二进制表示是全0,所以被误判为object function二进制前三位不是000,所以能正确识别
三、instanceof 操作符
3.1 基本用法
instanceof 通过原型链判断对象是否属于某个构造函数,且只能判断引用类型,无法判断原始类型:
javascript
let arr = [];
let obj = {};
let fn = function(){};
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true
console.log(obj instanceof Object); // true
console.log(fn instanceof Function); // true
let s = 'hello';
console.log(s instanceof String); // false(原始类型)
判断过程(以第二个输出举例):
- 判断
arr.__proto__是否等于Object.prototype,如果相等,返回true - 若不相等,顺着原型链继续判断
arr.__proto__.__proto__是否等于Object.prototype - 由于
arr.__proto__ == Array.prototype(数组由 new Array创建),且Array.prototype.__proto__ == Object.prototype(Array由 new Object 创建),因此arr.__proto__.__proto__等于Object.prototype,此时判断成功,返回true - 如果还不相等,则直到原型链找到
null,返回false
3.2 手写简易instanceof原理
js
function myInstanceof(l,r){
if (typeof(l) !== 'object' && typeof(l) !== 'function' || l === null ) {
return false // 如果左侧不是对象或为 null,直接返回 false
}
while(l !== null) {
if (l.__proto__ === r.prototype){
return true
}
l = l.__proto__
// 沿着原型链向上查找
}
}
console.log(myInstanceof([], Array));// true
console.log(myInstanceof('hello', String));// false
- 使用
instanceof时,会先通过typeof判断是否是对象类型(null和function类型特殊),如果不是,直接返回false(无法判断原始类型),typeof返回的值是object才会顺着原型链查找
四、Object.prototype.toString.call()
4.1 基本用法
这是最准确的类型判断方法,可以准确判断所有类型:
javascript
let s = 'hello';
let num = 123;
let arr = [];
let obj = {};
let fn = function(){};
console.log(Object.prototype.toString.call(s)); // "[object String]"
console.log(Object.prototype.toString.call(num)); // "[object Number]"
console.log(Object.prototype.toString.call(arr)); // "[object Array]"
console.log(Object.prototype.toString.call(obj)); // "[object Object]"
console.log(Object.prototype.toString.call(fn)); // "[object Function]"
- 该方法返回值是一串字符串 ,我们需要从字符串中提取出后面的类型
4.2 提取类型
通过slice()方法,可以截取数组或字符串中的一小段,并返回这个新数组/字符串
js
console.log(Object.prototype.toString.call(s).slice(8,-1));//返回String
4.3 slice 方法用法解析
js
const arr = ['a','b','c','d']
arr.slice(1,3)
const str = 'hello'
str.slice(2,4)//'ll'
str.slice(-1,3)//没有值
arr.slice(1,3),从索引为1开始,到索引为3结束,不包含索引为3的元素,即截取'a'和'b'str.slice(2,4),字符串同样也有slice方法(但没有splice方法),规则与数组一致,截取索引2到4的元素,不包括4,即截取得到一个新字符串'll'str.slice(-1,3),-1索引,即倒数第一个元素,3索引结束,由于默认只能从前面的元素开始到后面的元素结束,故该语句出错,没有返回值
注意: slice方法执行后,原数组/字符串不会改变 ,只会返回一个新数组/字符串
五、Object.prototype.toString()
如果我们将.call()去掉后又是什么?我们知道call()方法是改变this指向,把Object.prototype.toString的this指向变为括号里面需要判断类型的变量有什么用呢?
官方文档链接:es5.github.io/#x15.2.4.2
5.1 当调用 toString 方法时,执行以下步骤:
- 如果 this 值为 undefined,则返回 "object Undefined"。
- 如果 this 值为 null,则返回 "object Null"。
- 令 O 为以 this 值作为参数调用 ToObject 所得到的结果。 即令
const O = ToObject(this)
//O 永远是object
//O 要么是string对象||number对象||boolean对象||symbol对象||bigint对象 - 令 class 为 O 的 \[Class] 内部属性的值。
即令const class = O.[['Class']] - 返回由三个字符串 "object "、class 和 "" 拼接而成的字符串值。
5.2 ToObject()方法:
官方文档链接:es5.github.io/#x9.9
ToObject方法会将所有原始类型转换由 new 关键字得到的对象,并将原始类型的值赋给该对象的[[PrimitiveValue]],即将原始类型包装成对象,此时可以获取对象的 [[Class]] 内部属性
5.3 简单实现:
javascript
Object.prototype.toString = function() {
const O = ToObject(this); // 自动装箱
const class = O.[[Class]]; // 内部属性
return "[object " + class + "]";
};
六、Array.isArray()
6.1 基本用法
专门用于判断数组:
javascript
let arr = [];
console.log(Array.isArray(arr)); // true
6.2 注意事项
Array.isArray 是静态方法 ,不是定义在数组原型 上,而是定义在 Array 构造函数上:
javascript
// 正确调用
Array.isArray([]); // ✅
// 错误调用
[].isArray(); // ❌ TypeError