数据类型
💡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); // true
console.log(auto instanceof Object); // true
console.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)) // true
console.log(instance_of(f1, Object)) // true
console.log(instance_of(f1, Foo2)) // true
let a = []
let b = {}
console.log(instance_of(a, Array)) // true
console.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 |
关于类型转换暂时就讲述到这里。