当前位置: 首页 > news >正文

ES6 面试题及详细答案 80题 (33-40)-- Symbol与集合数据结构

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux… 。

前后端面试题-专栏总目录

在这里插入图片描述

文章目录

  • 一、本文面试题目录
      • 33. 什么是Symbol?它有什么特性?
      • 34. 如何创建一个Symbol类型的值?如何为其添加描述?
        • 一、创建Symbol值
        • 二、为Symbol添加描述
      • 35. Symbol作为对象属性有什么优势?如何获取对象的Symbol属性?
        • 一、Symbol作为对象属性的优势
        • 二、获取对象的Symbol属性
      • 36. Set和Map的区别是什么?分别适用于哪些场景?
        • 适用场景:
      • 37. Set如何实现数组去重?
        • 实现步骤:
        • 示例代码:
        • 原理:
      • 38. Map与对象(Object)相比有哪些优势?
      • 39. WeakSet和WeakMap的特性是什么?与Set、Map有何区别?
        • 一、核心特性(WeakSet和WeakMap共有的)
        • 二、与Set、Map的区别
        • 示例:
        • 适用场景:
      • 40. 如何遍历Set和Map中的元素?
        • 一、遍历Set
        • 二、遍历Map
        • 总结:
  • 二、80道ES6 面试题目录列表

一、本文面试题目录

33. 什么是Symbol?它有什么特性?

Symbol是ES6新增的一种原始数据类型,用于表示独一无二的值,不属于任何其他类型(如字符串、数字等)。它的核心特性如下:

  1. 唯一性:即使两个Symbol的描述相同,它们也是不同的。

    const s1 = Symbol("test");
    const s2 = Symbol("test");
    console.log(s1 === s2); // false
    
  2. 不可枚举性:Symbol作为对象属性时,不会被for...inObject.keys()等方法枚举,也不会被JSON.stringify()序列化。

    const obj = {[Symbol("id")]: 123,name: "test"
    };
    console.log(Object.keys(obj)); // ['name'](Symbol属性未被枚举)
    
  3. 不能与其他类型直接运算:Symbol值不能与字符串、数字等进行拼接或算术运算,否则会报错。

    const s = Symbol("a");
    // console.log(s + "b"); // TypeError: Cannot convert a Symbol value to a string
    
  4. 可作为对象属性的键:解决对象属性名冲突问题(如多模块协作时避免属性覆盖)。

  5. 无法被实例化:Symbol是原始类型,不能用new操作符创建(new Symbol()会报错)。

34. 如何创建一个Symbol类型的值?如何为其添加描述?

创建Symbol值的方式及添加描述的方法如下:

一、创建Symbol值

通过Symbol()函数创建,注意不能使用new关键字(因Symbol是原始类型,非对象)。

const s = Symbol(); // 创建一个无描述的Symbol
console.log(typeof s); // "symbol"(特殊的原始类型)
二、为Symbol添加描述

Symbol()函数可接收一个字符串作为描述(description),用于调试时区分不同的Symbol(不影响其唯一性)。

  1. 直接传入描述字符串

    const s1 = Symbol("userName"); // 描述为"userName"
    const s2 = Symbol("age");      // 描述为"age"
    
  2. 通过description属性获取描述

    console.log(s1.description); // "userName"(ES2019新增属性)
    
  3. 注意:描述相同的Symbol仍是不同的值:

    const s3 = Symbol("id");
    const s4 = Symbol("id");
    console.log(s3 === s4); // false(描述相同但值不同)
    
  4. 通过Symbol.for()创建全局共享的Symbol(特殊场景):
    若需要让描述相同的Symbol在全局范围内保持唯一,可使用Symbol.for(),它会在全局Symbol注册表中查找描述,存在则返回,否则创建新的并注册。

    const s5 = Symbol.for("globalKey");
    const s6 = Symbol.for("globalKey");
    console.log(s5 === s6); // true(全局共享,描述相同则值相同)
    console.log(Symbol.keyFor(s5)); // "globalKey"(获取全局Symbol的描述)
    

35. Symbol作为对象属性有什么优势?如何获取对象的Symbol属性?

