JS内置对象3分钟掌握Symbol
目录
JS—内置对象:3分钟掌握Symbol
个人博客: 。感谢关注
1. 目录
2. 内置对象
常用的内置对象,只是简单的说一下,最想说的还是Symbol,面试问道的频率高。比方说:
//Object 所有对象的基类,提供属性/方法如 create(), keys(), assign()
//Function 函数构造器,所有函数实例的原型对象
//Array 数组对象,提供 push(), map(), filter() 等方法
const obj = new Object();
const arr = new Array(1, 2, 3);
//Math用于进行常见的数学运算
Math.random()//用于生成一个随机数,
Math.floor()//用于向下取整,
Math.sqrt()//用于开平方等。
//Date用于处理日期和时间
new Date()//可以创建一个表示当前日期和时间的对象
//String用于处理字符串
charAt()//用于获取特定位置的字符,
concat()//用于连接两个或多个字符串,
indexOf()//用于查找特定字符串的位置等。
//Map ES6 键值对集合,支持任意类型键
//Set ES6 唯一值集合
//WeakMap 键为弱引用的 Map,防止内存泄漏
//WeakSet 值为弱引用的 Set
const map = new Map();
map.set("key", "value");
const set = new Set([1, 2, 3]);
//Error 通用错误基类,如 new Error("message")
//TypeError 类型错误(如调用不存在的方法)
//SyntaxError 语法错误(如 JSON 解析失败)
//ReferenceError 引用错误(如访问未声明变量)
try {
throw new TypeError("类型错误");
} catch (e) {
console.error(e);
}
//JSON JSON 解析工具,提供 parse(), stringify()
const json = JSON.stringify({ name: "Alice" });
//RegExp 正则表达式对象,如 new RegExp("\\d+", "g")
//Promise ES6 异步操作对象,支持链式调用 .then()/.catch()
//Proxy ES6 代理对象,用于拦截对象操作(如 get/set)
//Reflect ES6 反射工具,提供对象操作的静态方法
const regex = new RegExp("\\d+", "g");
const promise = new Promise((resolve) => resolve("OK"));
3. Symbol
Symbol是ES6中引入的基本数据类型。用来创建 唯一的 , 不可变 的值。通常用于对象属性的key。
唯一性
每个symbol的值都是唯一的,即使他们的描述也相同,如下
let sym1 = Symbol("name");
let sym2 = Symbol("name");
console.log(sym1 === sym2); // false
不可变
Symbol 一旦创建,无法修改其值或描述
// 创建带描述的 Symbol
const sym = Symbol("original description");
console.log(sym.description); // "original description"
// 尝试修改描述
sym.description = "new description"; // 静默失败,无报错但无效
console.log(sym.description); // 仍输出 "original description"
// 甚至尝试强制修改(严格模式会报错)
Object.defineProperty(sym, 'description', { value: "hacked" }); // 抛出 TypeError
非字符串键
作用于对象时,symbol的键不会隐式的转为字符串,避免命名冲突。
//键是Symbol("id")这个对象。并不是字符串
const obj = {
[Symbol("id")]: 123 // 唯一的键
};
不可枚举性
symbol属性默认不会出现在for…in、Object.keys() 或 JSON.stringify() 中
//定义obj1,其中定义了两个属性,一个普通属性,一个symbol属性
let obj1 = {name:"zhangsan",[Symbol('id')]:"001"}
JSON.stringify(obj1) //{"name":"zhangsan"}
Object.keys(obj1)//['name']
4. Symbol的常见用法与问题
常见获取symbol的方法
//创建
const symId1 = Symbol("id")
//通过全局注册表去获取Symbol
const symId2 = Symbol.for("id")
const symId3 = Symbol.for("id")
console.log(symId1 === symId2) //false
console.log(symId2 === symId3) //true
//前面都说了唯一性了,为啥这里会打印true呢?
//因为,你通过Symbol.for方式去获取symbol对象,原理是它优先从全局注册表中查找以key为描述的symbol对象
//如果没有查找到就创建一个symbol对象返回,如果查找到了,就把查找到的symbol对象返回。
常见用法
- 避免属性名冲突。解决对象属性名可能被覆盖的问题:
const user = {
id: 1,
name: "Alice",
[Symbol("internal_id")]: "X-123" // 隐藏的内部属性
};
- 定义类的私有成员。模拟私有属性(通过闭包和 Symbol):
const _counter = Symbol("counter");
class MyClass {
constructor() {
this[_counter] = 0; // "私有"属性
}
increment() {
this[_counter]++;
}
}
- 定义常量。确保常量的唯一性:
const LOG_LEVEL = {
DEBUG: Symbol("debug"),
INFO: Symbol("info"),
ERROR: Symbol("error")
};
常见问题
- for…in,Object.keys方法无法获取到symbol,那么,要怎么获取symbol呢?
const obj = {
[Symbol("id")]: 123,
name: "Alice"
};
obj[Symbol("sex")] = "男"
//获取symbol对象
Object.getOwnPropertySymbols(obj);//[Symbol(id), Symbol(sex)]
//获取所有的key
Reflect.ownKeys(obj)//['name', Symbol(id), Symbol(sex)]
- Symbol.iterator 的作用
当一个对象实现了Symbol.iterator迭代器,则该对象可以用for…of遍历。比方说我们的内置对象Array
const arr = [10, 20, 30];
const iterator = arr[Symbol.iterator](); // 获取迭代器
console.log(iterator.next()); // { value: 10, done: false }
console.log(iterator.next()); // { value: 20, done: false }
console.log(iterator.next()); // { value: 30, done: false }
console.log(iterator.next()); // { done: true }
- for…in和for…of
let arr1 = ["1","2",Symbol("id"),"3"]
for (const key in arr1) {
//这里输出0,1,2,3
//然后通过key去获取值。
console.log(key);
}
let arr1 = ["1","2",Symbol("id"),"3"]
for (const value of arr1) {
//这里输出值
console.log(value);
}
for…in 是 JavaScript 中用于遍历对象 可枚举的字符串键属性 的语法,其底层机制如下:
a. 遍历范围
自身属性:对象直接定义的属性。
继承属性:从原型链继承的可枚举属性。
b. 遍历规则
仅遍历字符串键:for…in 只处理属性名为字符串的键,忽略 Symbol 键。
可枚举性检查:仅遍历 enumerable: true 的属性(通过 Object.defineProperty 或直接赋值定义的属性默认可枚举)
let obj = {}
obj.name = "zhangsan"
obj[Symbol("sex")] = "男"
let func = ()=>{
}
obj[func] = "李四"
//这里方法之所以能遍历,是因为这里的方法被存储为了字符串
//再回过头去看前面说的 非字符串键
Object.keys(obj) //['name', '()=>{\n}']