引言:修仙之途,始于识型。Javascript 世界中万物皆有根基,唯有精准判别其来历根脚,方能在变幻莫测的代码洪流中稳如磐石。今日便为诸位道友奉上这四门绝学,助你勘破迷雾,直指本质。
首先我们先来给各位道友介绍一下js中的基础类型,道友初步了解了这部分的知识,才是真正踏入了 属于js 的仙缘
一,js中的基础类型
- 原始类型:string,number,boolean,undefined,null,bigInt,symbol
- 引用类型:Array,Object,Function,Date
二, 深入了解js中的四大判断类型秘籍
所以聪明的道友会想到 v8引擎 是如何识别并返回数据给使用者的呢? 接下来我们将探寻可以通往知识深处的四大类型判断方法
1. typeof 方法(判断类型的残缺功法)
首先typeof是存在 windows 里的方法,我们也可以直接作为关键字使用
typeof 42; // "number"
typeof 'hello'; // "string"
我们通过运行几个小周天来了解typeof的用法
function greatting(name) {
if (typeof (name) === 'string') {
return `hello, I am ${name}`
}
return '请输入字符串类型'
}
console.log(greatting(myname));
输出结果为:
由上方运行结果可知,typeof()可以正确判断 myname 的类型并返回
可是为什么标题会提到typeof()是一种残缺的方法? 因为在typeof中,null会返回object类型,其他引用类型会返回object类型,除了function
console.log(typeof null); // "object"
console.log(typeof { name: '茶壶' }); // "object"
console.log(typeof function(){}); // "function"
console.log(typeof console.log); // "function"
你看结果如我们所预料的一样,而为什么 null 的原始类型不返回 null 类型而返回 object 类型呢? 是因为在typeof方法的规律中,typeof 是通过将值转化为二进制来判断类型的,二进制前三位是 0 的统一被认为是引用类型, 在计算机中,所有的引用类型被转化为二进制前三位都是 0 (除了函数),而 null 转化为二进制是一整串的 0 ,电脑是32位就是32个0
2. 判断引用类型的天阶方法instanceof
instanceof可以准确的判断引用类型的类型,但是无法判断原始类型 ,null和undefined会显示报错,因为根本没有这个构造函数 接下来我们来深度剖析这个功法的核心运作规律 它是通过隐式原型链来查找 x 是否隶属于 X 这个类型
这就要涉及到一个隐藏的运转规律 v8 在访问对象中的一个属性时,会先访问对象中显示存在的属性,如果没有,就会去对象的隐式原型上查找,如果还没有,就顺着隐式原型一直往上找,直到找到 null 为止,这个查找关系,就叫原型链查找,下面我们通过自己实现这个方法来直观体验它的用处
function myInstanceof(left, right){
if(typeof left !== 'object' && typeof left !== 'function' || left === null){
return false
}
let leftProto = left.__proto__
let rightProto = right.prototype
while(leftProto !== null){
if(leftProto.__proto__ === rightProto.__proto__){
return true
}
leftProto = leftProto.__proto__
}
return false
}
console.log(myInstanceof({}, Array));//false
console.log(myInstanceof([], Object));//true
console.log(myInstanceof('hello', String));//false,因为这个方法就是只能用来判断引用类型
console.log(arr instanceof Array);//true
arr.__proto__ === Array.prototype//隐示原型等于显示原型
console.log(arr instanceof Object);//true
//先判断隐式原型是否等于显示原型,再判断隐式原型的原型是否等于显示原型,接着判断过去,直到判断到 Null
arr.__proto__.__proto__ === Object.prototype隐示原型的原型等于显示原型
这是上述代码块的运行结果
我们要注意在运行结果中它把 [] 数组也给识别为了 Object,运行结果为true,因为instanceof通过访问隐式原型链来判断结果 。
那各位道友肯定会好奇有没有一种万能的秘籍既能判断引用类型又能判断原始类型?
3. Object.prototype.toString.call() 用于渡劫得证果位的最终秘籍
首先我们要想了解这门功法,得归溯到创作这门法门的老祖 Annotated ES5
结合我们溯源的记忆,可以将该方法分为四步
-
特殊处理
undefined和null-
如果
this值是undefined,直接返回"[object Undefined]"。 -
如果
this值是null,直接返回"[object Null]"。
这是为了避免调用
ToObject时抛出错误(ToObject(undefined/null)会报错)。 -
-
将
this转为对象
Let O be the result of calling ToObject passing the this value as the argument.- 基本类型(
number、string、boolean、symbol、bigint)会被包装为对应的包装对象。
- 基本类型(
-
获取内部属性
[[Class]]
Let class be the value of the [[Class]] internal property of O.- 每个内置对象都有一个不可直接访问的内部属性
[[Class]],如"Number"、"String"、"Array"、"Object"等。 const class = O.[[calss]]
- 每个内置对象都有一个不可直接访问的内部属性
-
拼接并返回字符串
返回"[object " + class + "]"。
4. Array.isArray() 触类旁通的小秘籍
道友历经三招绝学,已然能够应对诸多类型判断之劫难。然在应对数组一脉时,尚有一门小巧而迅捷的功法不可不知,这便是 Array.isArray() 。
与 instanceof 需循着原型链苦苦追寻不同,Array.isArray() 专为鉴定数组而生,无论这位数组道友是诞生自当前窗口,还是跨越了 iframe 的边界,它皆能慧眼识真,绝不会因为不同执行环境(Realm)的 Array 构造不同而产生误判。
js
// 在当前世界诞生的数组
const arr = [1, 2, 3];
console.log(Array.isArray(arr)); // true
// 伪装成数组的普通对象
const fakeArr = { length: 3, 0: 'a', 1: 'b', 2: 'c' };
console.log(Array.isArray(fakeArr)); // false
// 跨越边界的数组,instanceof 可能判断失败,但 isArray 依然稳健
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const frameArr = iframe.contentWindow.Array(1,2,3);
console.log(frameArr instanceof Array); // false
console.log(Array.isArray(frameArr)); // true
document.body.removeChild(iframe);
此功法的内功心法其实非常简单——它直接调用了 Object.prototype.toString.call() 的变体,查看传入对象的 [[Class]] 内部属性是否为 "Array",进而返回布尔结果。因其专一,故而极快且稳,是道友日常行侠仗义、处理数组判断时的上佳之选。
谨记:Array.isArray() 只能判断变量是否为纯正的数组,面对类数组对象它毫不留情地返回 false。若需判断类数组,仍需结合其他功法共同施展。
至此,四大类型判断秘籍已尽数托付于诸位道友,望尔等勤加修炼,早日在 JavaScript 的世界中洞悉万物本相,修得大成之境