一、Symbol作为对象属性的优势
  1. 避免属性名冲突
    Symbol的值唯一,即使属性名的描述相同,也不会覆盖已有属性(解决多模块协作或动态属性场景的冲突问题)。

    const moduleA = { [Symbol("id")]: 1 };
    const moduleB = { [Symbol("id")]: 2 };
    // 合并两个对象时,Symbol属性不会冲突
    const merged = { ...moduleA, ...moduleB };
    console.log(merged[Object.getOwnPropertySymbols(moduleA)[0]]); // 1(属性保留)
    
  2. 隐藏属性
    Symbol属性不会被for...inObject.keys()Object.values()枚举,适合定义“私有”属性(非真正私有,但不易被意外访问)。

    const obj = {public: "可见属性",[Symbol("private")]: "隐藏属性"
    };
    for (const key in obj) {console.log(key); // 仅输出"public"(Symbol属性被忽略)
    }
    
二、获取对象的Symbol属性

需使用专门的API获取:

  1. Object.getOwnPropertySymbols(obj)
    返回对象自身所有Symbol属性的数组。

    const s = Symbol("test");
    const obj = { [s]: "value" };
    const symbols = Object.getOwnPropertySymbols(obj);
    console.log(symbols); // [Symbol(test)]
    console.log(obj[symbols[0]]); // "value"(访问Symbol属性值)
    
  2. Reflect.ownKeys(obj)
    返回对象自身所有属性(包括字符串键和Symbol键)的数组。

    const obj = {a: 1,[Symbol("b")]: 2
    };
    console.log(Reflect.ownKeys(obj)); // ['a', Symbol(b)](包含所有键)
    

36. Set和Map的区别是什么?分别适用于哪些场景?

Set和Map是ES6新增的集合数据结构,核心区别及适用场景如下:

