前端面試手寫練習 - set
- 文章發表於
問題
在前篇我們提到了如何透過 前端面試手寫練習 - get 來讀取物件中深層嵌套的屬性。
本篇我們將會來實作一個可以新增或更新深層嵌套物件中屬性的函式 set
,此函式接受一個物件、一個路徑字串或路徑陣列,以及一個值。如果路徑存在,則設置路徑對應的值,否則創建路徑。
function set(obj: Object, path: string | Array<string>, value: any): void;
範例
假設今天我們要更改 user
這個物件裡 firstName
的值,我們可能會這樣寫:
const user = {profile: {name: { firstName: 'John', lastName: 'Doe' },age: 99,},}user.profile.name.firstName = 'Jane'
這看起來非常直觀,然而在現實開發中,我們沒辦法確保 profile
、name
是否存在,如果直接更改可能會導致像 TypeError: Cannot set property 'firstName' of undefined
的錯誤。
而 set
函式可以幫助我們避免這個問題:
set(user1, 'profile.name.firstName', 'Jane')console.log(user1.profile.name.firstName) // 'Jane'
甚至當 profile
、name
不存在時,set
函式會自動幫我們創建這些路徑。
const user2 = {}set(user2, 'profile.name.firstName', 'Jane')console.log(user2.profile.name.firstName) // 'Jane'console.log(user2) // { profile: { name: { firstName: 'Jane' } } }
練習區
在了解問題後,可以嘗試先寫下您的思路,再到下方的練習區域實際寫出程式碼。
筆者思路
- 首先我們需要判斷
path
是否為字串,如果是字串則將其轉換為陣列。 - 建立一個指標
pointer
指向物件obj
。 - 遍歷
path
陣列,對於每個元素p
:- 如果
pointer
中不存在p
或pointer[p]
不是物件,則根據下一個 path 的類型創建一個空物件或空陣列。 - 將
pointer
指向pointer[p]
。
- 如果
- 將
pointer
的最後一個元素設置為value
。
筆者解答
function set(obj, path, value) {path = Array.isArray(path) ? path : path.replace('[', '.').replace(']', '').split('.')let pointer = objfor (let i = 0; i < path.length - 1; i++) {const currPath = path[i]if (!Reflect.has(pointer, currPath) || typeof pointer[currPath] !== 'object') {const next = path[i + 1]pointer[currPath] = String(Number(next)) === next ? [] : {}}pointer = pointer[currPath]}pointer[path[path.length - 1]] = value}