数据类型
在JavaScript中,数据类型可以分为两类:基础数据类型、引用/复杂数据类型
1.基础类型:
-
String -> 表示文本类型,如
"Hello World!"
-
Number -> 表示数字,可以是整数或者浮点数,例如
3
或者3.141592
,在JavaScript中,所有数字都是浮点数类型,即使没有小数部分 -
Boolean -> 表示逻辑实体,只有两个值:
true
和false
-
Undefined -> 表示表里已被声明但未赋值,或者直接没有被声明
-
Null -> 表示一个为空的值
-
BigInt(ES2020引入) -> 表示大于
2^53 - 1
的整数,这是Number类型能安全表示的最大整数。BigInt类型的值通过在整数后面加n来创建,例如9007199254740991n
。 -
Symbol(ES6引入) --> 符号类型,表示唯一、不可变的数据值,常用于对象属性的键
2.对象/复杂类型
Object,表示一个实例对象,是键值队的集合。在JavaScript中,几乎所有事物都是对象,包括数组、函数等。
-
Function,特殊类型的对象,可调用,有时被视为一种数据结构,因为它们可以像对象一样具有属性和方法
-
Array,特殊类型的对象,用于存储数据集合跟列表
此外,Date、RegExp(正则表达式)、Map、Set、WeakMap、WeakSet等都是特殊的对象类型,都可以用来存储和管理数据。
下面重点说一下Symbol
类型,面试爱问o(╥﹏╥)o
1. 作为对象属性的键:
使用Symbol创建的变量始终是唯一的,把它作为属性的键,可以有效避免冲突或者意外覆盖问题
let price = {
"影流之主": 6800,
"影流之主": 4800,
}
console.log(price);//{ '影流之主': 4800 }
//可以看到打印出来的对象只有一个属性,下面改写一下:
const KEY_ONE = Symbol();
const KEY_TWO = Symbol();
let price2 = {
[KEY_ONE]: 6800,
[KEY_TWO]: 4800,
};
const MY_KEY = Symbol();
price2[MY_KEY] = 3600;
console.log(price2[KEY_ONE]);//6800
console.log(price2);//{ [Symbol()]: 6800, [Symbol()]: 4800, [Symbol()]: 3600 }
2. Symbol值的描述
它可以接受一个字符串作为参数,并且通过description属性可以获取到对应的描述,进而区分不同的Symbol
const MY_NAME = Symbol('MY_NAME');
const YOUR_NAME = Symbol('YOUR_NAME');
let person = {
[MY_NAME]: '你比从前快乐KX',
[YOUR_NAME]: '甜酒果子',
}
console.log(person[MY_NAME]);//你比从前快乐KX
console.log(person[YOUR_NAME]);//甜酒果子
console.log(MY_NAME.description);//MY_NAME
console.log(YOUR_NAME.description);//YOUR_NAME
//需要说明的是,带有相同参数的两个Symbol值不相等,这个参数只是表示Symbol值的描述而已
const id1 = Symbol('id');
const id2 = Symbol('id');
console.log(id1 === id2);//false
3. 隐藏属性
使用Symbol创建的变量作为对象的属性,不能被常规方法访问到,所以可以使用这一点将属性隐藏,造成一个假的私有属性现象
const MY_NAME = Symbol('MY_NAME');
const YOUR_NAME = Symbol('YOUR_NAME');
let person = {
[MY_NAME]: '你比从前快乐KX',
[YOUR_NAME]: '甜酒果子',
'name': '张三',
}
console.log(Object.values(person));//[ '张三' ]
console.log(Object.keys(person));//[ 'name' ]
console.log(Object.getOwnPropertyNames(person));//[ 'name' ]
for (const key in person) {
console.log(key);//name
}
可以遍历到Symbol的方法:
Object.getOwnPropertySymbols() :返回对象中只包含symbol类型key的数组
Reflect.ownKeys() :返回对象中所有类型key的数组(包含symbol)
console.log(Object.getOwnPropertySymbols(person));//[ Symbol(MY_NAME), Symbol(YOUR_NAME)
console.log(Reflect.ownKeys(person));//[ 'name', Symbol(MY_NAME), Symbol(YOUR_NAME) ]
4. Symbol自带的方法
Symbol.for(),在全局 Symbol 注册表中搜索键为 key 的 Symbol。如果找到,则返回它;否则,将创建一个与给定键相关联的新 Symbol。这使得多个独立的代码片段可以通过给定的键共享 Symbol。
Symbol.keyFor(),接受一个通过 Symbol.for 方法创建的 Symbol,并返回该 Symbol 注册表中的键。如果 Symbol 不是全局注册的,则返回 undefined。
由于Symbol创建的值独一无二,但有时候我们可能希望使用同一个Symbol值,这时候就可以通过Symbol.for()
创建
const KEY1 = Symbol.for('KEY');
const KEY2 = Symbol.for('KEY');
console.log(KEY1 === KEY2);//true
console.log(Symbol.keyFor(KEY1));//KEY
console.log(Symbol.keyFor(KEY3));//undefined
3. 包装类型
在JavaScript中,包装类型(Wrapper Objects)不被视为独立的数据类型,而是存在于语言的运行时行为中,用于提供一种方式将原始数据类型(如 string、number、boolean、symbol、bigint)转换为对象。这样,原始值就可
以像对象一样使用,访问方法和属性。如下:
let heroName = 'LeBlanc';
console.log(heroName.toLowerCase());//leblanc
console.log(heroName.toString());//LeBlanc
在上面的例子中,字符串 heroName 是一个原始类型的值。当调用 .toLowerCase() 方法时,JavaScript临时将 heroName 包装为一个 String 对象,以便可以访问 .toLowerCase() 方法。方法调用完成后,返回的是一个新的原始类型的字符串,而临时创建的包装对象被丢弃。
尽管包装对象在技术上不是JavaScript的基本数据类型,但它们是理解和使用语言中的原始值与对象之间互动的重要概念。然而,直接使用这些包装对象的构造函数来创建对象(例如,使用 new String("LeBlanc"))是不推荐的,因为它可能导致混淆和错误。在大多数情况下,最好让JavaScript自动处理原始值和对象之间的转换。
另外,如果你尝试在原始值上设置一个属性,JavaScript 会创建一个临时对象,就像访问属性或方法时一样,但是设置的属性不会保留,因为这个临时对象会被立即丢弃。
这个行为可能初看起来有些反直觉。以下是一个例子来说明这个过程:
let assassin = 'LeBlanc';
assassin.chineseName = '乐芙兰';
console.log(assassin);//LeBlanc
console.log(assassin.chineseName);//undefined
在这个例子中,assassin 是一个字符串,因此是一个原始值。当我们尝试给它设置 chineseName 属性时,JavaScript 会临时将 assassin 转换成一个 String 包装对象,并在这个对象上设置 chineseName 属性。但是,一旦这个操作完成,这个临时的包装对象就会被丢弃,所以 chineseName 并没有被真正添加到 assassin 上。当我们接下来尝试访问 assassin.chineseName 时,你会得到 undefined,因为 assassin 是一个原始值,它没有任何附加的属性。
这也是为什么通常不建议在原始值上设置属性:这些属性不会被永久保存,因此这个操作没有任何实际效果。这个行为是 JavaScript 自动装箱机制的一部分,设计是为了让原始值表现得像对象一样,同时保持原始值的轻量和高效。