特性SetMap
存储内容唯一的(value)键值对(key-value),键唯一
本质无序的“值的集合”无序的“键值对集合”
常用APIadd()has()delete()sizeset()get()has()delete()size
键的特性无键,值本身具有唯一性键可以是任意类型(包括对象),且键唯一
遍历方式遍历值(values()keys()等价,因无键)遍历键、值或键值对(keys()values()entries()
适用场景:
  • Set

    • 存储不重复的值(如数组去重);
    • 实现数学中的“集合”操作(如交集、并集、差集);
    • 跟踪对象是否存在(如DOM节点的引用集合,避免重复操作)。
    // 数组去重
    const arr = [1, 2, 2, 3];
    const uniqueArr = [...new Set(arr)]; // [1, 2, 3]
    
  • Map

    • 需要键值对映射关系,且键不是字符串(如用对象作为键);
    • 存储复杂数据的关联关系(如缓存数据:键为请求URL,值为响应结果);
    • 频繁添加/删除键值对的场景(性能优于Object)。
    // 用对象作为键
    const objKey = { id: 1 };
    const map = new Map();
    map.set(objKey, "关联数据");
    console.log(map.get(objKey)); // "关联数据"
    

37. Set如何实现数组去重?

Set的核心特性是“存储唯一的值”(重复值会被自动忽略),利用这一特性可简洁实现数组去重。

实现步骤:
  1. 将数组转为Set(自动去重);
  2. 将Set转回数组(通过扩展运算符...Array.from())。
示例代码:
// 基础用法:去重基本类型值
const arr = [1, 2, 2, 3, 3, 3, "a", "a"];
const uniqueArr1 = [...new Set(arr)]; // 扩展运算符转换
const uniqueArr2 = Array.from(new Set(arr)); // Array.from转换
console.log(uniqueArr1); // [1, 2, 3, "a"]// 注意:无法去重引用类型(因对象的引用不同)
const obj1 = { id: 1 };
const obj2 = { id: 1 };
const arrWithObjects = [obj1, obj2, obj1];
const uniqueObjects = [...new Set(arrWithObjects)];
// 结果:[ {id:1}, {id:1}, {id:1} ](obj1和obj2引用不同,未去重)
原理:

Set判断值是否重复的逻辑与===类似,但有一个例外:NaN在Set中被视为相等(而NaN === NaNfalse)。

const arrWithNaN = [NaN, NaN, 1, 1];
console.log([...new Set(arrWithNaN)]); // [NaN, 1](NaN被去重)

38. Map与对象(Object)相比有哪些优势?

Map作为键值对集合,相比传统对象(Object)有以下优势:

  1. 键的类型更灵活
    Object的键只能是字符串或Symbol,而Map的键可以是任意类型(包括数字、对象、函数等)。

    const map = new Map();
    const objKey = { id: 1 };
    map.set(objKey, "value"); // 用对象作为键
    map.set(123, "number key"); // 用数字作为键
    
  2. 键的顺序更明确
    Map会保留键的插入顺序,而Object在ES6前不保证属性顺序(数字键会被优先排序)。

    const map = new Map();
    map.set("b", 2);
    map.set("a", 1);
    console.log([...map.keys()]); // ['b', 'a'](保留插入顺序)const obj = { b: 2, a: 1 };
    console.log(Object.keys(obj)); // ['b', 'a'](现代JS也保留顺序,但历史行为不一致)
    
  3. 更容易获取键值对数量
    Map通过size属性直接获取键值对数量,而Object需要手动计算(如Object.keys(obj).length)。

    const map = new Map([["a", 1], ["b", 2]]);
    console.log(map.size); // 2(直接获取)
    
  4. 更适合频繁添加/删除操作
    Map的set()delete()性能优于Object的属性添加/删除,尤其在键值对数量动态变化时。

  5. 避免原型链污染
    Object会继承原型链上的属性(如toStringhasOwnProperty),可能导致键名冲突;Map无原型链,仅包含自身键值对。

    const obj = {};
    console.log(obj["toString"]); // 函数(继承自原型)const map = new Map();
    console.log(map.has("toString")); // false(无继承属性)
    
  6. 遍历方式更统一
    Map原生支持迭代器,可直接用for...of遍历,而Object需要先获取键数组再遍历。

39. WeakSet和WeakMap的特性是什么?与Set、Map有何区别?

WeakSet和WeakMap是ES6新增的“弱引用”集合,特性及与Set、Map的区别如下:

一、核心特性(WeakSet和WeakMap共有的)
  1. 弱引用
    对存储的对象键(WeakMap)或值(WeakSet)保持弱引用,即不影响垃圾回收(GC)。若对象的其他引用被删除,Weak集合中的对象会被自动回收,释放内存。

  2. 不可枚举
    没有size属性,也不支持keys()values()等遍历方法,无法枚举其中的元素(因元素可能随时被GC回收)。

  3. 只能存储对象
    WeakSet的元素和WeakMap的键必须是对象(不能是原始类型,如数字、字符串)。

二、与Set、Map的区别
特性SetWeakSetMapWeakMap
存储内容任意类型的值仅对象(值)任意类型的键值对键必须是对象
引用类型强引用(阻止GC)弱引用(不阻止GC)强引用(键)弱引用(键)
可枚举性可枚举(有size)不可枚举(无size)可枚举(有size)不可枚举(无size)
常用APIadd/has/deleteadd/has/deleteset/get/has/deleteset/get/has/delete
适用场景去重、集合操作临时存储对象(如DOM节点)键值对映射关联对象元数据(不影响GC)
示例:
// WeakMap示例(键为对象,弱引用)
let obj = { id: 1 };
const weakMap = new WeakMap();
weakMap.set(obj, "metadata");obj = null; // 解除obj的引用,原对象会被GC回收,weakMap中对应的键值对也会消失// WeakSet示例(值为对象,弱引用)
let domNode = document.createElement("div");
const weakSet = new WeakSet();
weakSet.add(domNode);domNode = null; // DOM节点引用被解除,会被GC回收,weakSet中不再包含该节点
适用场景:
  • WeakSet:存储临时对象(如DOM节点),避免内存泄漏。
  • WeakMap:为对象添加元数据(如缓存对象的计算结果),不影响对象的生命周期。

40. 如何遍历Set和Map中的元素?

Set和Map均为可迭代对象(实现了[Symbol.iterator]),可通过多种方式遍历,具体方法如下:

一、遍历Set

Set存储的是“值的集合”,keys()values()返回的迭代器相同(因无键),常用values()或直接遍历。

  1. for...of循环(推荐):

    const set = new Set(["a", "b", "c"]);
    for (const value of set) {console.log(value); // "a" → "b" → "c"
    }
    
  2. forEach()方法

    set.forEach((value, key, self) => {// 注意:Set的forEach回调中,value和key参数相同(因无键)console.log(value); // "a" → "b" → "c"
    });
    
  3. 通过values()/keys()迭代器

    const values = set.values();
    console.log(values.next().value); // "a"
    console.log(values.next().value); // "b"
    
  4. 通过entries()迭代器(返回[value, value]形式的数组):

    for (const [value, sameValue] of set.entries()) {console.log(value, sameValue); // "a" "a" → "b" "b" → "c" "c"
    }
    
二、遍历Map

Map存储的是“键值对”,可分别遍历键、值或键值对。

  1. 遍历键值对(entries(),默认迭代器)

    const map = new Map([["name", "Alice"], ["age", 30]]);// for...of直接遍历(默认使用entries())
    for (const [key, value] of map) {console.log(`${key}: ${value}`); // "name: Alice" → "age: 30"
    }
    
  2. 遍历键(keys()

    for (const key of map.keys()) {console.log(key); // "name" → "age"
    }
    
  3. 遍历值(values()

    for (const value of map.values()) {console.log(value); // "Alice" → 30
    }
    
  4. forEach()方法

    map.forEach((value, key, self) => {console.log(`${key}: ${value}`); // "name: Alice" → "age: 30"
    });
    
总结:
  • Set的遍历以“值”为核心,方法简单;
  • Map的遍历可灵活选择键、值或键值对,适合不同场景(如仅需值时用values(),需键值关系时用entries())。

二、80道ES6 面试题目录列表

文章序号ES6 80道
1 ES6面试题及详细答案80道(01-05)
2 ES6面试题及详细答案80道(06-12)
3 ES6面试题及详细答案80道(13-21)
4 ES6面试题及详细答案80道(22-32)
5 ES6面试题及详细答案80道(33-40)
6 ES6面试题及详细答案80道(41-54)
7 ES6面试题及详细答案80道(55-61)
8 ES6面试题及详细答案80道(62-80)

文章转载自:

http://j94R9hIg.fpqsd.cn
http://rDuh8jhY.fpqsd.cn
http://cjrLcGi7.fpqsd.cn
http://1ctXuyJA.fpqsd.cn
http://G8sC17dk.fpqsd.cn
http://yb2ZQd3n.fpqsd.cn
http://JwJ9DoV4.fpqsd.cn
http://FEobePUn.fpqsd.cn
http://sqAYGbpK.fpqsd.cn
http://2f0Pamt4.fpqsd.cn
http://1bPN9ZGo.fpqsd.cn
http://WMRsqB9G.fpqsd.cn
http://S8PJqfad.fpqsd.cn
http://dulz36v0.fpqsd.cn
http://VaNz73d0.fpqsd.cn
http://9qGwGSBV.fpqsd.cn
http://ELk09QSk.fpqsd.cn
http://Ui5wbVjD.fpqsd.cn
http://xca9c8ts.fpqsd.cn
http://uRLplNat.fpqsd.cn
http://IzRK0p7W.fpqsd.cn
http://Ipx4u7mk.fpqsd.cn
http://HLNYoiFE.fpqsd.cn
http://sA887djK.fpqsd.cn
http://HvynBawj.fpqsd.cn
http://wCMemGpn.fpqsd.cn
http://8mRDrQUR.fpqsd.cn
http://6mXPzWlA.fpqsd.cn
http://6Q6g5qzg.fpqsd.cn
http://AMAyihdm.fpqsd.cn
http://www.dtcms.com/a/376804.html

相关文章:

  • DeepResearch(上)
  • 即时通讯小程序
  • Firefox Window 开发详解(二)
  • Chrome性能黑魔法:深入浅出PGO优化与实战指南
  • 【算法专题训练】20、LRU 缓存
  • 66. 加一 (编程基础0到1)(Leetcode)
  • 多任务相关概念
  • ubuntu 18.04 泰山派编译报错
  • 解决apk包体大于2G无法对齐和签名的问题
  • 运筹学——运输问题之表上作业法,西北角法,最小元素法
  • python版本管理和依赖管理的最佳实践,pyenv + uv
  • iPhon 17 推出
  • MySQL的常用命令
  • KEDA/HPA/VPA 三件套:ABP 后台作业的事件驱动伸缩
  • 金融中的异常收益率
  • 模型部署:(三)安卓端部署Yolov8-v6.0目标检测项目全流程记录
  • 阅读|史蒂芬·普拉达《C Primer Plus(第6版)》:数据和C
  • 回归预测 | MATLAB基于GRU-Attention的多输入单输出回归预测
  • UniApp 分包异步化配置及组件引用解决方案
  • Postman环境变量全局变量设置
  • C语⾔内存函数
  • go资深之路笔记(一) Context
  • 数学建模资源合集
  • STM32项目分享:基于STM32智能吸尘器系统的设计与实现
  • 计算机毕设 java 高校会议室预约管理系统 基于 SSM 框架的高校会议室管理平台 Java+MySQL 的预约全流程管控系统
  • vue-pdf 实现blob数据的预览
  • RiskBird企业信息模糊查询工具
  • 常用PDF转换工具推荐
  • ES6 类与继承:现代 JavaScript 面向对象编程
  • 使用 Docker Buildx 制作并推送双架构镜像