JavaScript – 数据类型

前言

写着 TypeScript 教程,顺便也写点 JavaScript 的。

 

参考

JS数据类型分类和判断

阮一峰 – 数据类型

 

JavaScript 数据类型

JavaScript 一共有 8 种类型:

  1. string

  2. number

  3. boolan

  4. undefined

  5. null

  6. object

  7. symbol (es6)

  8. bigint (es2020)

symbolbigint 是后来(es6 和 es2020)加进去的。

除了 object 以外,其余 7 种被称为原始类型(primitive type),它们都属于值类型(value type)。

object 被称为非原始类型(non-primitive type),它是引用类型(reference type)。

 

typeof

typeof 可以 detect 出 value 的类型(虽然不是很精准)

console.log('string', typeof '');           // typeof 字符串返回的是 'string'(也就是 string 类型的意思)
console.log('number', typeof 0);            // 整数或浮点数是 'number'
console.log('boolean', typeof true);        // true,false 是 'boolean'
console.log('undefined', typeof undefined); // undefined 是 'undefined'
console.log('null', typeof null);           // null 是 'object'  
console.log('object', typeof {});           // 对象是 'object'
console.log('symbol', typeof Symbol());     // Symbol 创建的是 'symbol' 
console.log('bigint', typeof (100n));       // 整数+n 是 'bigint'

效果

都挺直观的,只有一个比较奇葩 —— null 是 'object',这是个历史错误,by right 它应该要是 'null' 才对。

其它常见 valuetypeof

console.log('array', typeof []);                  // array 是 'object'
console.log('function', typeof function() {});    // 函数是 'function'
console.log('arrow function', typeof (() => {})); // 箭头函数是 'function'
console.log('date', typeof new Date());           // Date 实例是 'object'
console.log('reg', typeof /\d/gi);                // 正则表达式是 'object'
console.log('NaN', typeof NaN);                   // not a number 是 'number'
console.log('class', typeof class{});             // class 是 'function'

效果

typeof 函数和箭头函数返回的是 'function'

不过,'function' 其实不是一种类型哦,它算是 'object' 的一种。

另外,class 的本质是函数,所以 typeof class 返回 'function'

new RegExpnew Date 返回的是实例,实例就是对象,所以是 'object'

NaN 是 "not a number",虽然名字是 "不是一个 number",但其实它依然是 'number' 类型。

array 不是一种类型,它算是一种 'object'

总结

typeof 可以返回 value 的类型信息,但它不直接等于 JavaScript 的 8 种类型。

我们需要自己进一步将其归类,比如:

typeof null 返回 'object',但 null 其实不是 object 类型,它是 null 类型才对。

typeof classtypeof function 返回的是 'function',但 JavaScript 没有 function 类型,它应该要被归纳为 object 类型。

 

其它判断方式

除了 typeof, 还有一些常用的类型技巧:

判断 null

null === null

判断 NaN

Number.isNaN(NaN)

判断 Array

Array.isArray([])

判断 Date 或 Regex

const date = new Date();
date instanceof Date; // true

黑魔法 typeof

console.log('string', Object.prototype.toString.call('string').slice(8, -1).toLowerCase());

效果

null 不是 'object' 而是 'null'

Array 不是 'object' 而是 'array'

Date 不是 'object' 而是 'date'

Regex 不是 'object' 而是 'regexp'

结论:透过 Object.prototype.toString 来做 typeof 可以判断的更仔细。

 

类型转换

参考:阮一峰 – 数据类型转换

先提醒:JavaScript 的类型转换规则挺乱的,最好不要常用,如果非要用,那要记好规则。

所有类型都可以强转成 booleanstringnumber

转 boolean

Boolean(value) 或者 !!value,两种写法都可以把 value 强制转换成 boolean

它的规则是:除了以下 5 个 value 会转成 false,其它 value 都会转成 true

  1. undefined

  2. null

  3. +0 或 -0

  4. NaN

  5. ''(empty string)

像 emtpty object {}、empty array [] 这些都会转成 true

转 number

Number(value) 或者 +value 两种写法都可以把 value 强制转换成 number

  1. '123'123

  2. ''0

  3. true1

  4. false → 0

  5. '123abc'NaN

  6. undefined → NaN

  7. null0

知识点:

  1. booleantrue1false  → 0(这个还算好记)

  2. empty string ''0(这个也还算记得住)

  3. numeric string '123'123(这个还算好记)

    numeric string + alphabetic string '123abc'NaN(这个还算好记)

    注:有一点不要混淆,使用 Number.parseIntNumber.parseFloat 的话,它会自动过滤掉 alphabetic string 'abc' 的部分,所以不会返回 NaN,这一点和强转 number 是不同的。
  4. undefinedNaN,而 null0 (这个不好记,为什么它俩会不一致呢🤔?)

object 转 number

它比较复杂,有三个步骤:

