js 判断数据类型方法
js 判断数据类型方法
1. typeof()
js
是一门弱语言,它在声明变量时无需确定变量的类型,js
在运行时会自动判断。那么如何判断一个变量的类型呢,js
提供了 typeof
运算符,用来检测一个变量的类型。
1.1 typeof 语法
typeof
是一个运算符,有2种使用方式:typeof(表达式)和typeof 变量名,第一种是对表达式做运算,第二种是对变量做运算。
1.2 typeof 返回值
typeof
运算符的返回类型为字符串,值包括如下几种:
① 'undefined' --未定义的变量或值
② 'boolean' --布尔类型的变量或值
③ 'string' --字符串类型的变量或值
④ 'number' --数字类型的变量或值
⑤ 'object' --对象类型的变量或值,或者null(这个是js历史遗留问题,将null作为object类型处理)
⑥ 'function' --函数类型的变量或值
1.3 示例
// 'number' console.log(typeof 123); //'number' console.log(typeof NaN); //'number' // 'string' console.log(typeof '123'); //'string' // 'object' console.log(typeof null); //'object' var obj = new String(); console.log(typeof(obj)); //'object' let a = []; console.log(typeof a); //'object' // 'function' var fn = function(){}; console.log(typeof(fn)); //'function' console.log(typeof(class c{})); //'function' // 'undefined' console.log(typeof a); //'undefined' // 'boolean' console.log(typeof(true)); //'boolean' // 'symbol' let a = Symbol(); console.log(typeof a); //'symbol'
总结:typeof
运算符用于判断对象的类型,但是对于一些创建的对象,它们都会返回'object',有时我们需要判断该实例是否为某个对象的实例,那么这个时候需要用到instanceof
运算符。
2. instanceof
在 JavaScript 中,有7种基本类型(包括6种原始类型以及对象类型)。
在某些场景下,可能会需要我们做类型的判断,通常我们使用 typeof 。但是 typeof 在进行类型判断时有局限—— typeof 对于对象来说,除了函数都会显示 object 。因此,我们可以考虑使用 instanceof 来进行类型判断,因为 instanceof 内部机制是通过原型链来实现的。
function foo() { console.log('我是函数'); } let obj = { name: 'wyh', age: '23' } let arr = [1, 2, 3]; console.log(typeof(123)) // number console.log(typeof('haha')) // string console.log(typeof(true)) // boolean console.log(typeof(foo)) // function console.log(typeof(obj)) // object console.log(typeof(arr)) // object
2.1 instanceof 判断继承
刚才提到 instanceof
内部机制是通过原型链实现的,所以不难想到,可以通过 instanceof
来进行继承关系的判断。
function Foo() { this.name = 'wyh' this.age = '23' } let foo = new Foo() console.log(foo instanceof Foo) // true
同样的,在多层继承关系中,instanceof
同样适用:
function Foo() { this.name = 'wyh'; this.age = '23'; } function GFoo() { this.country = 'China'; } Foo.prototype = new GFoo(); let foo = new Foo() console.log(foo instanceof Foo) // true console.log(foo instanceof GFoo) // true
2.2 instanceof 实现原理
上面看过 instanceof
其实是通过原型链来实现继承关系的判断。那么我们如何来手写一个函数来实现 instanceof
的功能呢。首先,我们通过 ECMA 标准可以得到关于 instanceof
的底层原理:
我们只需要关注 instanceof
实现实际上是调用 JS 内部函数 [[HasInstance]]
来实现的。看到这里其实我们并不陌生,因为在 es6
的 Symbol
章节也有类似的说明:
那么我们来看一下,ECMA 中是如何描述 HasInstance
的:
function instance_of(L, R) { // L 表示instanceof左边,R 表示instanceof右边 let O = R.prototype; // 取 R 的显示原型 L = L.__proto__; // 取 L 的隐式原型 while (true) { // 循环执行,直到 O 严格等于 L if (L === null) return false; if (O === L) return true; L = L.__proto__; } } // 一直取 L 的隐式原型 __proto__,直到等于 R 的显示原型 prototype
instance_of
函数即是 instanceof
操作符的代码实现,并需要注意传入的参数都要为 object
类型。
2.3 instanceof 易错问题
我们通过上文已经知道, instanceof
是通过原型链来实现继承关系判断以及类型判断的。那么 instanceof
有没有弊端呢?或者说它就是判断类型的终极方法了吗? 并不是!
我们来看几个问题:
function Foo() { console.log('我是函数'); } let a = 1; console.log(a instanceof Number) // false console.log(Number instanceof Number) // false console.log(String instanceof String) // false console.log(Foo instanceof Foo) // false
分析:
- 对于 a instanceof Number ,上文提到的 ECMA 规范中指出,instanceof 用来判断的是 object 类型的,如果不是则会返回 false;
- 对于 Number instanceof Number 以及 String instanceof String ,都可以看做是 Foo instanceof Foo ,因为 Number 和 String 都是构造函数,原型链上都是由 Function 实例化出来的。那么我们只需要分析 Foo instanceof Foo 即可将这三个搞懂,将 { L : Foo , R : Foo } 代入到由 ECMA 规范得出的 instance_of 函数中去,即可得到:
let O = R.prototype = Foo.prototype L = L.__proto__ = Foo.__proto__ = Function.prototype O !== L // 循环 L = L.__proto__.__proto__ = Function.prototype.__proto__ = Object.prototype O !== L // 循环 L = L.__proto__.__proto__.__proto__ = Object.prototype.__proto__ = null return false
3. Object.prototype.toString.call()
前端技术分享