《前后端面試題
》專欄集合了前后端各個知識模塊的面試題,包括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新增的一種原始數據類型,用于表示獨一無二的值,不屬于任何其他類型(如字符串、數字等)。它的核心特性如下:
-
唯一性:即使兩個Symbol的描述相同,它們也是不同的。
const s1 = Symbol("test"); const s2 = Symbol("test"); console.log(s1 === s2); // false
-
不可枚舉性:Symbol作為對象屬性時,不會被
for...in
、Object.keys()
等方法枚舉,也不會被JSON.stringify()
序列化。const obj = {[Symbol("id")]: 123,name: "test" }; console.log(Object.keys(obj)); // ['name'](Symbol屬性未被枚舉)
-
不能與其他類型直接運算:Symbol值不能與字符串、數字等進行拼接或算術運算,否則會報錯。
const s = Symbol("a"); // console.log(s + "b"); // TypeError: Cannot convert a Symbol value to a string
-
可作為對象屬性的鍵:解決對象屬性名沖突問題(如多模塊協作時避免屬性覆蓋)。
-
無法被實例化:Symbol是原始類型,不能用
new
操作符創建(new Symbol()
會報錯)。
34. 如何創建一個Symbol類型的值?如何為其添加描述?
創建Symbol值的方式及添加描述的方法如下:
一、創建Symbol值
通過Symbol()
函數創建,注意不能使用new
關鍵字(因Symbol是原始類型,非對象)。
const s = Symbol(); // 創建一個無描述的Symbol
console.log(typeof s); // "symbol"(特殊的原始類型)
二、為Symbol添加描述
Symbol()
函數可接收一個字符串作為描述(description),用于調試時區分不同的Symbol(不影響其唯一性)。
-
直接傳入描述字符串:
const s1 = Symbol("userName"); // 描述為"userName" const s2 = Symbol("age"); // 描述為"age"
-
通過
description
屬性獲取描述:console.log(s1.description); // "userName"(ES2019新增屬性)
-
注意:描述相同的Symbol仍是不同的值:
const s3 = Symbol("id"); const s4 = Symbol("id"); console.log(s3 === s4); // false(描述相同但值不同)
-
通過
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作為對象屬性的優勢
-
避免屬性名沖突:
Symbol的值唯一,即使屬性名的描述相同,也不會覆蓋已有屬性(解決多模塊協作或動態屬性場景的沖突問題)。const moduleA = { [Symbol("id")]: 1 }; const moduleB = { [Symbol("id")]: 2 }; // 合并兩個對象時,Symbol屬性不會沖突 const merged = { ...moduleA, ...moduleB }; console.log(merged[Object.getOwnPropertySymbols(moduleA)[0]]); // 1(屬性保留)
-
隱藏屬性:
Symbol屬性不會被for...in
、Object.keys()
、Object.values()
枚舉,適合定義“私有”屬性(非真正私有,但不易被意外訪問)。const obj = {public: "可見屬性",[Symbol("private")]: "隱藏屬性" }; for (const key in obj) {console.log(key); // 僅輸出"public"(Symbol屬性被忽略) }
二、獲取對象的Symbol屬性
需使用專門的API獲取:
-
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屬性值)
-
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新增的集合數據結構,核心區別及適用場景如下:
特性 | Set | Map |
---|---|---|
存儲內容 | 唯一的值(value) | 鍵值對(key-value),鍵唯一 |
本質 | 無序的“值的集合” | 無序的“鍵值對集合” |
常用API | add() 、has() 、delete() 、size | set() 、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的核心特性是“存儲唯一的值”(重復值會被自動忽略),利用這一特性可簡潔實現數組去重。
實現步驟:
- 將數組轉為Set(自動去重);
- 將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 === NaN
為false
)。
const arrWithNaN = [NaN, NaN, 1, 1];
console.log([...new Set(arrWithNaN)]); // [NaN, 1](NaN被去重)
38. Map與對象(Object)相比有哪些優勢?
Map作為鍵值對集合,相比傳統對象(Object)有以下優勢:
-
鍵的類型更靈活
Object的鍵只能是字符串或Symbol,而Map的鍵可以是任意類型(包括數字、對象、函數等)。const map = new Map(); const objKey = { id: 1 }; map.set(objKey, "value"); // 用對象作為鍵 map.set(123, "number key"); // 用數字作為鍵
-
鍵的順序更明確
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也保留順序,但歷史行為不一致)
-
更容易獲取鍵值對數量
Map通過size
屬性直接獲取鍵值對數量,而Object需要手動計算(如Object.keys(obj).length
)。const map = new Map([["a", 1], ["b", 2]]); console.log(map.size); // 2(直接獲取)
-
更適合頻繁添加/刪除操作
Map的set()
、delete()
性能優于Object的屬性添加/刪除,尤其在鍵值對數量動態變化時。 -
避免原型鏈污染
Object會繼承原型鏈上的屬性(如toString
、hasOwnProperty
),可能導致鍵名沖突;Map無原型鏈,僅包含自身鍵值對。const obj = {}; console.log(obj["toString"]); // 函數(繼承自原型)const map = new Map(); console.log(map.has("toString")); // false(無繼承屬性)
-
遍歷方式更統一
Map原生支持迭代器,可直接用for...of
遍歷,而Object需要先獲取鍵數組再遍歷。
39. WeakSet和WeakMap的特性是什么?與Set、Map有何區別?
WeakSet和WeakMap是ES6新增的“弱引用”集合,特性及與Set、Map的區別如下:
一、核心特性(WeakSet和WeakMap共有的)
-
弱引用:
對存儲的對象鍵(WeakMap)或值(WeakSet)保持弱引用,即不影響垃圾回收(GC)。若對象的其他引用被刪除,Weak集合中的對象會被自動回收,釋放內存。 -
不可枚舉:
沒有size
屬性,也不支持keys()
、values()
等遍歷方法,無法枚舉其中的元素(因元素可能隨時被GC回收)。 -
只能存儲對象:
WeakSet的元素和WeakMap的鍵必須是對象(不能是原始類型,如數字、字符串)。
二、與Set、Map的區別
特性 | Set | WeakSet | Map | WeakMap |
---|---|---|---|---|
存儲內容 | 任意類型的值 | 僅對象(值) | 任意類型的鍵值對 | 鍵必須是對象 |
引用類型 | 強引用(阻止GC) | 弱引用(不阻止GC) | 強引用(鍵) | 弱引用(鍵) |
可枚舉性 | 可枚舉(有size) | 不可枚舉(無size) | 可枚舉(有size) | 不可枚舉(無size) |
常用API | add/has/delete | add/has/delete | set/get/has/delete | set/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()
或直接遍歷。
-
for...of
循環(推薦):const set = new Set(["a", "b", "c"]); for (const value of set) {console.log(value); // "a" → "b" → "c" }
-
forEach()
方法:set.forEach((value, key, self) => {// 注意:Set的forEach回調中,value和key參數相同(因無鍵)console.log(value); // "a" → "b" → "c" });
-
通過
values()
/keys()
迭代器:const values = set.values(); console.log(values.next().value); // "a" console.log(values.next().value); // "b"
-
通過
entries()
迭代器(返回[value, value]
形式的數組):for (const [value, sameValue] of set.entries()) {console.log(value, sameValue); // "a" "a" → "b" "b" → "c" "c" }
二、遍歷Map
Map存儲的是“鍵值對”,可分別遍歷鍵、值或鍵值對。
-
遍歷鍵值對(
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" }
-
遍歷鍵(
keys()
):for (const key of map.keys()) {console.log(key); // "name" → "age" }
-
遍歷值(
values()
):for (const value of map.values()) {console.log(value); // "Alice" → 30 }
-
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) |