有人说JS里万物皆对象,有人说JS里类型多得让人头大。今天我们就来盘点一下JavaScript的七种基本数据类型和它们的"爸爸"Object,看看它们各自有什么脾气,日常相处中又有哪些让人哭笑不得的坑。
前言
JavaScript的数据类型,就像一大家子人。有嗓门大的,有闷葫芦的,有喜欢装酷的,还有整天搞事情的。作为前端开发者,不了解它们的性格,写代码时就等着被坑吧。
先来个数数:ES6之前,JS有5种基本类型:String、Number、Boolean、Null、Undefined。ES6加入了Symbol,ES2020又加了BigInt。再加上作为"一家之主"的Object(包括Array、Function、Date等引用类型),总共8种。
这8种类型,我们一个一个盘。
一、String:话痨属性,啥都能变成它
String类型就是文本数据,用引号包着。单引号、双引号、反引号(模板字符串)都行。
js
let name = '张三';
let greeting = "你好";
let template = `我的名字是${name}`;
String的特点就是"啥都能变成字符串"。你给它一个数字,它给你变字符串;给它一个对象,它给你变[object Object]。就像班里的话痨,什么话题都能接上。
但要注意,字符串是不可变的。你不能通过索引修改某个字符,只能重新赋值。
二、Number:数学课代表,但总算错账
Number类型代表数字,包括整数和浮点数。它负责所有的数学运算,看起来靠谱,但其实有个著名bug:
js
console.log(0.1 + 0.2 === 0.3); // false
什么?数学课代表居然算错?其实这不怪JS,是计算机二进制浮点数精度问题。所以涉及金钱计算,千万别直接用浮点数,要用整数(分)或者用第三方库。
Number还有一个特殊成员:NaN(Not a Number),表示"不是一个数字",但它属于Number类型。NaN有个怪癖:它不等于自己。
js
console.log(NaN === NaN); // false
判断是不是NaN要用isNaN()或Number.isNaN()。
三、Boolean:非黑即白的法官
Boolean只有两个值:true和false。它负责逻辑判断,简单直接。但在JS里,很多东西都能"变成"布尔值,比如if语句里,0、''、null、undefined、NaN、false都会被转换成false,其余都是true。
这就是传说中的真值和假值 。记住六个假值:false、0、''、null、undefined、NaN。其他的都是真。
js
if ('hello') {
console.log('这是真'); // 会执行
}
if (0) {
console.log('这是假'); // 不会执行
}
四、Null:空盒子,但身份成谜
Null类型只有一个值:null。它表示"什么都没有",通常我们用它来清空对象。
但Null有个著名的历史遗留bug:
js
console.log(typeof null); // "object"
明明是Null类型,为什么typeof返回"object"?这是JS第一版设计时的错误,后来为了兼容旧代码,一直没改。所以判断null要用=== null,不能用typeof。
五、Undefined:放鸽子的代表
Undefined也只有一个值:undefined。它表示"声明了变量,但没赋值",就像你叫了外卖,但外卖小哥迟迟没到。
js
let a;
console.log(a); // undefined
函数没有返回值,默认返回undefined。访问对象不存在的属性,也是undefined。
六、Symbol:独一无二的身份证
ES6新增的Symbol,用来创建唯一的值。每次调用Symbol()都会生成一个全新的、独一无二的值,即使描述相同。
js
let s1 = Symbol('id');
let s2 = Symbol('id');
console.log(s1 === s2); // false
Symbol常用于对象属性名,防止属性名冲突。比如你要给一个对象添加一个属性,但又怕覆盖原来的属性,用Symbol就安全了。
Symbol还有一个特点:它不会出现在for...in循环和Object.keys()里,但可以被Object.getOwnPropertySymbols()获取。
七、BigInt:大数专家,解决超限问题
BigInt是ES2020新增的,用来表示大于2^53-1的整数。因为Number能安全表示的最大整数是Number.MAX_SAFE_INTEGER,超出这个范围,计算就可能出错。
创建BigInt很简单:在数字后面加n,或者用BigInt()函数。
js
let big = 123456789012345678901234567890n;
let big2 = BigInt(123);
BigInt可以和BigInt运算,但不能和Number混合运算(会报错),必须显式转换。
八、Object:一家之主,万物之源
Object是引用类型,包括普通对象、数组、函数、日期、正则等等。它就像家里的大家长,其他类型都是基本类型,只有它是复杂类型。
基本类型存储的是值,而Object存储的是引用(内存地址)。所以:
js
let a = { name: '张三' };
let b = a;
b.name = '李四';
console.log(a.name); // '李四'
因为a和b指向同一个对象。
数组、函数都是Object的子类型。判断数组用Array.isArray(),判断函数用typeof(返回'function'),但注意typeof []返回'object'。
九、如何判断类型:侦探三件套
判断数据类型,我们有三个工具:
-
typeof:适合基本类型,但对null和Object不够精准。
jstypeof 'hello'; // 'string' typeof 123; // 'number' typeof true; // 'boolean' typeof undefined; // 'undefined' typeof Symbol(); // 'symbol' typeof 123n; // 'bigint' typeof null; // 'object' ------ 坑! typeof {}; // 'object' typeof []; // 'object' typeof function(){}; // 'function' -
instanceof:检查对象是否是某个构造函数的实例,适合引用类型。
js[] instanceof Array; // true {} instanceof Object; // true function(){} instanceof Function; // true -
Object.prototype.toString.call():终极武器,能准确判断所有类型。
jsObject.prototype.toString.call(123); // '[object Number]' Object.prototype.toString.call('123'); // '[object String]' Object.prototype.toString.call(null); // '[object Null]' Object.prototype.toString.call(undefined); // '[object Undefined]' Object.prototype.toString.call([]); // '[object Array]' Object.prototype.toString.call({}); // '[object Object]' Object.prototype.toString.call(function(){}); // '[object Function]'
这个方法最靠谱,返回格式统一的字符串,可以用来写类型判断函数。
十、类型转换:JS的骚操作之源
JS是弱类型语言,类型转换非常灵活,也因此诞生了很多"经典题目"。
隐式转换
-
字符串加法:只要有一边是字符串,另一边也会转为字符串。
js1 + '1' // '11' -
其他运算符:会尽量转为数字。
js'5' - 3 // 2 '5' * '2' // 10 'hello' - 1 // NaN -
比较运算符:双等号
==会进行类型转换,所以:js1 == '1' // true 0 == false // true null == undefined // true [] == false // true (这个最坑)
建议总是用三等号===,避免隐式转换带来的意外。
显式转换
手动用String()、Number()、Boolean()、parseInt()、parseFloat()等方法。
js
String(123); // '123'
Number('123'); // 123
Boolean(0); // false
parseInt('123px'); // 123
十一、总结:数据类型全家福
- 基本类型:String(话痨)、Number(数学课代表)、Boolean(法官)、Null(空盒子)、Undefined(放鸽子)、Symbol(身份证)、BigInt(大数专家)
- 引用类型:Object(一家之主),包括Array、Function、Date等
判断类型用三件套,注意坑点:typeof null === 'object',NaN不等于自己,0.1+0.2不精确。
掌握数据类型,是学好JavaScript的第一步。明天我们将深入变量的作用域和闭包,看看这些类型在内存里是怎么"串门"的。
如果你喜欢这篇文章,记得点赞收藏,让更多小伙伴看到。我们明天见!
明日预告:变量作用域与作用域链------JS的"找东西"逻辑,闭包到底是个啥?