前语

当咱们在编写JavaScript代码时,了解和正确运用类型判别是非常重要的。JavaScript是一种弱类型言语,变量的类型能够动态改变,因而在处理数据时,咱们常常需求进行类型判别以保证代码的正确性和牢靠性。

本文将带领读者从根底到高级,深入分析JavaScript中的类型判别机制,揭开这一重要主题的面纱。

数据类型

JavaScript有七种原始数据类型与四种引证类型,原始数据类型分别是Undefined、Null、Boolean、Number、String、Symbol和BigInt,引证类型分别是目标、数组、函数、日期。

1. typeof

在进行类型判别时,咱们能够运用typeof操作符来获取变量的类型。

原始数据类型

let str = 'hello';
console.log(typeof str);  // "string"
let num = 123;
console.log(typeof num);  // "number"
let flag = true;
console.log(typeof flag); // "boolean"
let und = undefined;
console.log(typeof und);  // "undefined"
let nu = null;
console.log(typeof nu);   // "object"
let big = 123n;
console.log(typeof big);  // "bigint"
let s = Symbol('hello');
console.log(typeof s);    // "symbol"

引证类型

let obj = {};
console.log(typeof obj);  // "object"
let arr = [];
console.log(typeof arr);  // "object"
let fn = function(){};
console.log(typeof fn);   // "function"
let date = new Date();
console.log(typeof date); // "object"

咱们发现typeof null 回来的是object,这是一个前史遗留问题,与言语本身的设计和演化有关。在 JavaScript 的前期版别中,变量的值是由存储在变量存储空间中的符号位来表明的。在 JavaScript 中,一切的目标都表明为32位的字(words),而其中的第一个位被用作类型标签。

  • 目标类型的类型标签是 000
  • null 被认为是一个空目标指针,因而它的类型标签也是 000

因而,typeof null 回来 "object" 是因为在查看变量类型时,JavaScript 会读取存储在变量存储空间中的类型标签,而 null 的类型标签被解释为目标类型。

虽然这个行为是前史遗留问题,但为了保持向后兼容性,JavaScript 的设计者挑选保留了这个特性。在现代的 JavaScript 中,为了准确判别变量是否为 null,引荐运用严厉相等运算符 ===

console.log(nu === null) //true

除此之外,咱们发现引证类型只能将函数判别为function、将目标判别为object,而数组跟函数也判别为object。所以咱们还需求再找一个能进一步判别引证类型的操作符。


2. instanceof

instanceof 操作符用于查看目标是否是特定类(结构函数)的实例。它经过查看目标的原型链来确定目标的类型。假如目标是指定类的实例,则回来 true,否则回来 false

let obj = {}
console.log(obj instanceof Object); // true 
let arr = []
console.log(arr instanceof Array); // true 
let fn = function(){}
console.log(fn instanceof Function); // true 
let date = new Date()
console.log(date instanceof Date); // true 

所以咱们能够经过instanceof,再结合结构函数来判别引证类型。

于是咱们能够手写一个instanceof

function instanceOF(L, R) {
    let left = L.__proto__;    // 初始化变量 left 为实例目标 L 的隐式原型
    let right = R.prototype;    // 初始化变量 right 为结构函数 R 的显现原型 
    while (left !== null) {    // 迭代访问左操作数的原型链,假如不为空则进循环
        if (left === right) {    // 查看当时目标的隐式原型是否与结构函数的显现原型相等
            return true;    // 假如相等,回来 true,表明这个实例目标是这个结构函数创建的 
        } 
        left = left.__proto__;    // 移动到链中的下一个隐式原型 
    } 
    return false;     // 假如没有找到匹配,回来 false 
}
//举例:
console.log(instanceOF([],Array));//true

但是咱们在运用instanceof的时候,还会呈现一种情况:

let arr = []
console.log(arr instanceof Object); // true

咱们发现,数组也能够被判定为目标,所以当咱们要判别一个数据类型是不是目标的时候,用instanceof就不当,因为数组能够被辨认成目标。导致咱们判别过错。

那有没有能够直接判别类型的办法?

3. Object.prototype.toString()

官方定义:
Object.prototype.toString()当调用toString办法时,将执行以下步骤:

  1. 假如this值未定义,则回来"[object undefined]"
  2. 假如this值为空,则回来"[object null]"
  3. o作为传递this值作为参数的object调用的成果。
  4. classo的内部特点[[Class]]的值。
  5. 回来三个字符串 "[object "class"]" 衔接后的String值。

以上为官方规定,在这里就不过多解释,咱们直接用就行了。(参阅原文Annotated ES5

let number = 42;
console.log(Object.prototype.toString.call(number)); // "[object Number]"
let str = "Hello";
console.log(Object.prototype.toString.call(str)); // "[object String]" 
let bool = true;
console.log(Object.prototype.toString.call(bool)); // "[object Boolean]"
console.log(Object.prototype.toString.call(null));//'[object Null]'
console.log(Object.prototype.toString.call(undefined));//'[object Undefined]'
let bigint = 123n
console.log(Object.prototype.toString.call(bigint));//'[object BigInt]'
let symbol = Symbol('hello')
console.log(Object.prototype.toString.call(symbol));//'[object Symbol]'
let array = [];
console.log(Object.prototype.toString.call(array)); // "[object Array]"
let date = new Date();
console.log(Object.prototype.toString.call(date)); // "[object Date]" 
var obj = {};
console.log(Object.prototype.toString.call(obj));//'[object Object]'
let func = function() {};
console.log(Object.prototype.toString.call(func)); // "[object Function]"

咱们能够用这个办法判别然后数据类型。在这里咱们经过运用 call 办法,能够将 this 设置为任何咱们想要查看的目标,从而获取该目标的准确类型信息。

咱们能够稍加改善,让这个办法更简单为咱们所用:

var s ='thisisstring'
function isType(s) {
    return Object.prototype.toString.call(s).slice(8,-1)
}
if(isType === 'String'){
    //xxx
}

经过isType函数,咱们就能够获取变量 s 的类型,并与字符串 'String' 进行比较,其中slice(8,-1)用于截取类型字符串,去除 "[object ""]" 部分。

最终

经过本文的学习,咱们不只深入了解了基本的 typeof 操作符和 instanceof 操作符,还探讨了更为精准的 Object.prototype.toString 办法。这些工具不只协助咱们在编码进程中避免潜在的过错,还为处理各种杂乱的数据结构供给了牢靠的手段。

我的Gitee: CodeSpace (gitee.com)

技术小白记录学习进程,有过错或不解的当地还请谈论区留言,假如这篇文章对你有所协助请 “点赞 保藏 重视”,感谢支持!!