valueOftoStringNumber(value)

先用 object.valueOf 获取 value

如果这个 value 是一个对象(注:array, function 也算对象哦),那就再用 object.toString 获取 value

如果 value 还是一个对象,那就报错。

只要 valueOf 或 toString 返回的 value 不是对象,那么就 Number(value)

console.log(+{ valueOf: () => '5', toString : () => '10' }); // 5
console.log(+{ valueOf: {}, toString: () => '10' });         // 10

转 string

String(value) 可以把 value 强制转换成 string

转换规则是:

  1. 123'123'

  2. true'true'

  3. undefined'undefned' 

  4. null'null' 

都挺好记的。

object 转 string

toStringvalueOfString(value)

和 object to number 一样,只是顺序不同,它是先调用 toString,如果返回的是对象,那就再调用 valueOf

只要 toStringvalueOf 返回的 value 不是对象,那么就 String(value)

 

自动类型转换

if (value) 会把 value 强转成 boolean

!!value 会把 value 强转成 boolean

+value 会把 value 强转成 number

'string' + value 加号会把 value 强转成 string。比如:'123' + 3'1233'

value -*/ value 减乘除号会把 value 强转成 number。比如:'123' - '3'120

value == value 双等号在对比时,会先自动转换类型(规则下面会详细讲)。

 

双等号 ==

参考:JavaScript中双等号(==)的比较机制

双等号在对比时,会先自动转换类型,它的规则蛮多的:

  1. nullundefned 是相等的

  2. nullundefined 对比前不会被转换类型

  3. NaN 和谁都不相等,包括 NaN,也就是说 NaN == NaN 是 false, NaN != NaNtrue

  4. string == stringnumber == numberboolean == booleanobject == object 类型相同就不会自动转换。

  5. 类型不同的情况下,比如 string == numberboolean == stringobject == number,会先把它们转换成 number,像这样 Number(string) == Number(boolean)

    注:不要问我为什么会转成 number,我也不清楚,总是这就是它的规则。

 

我日常会用的类型转换

由于类型转换的规则很复杂,所以尽量还是少用为妙,以下是我常用的几个:

  1. +(new Date())date 转成 number,等价于 (new Date()).getTime(),会得到 epoch time(从 1970 年 1 月 1 日到现在的 milliseconds)。

  2. 01 来表示 boolean —— 0false1true

  3. if (object | array) 判断有 value,如果是null or undefined 会被转成 false

    我只会用来判断 object | arraystringnumber 我不会这样写,因为规则不好记。

  4. 'abc' + 123number 拼接到 string 里。

就这么多,其它的规则不太好记,所以我会尽量避开它们的类型转换。

 

Auto-boxing 机制

7 个 primitive types 中,有 5 个是 object-like:

console.log(typeof '');       // 'string'
console.log(typeof 0);        // 'number'
console.log(typeof true);     // 'boolean'
console.log(typeof Symbol()); // 'symbol'
console.log(typeof 0n);       // 'bigint'

除了 nullundefined

什么是 "object-like"?

console.log('hello world'.substring(0, 5)); // 'hello'

'hello world'string 不是对象,为什么它可以调用 .substring 方法?

这方法哪来的?

new String('hello world').substring(0, 5);

其实这个方法来自 class String

当一个 string(e.g. 'hello world'.substring 时,JavaScript 引擎会进行 "临时装箱",把它变成 new String('hello world').substring,这就叫 auto-boxing 机制。

numberNumberbooleanBoolean 也是如此。

symbolbigint 则有一点特别。

SymbolBigInt 不是 class,它们不可以 new Symbolnew BigInt

因此,当我们访问 Symbol().description 时,它并不是 auto-boxing 成 new Symbol().description

不过我们也不用分那么细,总之 JavaScript 引擎会特殊处理就是了(类似 auto-boxing 机制)。

结论:stringnumberbooleansymbolbigint 都不是对象,但是却可以访问属性和方法,这是因为 JavaScript 引擎做了特别处理,这个机制叫 auto-boxing。

什么时候会 auto-boxing?

除了 .property.method 会 auto-boxing 以外,for...inObject.getPrototypeOf 等也会

const number = 0;
console.log(Object.getPrototypeOf(number) === Number.prototype); // true

console.log(Object.keys('abc')); // ['0', '1', '2']
console.log(Object.getOwnPropertyNames('abc')); // ['0', '1', '2', 'length']

什么时候不会 auto-boxing?

console.log(typeof '');             // 'string'
console.log(typeof new String('')); // 'object'

console.log('' instanceof String);             // false
console.log(new String('') instanceof String); // true

typeofinstanceof 就不会。

从这些例子中可以看到,并不是在每一种情况下都会 auto-boxing,因此我们在使用时一定要搞清楚状况。

 

posted @ 2022-05-05 22:50  兴杰  阅读(57)  评论(0)    收藏  举报