数据类型
💡Tips: 在数据类型中,值得注意的是要
Null与Undefined的区分以及Number与BigInt的差别。
JavaScript 语言中类型集合由原始值和对象组成。其中原始值有Undefined、Null、Boolean、String、Number、BigInt(es6新增)、Symbol(es6新增);对象有Object。
本文在这里就不再详细叙述,具体可请看JavaScript数据类型与数据结构。而如果想要深入了解JavaScript的变量在内存中的具体存储形式,可以参考JS中的栈内存堆内存。
接下来让我们看看JavaScript中的类型判断。
类型判断
💡Tips: 通常的类型判断中,有typeof、instanceof、constructor、Object.prototype.toString.call()、Array.isArray()等方法,本文只讲述其中三种。
typeof
**typeof** 操作符返回一个字符串,表示未经计算的操作数的类型。一般来说,数组、对象、null 都会被判断为object,其余判断正确。
| 类型 | 结果 |
|---|---|
| undefined | “undefined” |
| Boolean | “boolean” |
| Number/NaN | “number” |
| BigInt | “bigInt” |
| String | “string” |
| Function | “function” |
| 其他任何对象/ Null | “object” |
instanceof
**instanceof** 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上,它主要用来判别引用数据类型,不能用于判断基本数据类型。
function Car(make, model, year) {this.make = make;this.model = model;this.year = year;}function Plane(){}const auto = new Car('Honda', 'Accord', 1998);console.log(auto instanceof Car); // trueconsole.log(auto instanceof Object); // trueconsole.log(auto instanceof Plane); // false// 当改变实例对象的原型链时,员表达式的值可能会改变Car.prototype = {}console.log(auto instanceof Car) // false
instanceof原理
function instance_of(leftVaule, rightVaule) {let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值while (true) {if (leftVaule === null) {return false;}if (leftVaule === rightProto) {return true;}leftVaule = leftVaule.__proto__}}function Foo1() {}function Foo2() {}Foo1.prototype = new Foo2() {}let f1 = new Foo1()console.log(instance_of(f1, Foo1)) // trueconsole.log(instance_of(f1, Object)) // trueconsole.log(instance_of(f1, Foo2)) // truelet a = []let b = {}console.log(instance_of(a, Array)) // trueconsole.log(instance_of(b, Array)) // false
如上代码所示,instanceof主要的实现原理就是右边变量的prototype在左边变量的原型链上即可。因此,instanceof在查找过程中会遍历左边变量的原型链,直到找到右边变量的prototype,如果查找失败,返回false。
为了能更好的了解instanceof原理,可以参考js的原型继承原理,如下图:
Object.prototype.toString.call()
想了解上述的方法,我们可以先了解toString()方法。toString()默认返回一个表示给对象的字符串,通过[object type]的方式来表示。我们可以通过该方法来获取每个对象的类型,并且通过使用call()或 apply()能够获得更为精确的值。如下图:
为什么会发生这种情况呢?原因在于当对象的**toString()**方法未被重写时,将会正常返回类型;但是大多数对象都重写了**toString()**,这个时候需要用**call()**或 **Reflext.apply()**来调用。
// 1.未重写toString()({}).toString(); // => "[object Object]"Math.toString(); // => "[object Math]"// 2.重写toString()var x = {toString() {return "X";},};x.toString(); // => "X"Object.prototype.toString.call(x); // => "[object Object]"
原理
对于 Object.prototype.toString.call(arg),若参数为 null 或 undefined,直接返回结果。若参数不为null或 undefined,则将参数转为对象,再做判断。
转为对象后,取得该对象的 [Symbol.toStringTag] 属性值作为 tag,如无该属性,或该属性值不为字符串类型,则依下表取得 tag, 然后返回 "[object " + tag + "]" 形式的字符串。
Object.prototype.toString.call(null); // => "[object Null]"Object.prototype.toString.call(undefined); // => "[object Undefined]"// Boolean 类型,tag 为 "Boolean"Object.prototype.toString.call(true); // => "[object Boolean]"// Number 类型,tag 为 "Number"Object.prototype.toString.call(1); // => "[object Number]"// ...
类型转换
💡 Tips:类型转换是JS中情况繁杂且容易出错的知识点,列举全部知识点繁多,本文在这里只列举开发中的常见情况。想要深入了解可以参考JavaScript深入之头疼的类型转换(上),JavaScript深入之头疼的类型转换(下)。
开发中有三种常用的类型转换:转换为 string 类型、转换为 number 类型和转换为 boolean 类型。
字符串转换: 发生在输出内容的时候,也可以通过String(value)进行显示转换。
数字型转换:发生在进行算术操作时,也可以通过Number(value)进行显示转换。
| 值 | 转换成 |
|---|---|
| true/false | 1/0 |
| undefined | NaN |
| null | 0 |
| string | “按原样读取”字符串,两端的空格会被忽略。空字符串变成 0。转换出错则输出 NaN。 |
布尔型转换:发生在进行逻辑操作时,也可以通过Boolean(value)进行显示变换
| 值 | 转换成 |
|---|---|
| 0、null、undefined、NaN、“” | false |
| 其他值,比如“0”、“ ” | true |
关于类型转换暂时就讲述到这里。
