MST

星途 面试题库

面试题:JavaScript 复杂场景下属性特性对对象的深度影响

在 JavaScript 中,考虑一个复杂场景:有一个对象 `obj`,其内部嵌套了多层对象和数组结构,且部分属性设置了特定的属性特性(如 `writable: false`、`configurable: false` 等)。现在需要编写一个深度克隆函数 `deepClone`,要求克隆后的对象保持原对象的所有属性特性,并且在克隆过程中如果遇到属性特性为 `configurable: false` 且尝试修改其值的情况,要抛出一个自定义错误。请实现这个 `deepClone` 函数,并详细解释实现思路。
41.3万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试
function deepClone(obj) {
    if (typeof obj!== 'object' || obj === null) {
        return obj;
    }

    const isArray = Array.isArray(obj);
    const clone = isArray? [] : {};

    for (const key in obj) {
        if (Object.hasOwnProperty.call(obj, key)) {
            const desc = Object.getOwnPropertyDescriptor(obj, key);
            if (desc.configurable === false && desc.writable === false) {
                Object.defineProperty(clone, key, {
                   ...desc,
                    value: deepClone(desc.value)
                });
            } else if (desc.configurable === false && desc.writable === true) {
                Object.defineProperty(clone, key, {
                   ...desc,
                    value: deepClone(desc.value)
                });
            } else {
                clone[key] = deepClone(obj[key]);
            }
        }
    }

    return clone;
}

// 测试
const original = {
    a: 1,
    b: {
        c: 2,
        d: {
            e: 3
        }
    },
    f: Object.defineProperty({}, 'g', {
        value: 4,
        writable: false,
        configurable: false
    })
};

try {
    const cloned = deepClone(original);
    console.log(cloned);
    // 尝试修改不可配置且不可写的属性
    cloned.f.g = 5; 
} catch (error) {
    console.error(error.message);
}

实现思路

  1. 基本类型处理:如果传入的 obj 不是对象或者是 null,直接返回 obj,因为基本类型不需要克隆。
  2. 判断数组或对象:使用 Array.isArray 判断 obj 是数组还是对象,然后创建相应类型的空克隆对象 clone
  3. 遍历属性:通过 for...in 循环遍历 obj 的所有属性,并使用 Object.hasOwnProperty.call 确保只处理自身属性。
  4. 获取属性描述符:使用 Object.getOwnPropertyDescriptor 获取每个属性的描述符 desc
  5. 处理不同属性特性
    • 如果 configurablefalsewritablefalse,通过 Object.defineProperty 将该属性以相同特性克隆到 clone 中,同时递归克隆属性值。
    • 如果 configurablefalsewritabletrue,同样通过 Object.defineProperty 克隆属性,并递归克隆属性值。
    • 其他情况(configurabletrue),直接将属性值递归克隆到 clone 中。
  6. 返回克隆对象:最后返回克隆好的对象 clone。在测试部分,尝试修改不可配置且不可写的属性时会触发错误,因为克隆对象保持了原对象的属性特性。