JS 中有哪些数据类型
基本数据类型/值类型
-
数字 number
-
字符串 string
-
布尔 boolean
-
空 null
-
未定义 undefined
-
唯一值 symbol
-
大数据值 bigint
引用数据类型
-
对象 object
- 数组 new Array
- 正则 new RegExp
- 日期 new Date
- 错误 new Error
- ...
-
函数 function
有的人会认为函数 function 属于对象,其实确实也是,函数有三种角色,它既是一个普通函数,又可以作为一个普通对象来进行成员访问,它还能作为一个类。
String
// 字符串这个类型非常简单,只要单引号、双引号、“``”里包起来的就是字符串,不管里面的内容是什么
let str1 = ''
let str2 = ""
let str3 = '[10, 20]'
let str4 = 'function(){}'
let str5 = `` // es6新增的模板字符串,优势在于方便数据拼接
let str6 = `${}` // '${}'存放的是JS表达式:执行有返回结果的就是JS表达式(变量/数学运算/三元运算符/map...)
Boolean
let bool1 = true;
let bool2 = false;
Number
let num1 = 0;
let num2 = -1;
let num3 = 0.1;
let num4 = NaN; // not a number 不是一个有效数字,但是它确实是属于Numbe类型
let num5 = Infinity; // 无穷大
Symbol
Symbol 是 JavaScript 的 原始数据类型 ,Symbol 实例是唯一且不可改变的
Symbol 虽然是首字母大写,但是他是没有 constructor 的,不可以被 new
Symbol('foo') !== Symbol('foo');
const foo = Symbol();
const bar = Symbol();
typeof foo === 'symbol';
typeof bar === 'symbol';
let obj = {};
obj[foo] = 'foo';
obj[bar] = 'bar';
JSON.stringify(obj); // {}
Object.keys(obj); // []
Object.getOwnPropertyNames(obj); // []
Object.getOwnPropertySymbols(obj); // [ foo, bar ]
BigInt
在 JavaScript 中,BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数。而在其他编程语言中,可以存在不同的数字类型,例如:整数、浮点数、双精度数或大斐波数。
JS 中有一个最大安全数
Number.MAX_SAFE_INTEGER
9007199254740991(2^53-1)
Number.MIN_SAFE_INTEGER
-9007199254740991(-(2^53-1))
// 超过这个最大安全数,就不能精准计算了
Number.MAX_SAFE_INTEGER + 1
Number.MAX_SAFE_INTEGER + 2
...
// 都将不一定得到准确数值,所以超过最大安全数,我们使用BigInt处理
// 要创建BigInt,只需要在整数的末尾追加n即可
console.log(9007199254740995n); // → 9007199254740995n
console.log(9007199254740995); // → 9007199254740996
// 或者,可以调用BigInt()函数(和Symbol一样,非构造函数,不可以new)
BigInt("9007199254740995"); // → 9007199254740995n
BigInt 实际中使用特别少,我们知道它是什么东西就够了,这里就不深究了,有兴趣的同学可以去看MDN-BigInt
上面简单介绍了 JS 中的几种基础数据类型,关于 function 和 object 类型将在后续函数的高级用法和面象对象等文章中再详细介绍
数据类型检测
typeof
typeof 1; // 'number'
typeof NaN; // 'number'
typeof Infinity; // 'number'
typeof -Infinity; // 'number'
typeof ``; // 'string'
typeof true; // 'boolean'
typeof null; // 'object'
typeof undefined; // 'undefined'
typeof Symbol(); // 'symbol'
typeof BigInt(10); // 'bigint'
typeof {}; // 'object'
typeof []; // 'object'
typeof /^$/; // 'object'
typeof /^(?:-|\+)?(?:\d|(?:[1-9]\d+)(?:\.d+)?$/; // 'object'
typeof function () {}; // 'function'
- typeof 检测结果都是字符串,字符串中包含对应的类型"object"
- typeof null => 'object',但是 null 不是对象,为什么会出现这种情况呢?因为在 JS 的最初版本中,使用的是 32 位系统,为了性能考虑使用低位存储了变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object 。虽然现在的内部类型判断代码已经改变了,但是对于这个 Bug 却是一直流传下来。
- 检测数组,正则,日期对象返回的都是”object“,所以无法基于此方法细分对象
typeof 相关面试题
const a = typeof typeof typeof [12, 23];
console.log(a);
// 解析
// typeof(typeof(typeof [12, 23])) => typeof(typeof 'object') => typeof('string') => 'string'
NaN
// NaN: not a number 不是一个有效数字,但是它属于number类型
NaN === NaN; // false,NaN不是一个有效数字,所以它只要不是一个有效数字,其他啥都有可能,他和所有值都不相等,包括他自己
let n = '10';
if (n !== NaN) {
// 条件永远成立,使用这种方式,判断变量是不是有效数字,是不可以的
console.log('n不是有效数字');
}
// 上面那种方式去判断变量是否是有效数字,肯定是不行的,我们需要用到isNaN
// isNaN([val]):是否为非有效数字,把[val]隐式转换【Number([val])】为数字类型,再看一下是否为非有效数字,如果确实是非有效数字,返回TRUE,隐式转换后确实是有效数字,结果返回FALSE
let n = 'AAA';
if (isNaN(n)) {
// 所以,要使用这种方式去判断变量是不是有效数字
console.log('n不是有效数字');
}
NaN 相关面试题
let res = parseFloat('left:200px'); // parseFloat转换得出结果NaN
if (res === 200) {
// NaN === 200 不成立
alert(200);
} else if (res === NaN) {
// NaN === NaN 不成立 NaN不等于任何值,包括它本身
alert(NaN);
} else if (typeof res === 'number') {
// NaN是一个数字类型,条件成立
alert('number');
} else {
alert('Invalid Number');
}
// => 基于alert输出一个值,都要把值隐式转换为字符串,然后在输出
JS 中的数据类型转换
把其他数据类型转换为 Number 类型
// 1. 特定需要转换为Numbe的(Number([val])、parseInt/parseFloat([val]))
// 2. 隐式类型转换(浏览器内部默认要先转换为Number类型在进行计算的)【基本上都是基于Number([val])】来完成的
// + isNaN([val])
// + 数学运算(特殊情况:’+‘加号在出现字符串的情况下不是数学运算,是字符串拼接
// + 在‘==’两个等号进行比较时,有些值需要转换为数字再进行比较
// + ...
Number
- 把字符串转换为 Number,要求字符串中所有字符都必须是有效数字才能转换
console.log(Number('')); // 0
console.log(Number('10')); // 10
console.log(Number('10px')); // NaN
- 把布尔值转换为数字
console.log(Number(true)); // 1
console.log(Number(false)); // 0
- 把空转换为数字
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
- 把 Symbol、BigInt 转换为数字
console.log(Number(Number(Symbol('')))); // Uncaught TypeError: Cannot convert a Symbol value to a number
console.log(Number(BigInt('10'))); // 10
console.log(Number(BigInt('10px'))); // Uncaught SyntaxError: Cannot convert 10px to a BigInt
- 把对象或者函数转换为数字(先要基于 toString 把对象转换为字符串,再把字符串转化为数字)
console.log(Number({ 0: 10 })); // NaN
// ({0: 10}).toString() => '[object Object]',普通对象.toString()是检测数据类型,返回'[object Object]',再转换为数字为NaN
console.log(Number([10])); // 10
// [10].toString() => '10', Number('10') => 10
console.log(Number([10, 20])); // NaN
// [10, 20].toString() => '10, 20',Number('10,20') => NaN
// 数组.toString()是转换为字符串
console.log(Number([])); // 0 [].toString() => '' Number('') => 0
parseInt/parseFloat([val])
规则:先把[val]值转换为字符串,再按照从字符串左边第一个字符开始查找,把所有找到的有效数字字符串变为数字,直到遇到一个非有效数字字符则停止查找,如果一个有效数字字符都没有找到,返回结果就是 NaN,parseFloat 相比 parseInt 只是多识别一个小数点而已
console.log(parseInt('10px')); // 10
console.log(parseInt('10.5px')); // 10
console.log(parseFloat('10.5px')); // 10.5
console.log(parseInt('width:10px')); // NaN
把其他数据类型转换为字符串
// 1. 能使用的办法
// + String()
// + toString()
// 2. 隐式转换(一般都是调用其toString())
// + 在加号运算的时候,如果加号的某一边出现字符串,则不是数学运算,而是字符串拼接
// + 把对象转换为数字,需要先toString()转换为字符串,再去转换为数字
// + 基于alert/confirm/prompt/document.write... 基于这些方式输出内容,都是把内容先转换为字符串,然后再输出
// + ...
toString()
// 除了普通对象.toString()是检测数据类型(因为他们调用的是Object.prototype.toString(), 这个方法是检测数据类型的,其余的都是调用自己类原型上的toString,也就是用来转换字符串的)
let obj = { a: 1 };
let arr = [10];
let reg = /^\d+$/;
console.log(obj.toString()); // '[object Object]'
console.log(arr.toString()); // '10'
console.log(reg.toString()); // '/^\d+$/'
把其他类型转换为布尔
// 1. 基于以下方式可以把其他数据类型转换为布尔
// + ! 转换为布尔值后取反
// + !! 转换为布尔类型
// + Boolean([val])
// 2. 隐式转换
// + 在循环或者条件判断中,条件处理的结果是布尔值类型值
// 规则:只有0、NaN、null、undefined、空字符串,五个值变为布尔的FALSE,其余都是TRUE
console.log(!0); // true
console.log(!!0); // false
console.log(!![]); // true,空数组不会先转换为空字符串,记住那5个值
if (1) {
// 先把1转换为布尔,再验证真假
}
if (3 - 'AA' > 0) {
// 运算结果转换为布尔
}
验证一个对象是否为空对象
function isEmptyObject(obj) {
if (obj === null || typeof obj !== 'object') return false;
let flag = true;
for (let key in obj) {
if (!obj.hasOwnProperty(key)) break; // 没有自己的私有属性
flag = false;
break;
}
return flag;
}
隐式类型转换相关面试题
let result = 10 + false + undefined + [] + 'Tencent' + null + true + {};
console.log(result);
// 解析:
// ’+‘加号在js当中不一定是数学运算,只要有一边出现字符串(或者对象【因为数字 + 对象,理论上是吧对象转换为数字进行运算,但是我们知道,对象转换为数字要先转换为字符串,这样在还没有转换了数字的时候,就遇到了字符串了,变为字符串拼接】),都要变成字符串拼接
console.log(1 + '10'); // '110'
console.log(1 + [10]); // '110' [10].toString() => '10'
console.log(1 - [10]); // -9 加号拼接,减号还是做数学运算
// 所以上题
// 10 + false => 10 + Number(false) => 10 + 0 => 10
// 10 + undefined => 10 + Number(undefined) => 10 + NaN => NaN
// NaN + [] => NaN + Number([]) => NaN + [].toString() => 'NaN'
// 'NaN' + 'Tencent' => 'NaNTencent'
// 'NaNTencent' + null + true => 'NaNTencentnulltrue'
// 'NaNTencentnulltrue' + {} => 'NaNTencentnulltrue' + ({}).toString()
// 'NaNTencentnulltrue[object Object]'
显示类型转换相关面试题
parseInt(''); // NaN,parseInt的规则是从字符串从左往右找,一个都没找到就是NaN
Number(''); // 0, Number是从左往右,只要出现一个非有效数字就是NaN
isNaN(''); // false,isNaN(Number('')) => isNaN(0) => false
parseInt(null); // NaN,parseInt(null.toString()) => parseInt('null') => NaN
Number(null); // 0
isNaN(null); // false,isNaN(Number(null)) => isNaN(0) => false
parseInt('12px'); // 12
Number('12px'); // NaN
isNaN('12px'); // true
parseFloat('1.6px') + parseInt('1.2px') + typeof parseInt(null);
// 1.6 + 1 + 'number' => 2.6number
isNaN(Number(!!Number(parseInt(0.8))));
// isNaN(Number(!!Number(0))) => isNaN(Number(false)) => false
typeof !parseInt(null) + !isNaN(null);
// typeof的运算优先级要高于加号
// typeof false + false => boolean + !isNaN(0) => boolean + true => 'booleantrue'
// 浏览器运算符优先级 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
在 JS 中的比较操作
// == 比较
// === 绝对比较 (switch case 基于===比较的)
// 如果左右两边数据类型不一致,==会默认把数据类型转换为一致的,再去进行比较,===则直接返回false,因为它要求数据类型和值都一样才相等(严谨)
在==比较的过程中,数据转换的规则:
// 类型一样的几个特殊点
{} == {} // false,对象比较的是堆内存的地址
[] == [] // false
NaN == NaN // false
// 类型不一样的转换规则
// 1.
null == undefined // true,剩下的null/undefined和其他任何数据类型值都不相等
null === undefined // false,
// 2. 字符串 == 对象,要把对象转换成字符串
// 3. 剩下如果 == 两边数据类型不一致,都是需要转换为数字再进行比较
console.log(2 == true); // false
// 规则:== 是将数据类型转成一致再比较,将true转换成数字 2 == 1 => false
面试题
console.log([] == false); // true
// 两边类型不一致,转换成数字然后再比较,Number([]) => Number('') => 0
// Number(false) => 0
console.log(![] == false); // true
// 除0、NaN、null, undefined、空字符串变为false,其他全是true,所以![] => false
// false == false => true