JS中的数据类型转换与变量类型判断

Javascript 语言中有 6 种原始数据类型和 1 种复杂数据类型。原始数据类型有:undefinednullBooleanStringNumber 以及 ES6 引入的新的数据类型 Symbol。复杂数据类型是 Object,其中又细分了很多具体的类型,包括 ArrayFunctionDate 等等。

由于 Javascript 是一种动态类型的原因呢,变量没有类型限制,可以随时赋予任意值。所以一个变量的类型没法在编译阶段就知道,必须等到运行时才能知道。虽然变量的数据类型是不确定的,但是各种运算符对数据类型是由要求的,当操作数的类型与操作符要求的不一致时就会发生变量类型转换。

在了解变量自动转换之前,我们需要先了解下如何手动强制转换数据类型。

数据类型强制转换

强制数据类型转换主要会使用 NumberString 以及 Boolean 这三个函数,手动将变量转换成数字,字符串或布尔值。

Number()

  • 原始类型值的转换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Number(undefined); // NaN
    Number(null); // 0
    Number(true); // 1
    Number(false); // 0
    Number('abc'); // NaN
    Number(''); // 0
    Number('123'); // 123
    Number('123abc'); // 123

    // parseInt() 方法比 Number() 方法在转换字符串时要宽松
    parseInt('123abc'); // 123

    // parseInt() 方法和 Number() 方法都会过滤掉字符串的前导和后缀空格
    Number('\t\v\r233\n'); // 233
    parseInt('\t\v\r233\n'); // 233
  • 复杂类型值的转换

    1
    2
    3
    4
    5
    6
    // 对于复杂类型值(Object)而言,首先会调用自身的 valueOf() 方法,如果返回原始类型值则对其使用 Number() 方法,返回值是对象的话则再调用自身的 toString() 方法,如果其返回值是原始类型则使用 Number() 方法,如果返回值依然是对象则报错
    Number([]); // 0
    Number([5]); // 5
    Number([1, 2, 3]) // NaN
    Number({}); // NaN
    Number({a: 1}); // NaN

String()

  • 原始类型值的转换

    1
    2
    3
    4
    5
    6
    7
    8
    String(undefined); // 'undefined'
    String(null); // 'null'
    String(true); // 'true'
    String(false); // 'false'
    String('abc'); // 'abc'
    String(''); // ''
    String('123'); // '123'
    String('123abc'); // '123abc'
  • 复杂类型值的转换

    1
    2
    3
    4
    5
    // 对于复杂类型值(Object)而言,首先会调用自身的 toString() 方法,如果返回原始类型值则对其使用 String() 方法,返回值是对象的话则再调用自身的 valueOf() 方法,如果其返回值是原始类型则使用 String() 方法,如果返回值依然是对象则报错
    String({a: 1}); // '[object Object]'
    String([1, 2, 3]); // '1, 2, 3'
    String({}); // '[object Object]'
    String([]); // ''

Boolean()

除了 undefinednull-0/+0NaN 以及空字符串 '',使用 Boolean() 函数会转换成 false,其余值全部为 true,包括空对象以及 new Boolean(false)

1
2
3
4
5
6
7
8
9
Boolean(undefined); // false
Boolean(null); // false
Boolean(0); // false
Boolean(NaN); // false
Boolean(''); // false

Boolean({}); // true
Boolean([]); // true
Boolean(new Boolean(false)); // true

数据类型自动转换

自动数据类型转换是以强制数据类型转换为基础的。预期什么类型的之,就调用该类型的转换函数(Number()String()Boolean()),比如摸个位置预期为字符串,则会调用 String() 函数进行转换。如果该位置即可以是字符串也可以是数值,那么默认转为数值。

自动转换成布尔值

比如 if 语句的条件部分以及三目运算符的第一个表达式,就会将非布尔值的参数自动调用 Boolean() 函数转换为布尔值。

1
2
3
4
5
6
7
if (!undefined && !null && !0 && !NaN && !'') {
console.log('true'); // true
}

expression ? true : false;
// 等同于
!!expression

自动转换成字符串

字符串的转换主要发生在加法运算时。其中一个操作数为字符串,另一个为非字符串,则后者会调用 String() 方法转换成字符串。

1
2
3
4
5
6
7
8
9
10
11
'9' + 1 // '91'
'9' + true // '9true'
'9' + {} // '9[object Object]'
'9' + [] // '9'
'9' + function () {} // '9function () {}'
'9' + undefined // '9undefined'
'9' + null // '9null'

// 布尔值在加法运算符中另一个操作数为数字时也会自动转换成数字
true + 1 // 2
false + 1 // 1

自动转换成数值

除了加法运算符,其余运算符都会把操作数自动转换成数值。一元运算符也会把操作数转换成数值

1
2
3
4
5
6
7
8
9
10
'4' - '5' // -1
'4' * '5' // 20
true - 1 // 0
false - 1 // -1
'abc' - 1 // NaN
null + 1 // 1
undefined + 1 // NaN
+'abc' // NaN
+'true' // NaN
-false // 0

变量类型判断

下面简单梳理下常用的变量类型的判断方法

  1. typeof

    返回一个字符串,表示未经计算的操作数的类型,常用的判断结果如下

    类型 => 结果
    Undefined => ‘undefined’
    Null => ‘object’
    Boolean => ‘boolean’
    Number => ‘number’
    String => ‘string’
    Symbol => ‘symbol’
    Function => ‘function’
    宿主对象 => implementation-dependent
    任何其他对象 => ‘object’

  2. instanceof

    instanceof 运算符用来测试一个对象在其原型链上是否存在一个构造函数的 prototype 属性,该方法不适用于原始类型值的判断。另外,多个 iframe 或多个 window 窗口之间的交互导致了多个全局变量此时 instanceof 方法也会不准确。

    1
    2
    3
    4
    5
    6
    var arr = [1, 2, 3];
    arr instanceof Array; // true
    var func = function () {}
    func instanceof Function // true
    var data = new Date();
    date instanceof Date // true
  3. Object.prototype.toString.call()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var toString = Object.prototype.toString;
    var num = 123;
    toString.call(num); // [object Number]
    var str = 'abc';
    toString.call(str); // [object String]
    toString.call(null); // [object Null]
    toString.call(undefined); // [object Undefined]
    toString.call(new Date()); // [object Date]
    toString.call(new Error(); // [object Error]
  4. Array.isArray()

    该方法专门用来判断传递的值是否是一个 Array,在判断数组实例是,其优于 instanceof 方法,因为 Array.isArray 能检测 iframes

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var iframe = document.createElement('iframe');
    document.body.appendChild(iframe);
    xArray = window.frames[window.frames.length-1].Array;
    var arr = new xArray(1,2,3); // [1,2,3]

    // Correctly checking for Array
    Array.isArray(arr); // true
    // Considered harmful, because doesn't work though iframes
    arr instanceof Array; // false

Reference

数据类型转换
基础 |判断 JS 中的变量类型竟然可以如此简单
MDN: Array.isArray()
MDN: instanceof