本文以《JavaScript高级程序设计》第4版作为参考,整理使用JavaScript开发过程中,数据类型相关的知识点。
本文是开发知识点系列第二篇。
第一篇为:JavaScript开发中变量、常量声明的规矩总结
数据类型可以说是整个开发中的重中之重。没有数据什么都没法谈,有了数据也就有了数据类型。JavaScript数据类型有不同的分类标准,按照简单复杂分为简单数据类型和复杂数据类型,按照存储位置分为基本数据类型和引用数据类型。
简单数据类型和复杂数据类型
其中简单数据类型包含:
- Boolean
- Number
- String
- Undefined
- Null
- Symbol
其中Boolean只有true
和false
两个值。
其中Number数据类型的最大值约为179,769,313,486,231,570,814,527,423,731,704,356,798,070,567,525,844,996,598,917,476,803,157,260,780,028,538,760,589,558,632,766,878,171,540,458,953,514,382,464,234,321,326,889,464,182,768,467,546,703,537,516,986,049,910,576。还是挺大的,最小值约为5e-324。确定有限大,即介于JavaScript能表示的最大值和最小值之间,可以使用isFinite()
函数。
其中String数据类型的最大长度,根据ECMAScript标准,字符串的最大长度是2^53 - 1(即 9007199254740991)。
其中Undefined类型只有一个值,即undefined
。
其中Null类型只有一个值,即null
。
其中Symbol从ES6开始有。Symbol符号是原始值,且实例是唯一的不可变的,可以用来确保对象属性使用唯一标识符。
还有一种复杂数据类型叫Object(对象)。Object是一种无序名值对的集合,它是一种无序的数据结构,其中的属性(键)和对应的值是成对存在的。
基本数据类型和引用数据类型
在JavaScript中,基本数据类型的存储位置有两种情况:
-
栈(Stack):基本数据类型的值通常直接存储在栈内存中。栈是一种后进先出(LIFO)的数据结构,用于存储函数调用、局部变量和函数参数等。当一个函数被调用时,会在栈上创建一个新的执行上下文,并在其中存储函数的参数和局部变量。当函数执行完毕后,其执行上下文会从栈中弹出,释放相应的内存空间
-
固定内存空间:JavaScript中的基本数据类型(数字、字符串、布尔值、
null
和undefined
)的值是固定的,它们的存储是直接在变量中分配的。这意味着基本数据类型的值直接存储在变量所分配的内存空间中
需要注意的是,基本数据类型的值是不可变的,即它们的值在创建后不能被修改。当对基本数据类型进行赋值或传递给函数时,实际上是将值复制到新的变量或参数中。
与基本数据类型不同,引用类型(包括对象、数组和函数)的值存储在堆内存中,并且变量中存储的是对象的引用。当对象被赋值给变量或作为参数传递时,实际上是将对象的引用复制到新的变量或参数中,而不是复制整个对象。这也是为什么对象是可变的,因为可以通过引用修改对象的属性和值。
正因为引用数据类型的特殊性,如果要判断引用数据类型(如对象和数组)的相等性需要注意以下几点:
- 引用相等性:引用数据类型的相等性判断是基于引用的比较。当两个变量引用的是同一个对象时,它们被认为是相等的。可以使用
===
运算符来判断两个引用是否指向同一个对象。
javascript
const obj1 = { name: "John" };
const obj2 = { name: "John" };
const obj3 = obj1;
console.log(obj1 === obj2); // 输出:false
console.log(obj1 === obj3); // 输出:true
- 值相等性:如果需要判断两个对象的值是否相等,需要根据对象的属性进行比较。可以编写自定义的比较函数来逐个比较对象的属性值。
javascript
function isEqual(obj1, obj2) {
// 自定义比较逻辑,比较对象的属性值
// 返回 true 或 false
}
const obj1 = { name: "John", age: 25 };
const obj2 = { name: "John", age: 25 };
console.log(isEqual(obj1, obj2)); // 输出:true
实际上,简单数据类型 比如数字、字符串、布尔值也可以变为引用数据类型,只需要使用Number
、String
、Boolean
声明即可。
js
const n = new Number(1)
const s = new String('s')
const b = new Boolean(true)
console.log(typeof n, typeof s, typeof b) // object object object
而直接使用字面量初始化时
js
const n = 1
const s = 's'
const b = true
console.log(typeof n, typeof s, typeof b) // number string bolean
判断数据类型
typeof
typeof
常用来判断数据类型,比如上面用以区分基本数据类型和引用数据类型。但typeof
并不精准,就像将字面量初始化的字符串和new
操作符初始化的字符串判断为两种类型。
而且typeof null
也会返回object
。
instanceof
instanceof
运算符用于检查对象是否属于特定的构造函数或类。它可以判断一个对象是否是某个类的实例。例如:obj instanceof Array
判断obj
是否是一个数组的实例。
Array.isArray
Array.isArray(value)
方法用于检查一个值是否为数组。
Object.prototype.toString.call
Object.prototype.toString.call
方法可以返回一个表示数据类型的字符串。它适用于所有的数据类型,并且返回的结果更具体。
js
let n1 = 1
let n2 = new Number(1)
console.log(Object.prototype.toString.call(n1), Object.prototype.toString.call(n2))
// 输出 [object Number] [object Number]
综上,Object.prototype.toString.call
才是银弹,终极判断数据类型方案
js
/**
* @desc 数据类型检测
* @param data 待检测的数据
* @return {String} 类型字符串
*/
function type(data) {
return Object.prototype.toString.call(data).slice(8, -1).toLowerCase();
}
用上面的方法先判断大类型,之后再判断小类型。当然其它用于检验数据类型的方法不是不可以用,而是要看具体的开发场景开放需求。
最后总结一下:
- 要注意区分基本数据类型和引用数据类型区别,和简单数据类型复杂数据类型有什么区别
- 区分Number数据类型边界,String类型最大长度
- Symbol符号的特点和作用
- 最佳判断数据类型的方案是
Object.prototype.toString.call
本文完。