一文带你了解类型判断与类型转换

135 阅读4分钟

数据类型

💡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,直接返回结果。若参数不为nullundefined,则将参数转为对象,再做判断。

转为对象后,取得该对象的 [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/false1/0
undefinedNaN
null0
string“按原样读取”字符串,两端的空格会被忽略。空字符串变成 0。转换出错则输出 NaN。

布尔型转换: 发生在进行逻辑操作时,也可以通过Boolean(value)进行显示变换

转换成
0、null、undefined、NaN、“”false
其他值,比如“0”、“ ”true

关于类型转换暂时就讲述到这里。谢谢大家的阅读!