configurable:true ∈ JS原生配置

configurable: true 表示这个属性可以被修改、删除或重新定义! 🔧

🎯 基本含义

Object.defineProperty(p, 'name', {
    configurable: true  // 允许配置更改
})

configurable: true 的作用:

  • 允许删除属性
  • 允许修改属性描述符
  • 允许重新定义属性

🔍 详细解释

1. 允许删除属性

const obj = {};

// 定义可配置属性
Object.defineProperty(obj, 'name', {
    value: '张三',
    configurable: true,  // 允许删除
    writable: true,
    enumerable: true
});

console.log(obj.name); // "张三"

// ✅ 可以删除
delete obj.name;
console.log(obj.name); // undefined

2. 允许修改属性描述符

const obj = {};

Object.defineProperty(obj, 'age', {
    value: 25,
    configurable: true,  // 允许重新配置
    writable: false,     // 初始不可写
    enumerable: true
});

console.log(obj.age); // 25
obj.age = 30;         // ❌ 修改失败(writable: false)
console.log(obj.age); // 25

// ✅ 重新配置属性
Object.defineProperty(obj, 'age', {
    value: 30,
    writable: true,     // 改为可写
    enumerable: true,
    configurable: true
});

obj.age = 35;          // ✅ 现在可以修改
console.log(obj.age);  // 35

3. 与 configurable: false 对比

const obj = {};

// 不可配置的属性
Object.defineProperty(obj, 'id', {
    value: '12345',
    configurable: false,  // 禁止配置更改
    writable: true,
    enumerable: true
});

// ❌ 尝试删除 - 失败(严格模式会报错)
delete obj.id;
console.log(obj.id); // "12345" - 仍然存在

// ❌ 尝试重新配置 - 报错
try {
    Object.defineProperty(obj, 'id', {
        value: '67890',
        writable: true
    });
} catch (error) {
    console.error('错误:', error.message); // 无法重新定义属性
}

// ✅ 但可以修改值(因为 writable: true)
obj.id = '67890';
console.log(obj.id); // "67890"

🎯 属性描述符的完整选项

Object.defineProperty(obj, 'propertyName', {
    // 值相关
    value: 'some value',        // 属性值
    writable: true,            // 是否可修改值

    // 特性相关  
    configurable: true,        // 是否可配置
    enumerable: true,          // 是否可枚举(for...in, Object.keys)

    // 访问器(getter/setter)
    get() { return this._value },
    set(newValue) { this._value = newValue }
});

🔧 实际应用场景

场景1:创建可删除的常量属性

function createConfigurableConstant(obj, key, value) {
    Object.defineProperty(obj, key, {
        value: value,
        writable: false,       // 值不可修改
        enumerable: true,      // 可枚举
        configurable: true     // 但可删除
    });
}

const config = {};
createConfigurableConstant(config, 'API_URL', 'https://api.example.com');

console.log(config.API_URL); // "https://api.example.com"

// ❌ 不能修改值
config.API_URL = '新的URL';  // 静默失败
console.log(config.API_URL); // 仍然是原值

// ✅ 但可以删除
delete config.API_URL;
console.log(config.API_URL); // undefined

场景2:插件系统的配置属性

class PluginSystem {
    constructor() {
        this.plugins = new Map();
    }

    registerPlugin(name, plugin) {
        // 创建可配置的插件属性
        Object.defineProperty(this, name, {
            value: plugin,
            writable: false,       // 防止意外修改
            enumerable: true,     // 在迭代中可见
            configurable: true    // 允许卸载插件
        });

        this.plugins.set(name, plugin);
        plugin.install(this);
    }

    unregisterPlugin(name) {
        if (this.plugins.has(name)) {
            // ✅ 可以删除(因为 configurable: true)
            delete this[name];
            this.plugins.get(name).uninstall();
            this.plugins.delete(name);
        }
    }
}

// 使用示例
const system = new PluginSystem();
system.registerPlugin('logger', {
    install(sys) { console.log('Logger 安装') },
    uninstall() { console.log('Logger 卸载') }
});

console.log(system.logger); // 插件对象
system.unregisterPlugin('logger'); // ✅ 成功卸载

场景3:响应式数据绑定

function defineReactiveProperty(obj, key, value) {
    let internalValue = value;

    Object.defineProperty(obj, key, {
        configurable: true,  // 允许后续重新定义或删除
        enumerable: true,

        get() {
            console.log(`读取 ${key}:`, internalValue);
            return internalValue;
        },

        set(newValue) {
            console.log(`设置 ${key}:`, newValue);
            internalValue = newValue;

            // 触发更新逻辑
            if (typeof this.onChange === 'function') {
                this.onChange(key, newValue);
            }
        }
    });
}

const data = {};
defineReactiveProperty(data, 'username', '张三');

data.username = '李四'; // 控制台输出: 设置 username: 李四
console.log(data.username); // 控制台输出: 读取 username: 李四

// ✅ 以后可以重新定义为计算属性
Object.defineProperty(data, 'username', {
    get() {
        return this.firstName + ' ' + this.lastName;
    },
    configurable: true
});

⚠️ 重要注意事项

1. 默认值

// 普通属性赋值 - 默认所有特性为 true
obj.name = '张三';
// 等价于:
Object.defineProperty(obj, 'name', {
    value: '张三',
    writable: true,
    enumerable: true, 
    configurable: true  // 默认就是 true
});

// Object.defineProperty - 默认所有特性为 false
Object.defineProperty(obj, 'id', { value: '123' });
// 等价于:
Object.defineProperty(obj, 'id', {
    value: '123',
    writable: false,     // 默认 false
    enumerable: false,    // 默认 false  
    configurable: false  // 默认 false
});

2. 一次性操作

const obj = {};

// 第一次定义
Object.defineProperty(obj, 'key', {
    value: 'initial',
    configurable: true  // 允许后续修改
});

// ✅ 可以重新配置
Object.defineProperty(obj, 'key', {
    value: 'modified',
    configurable: false  // 现在设为不可配置
});

// ❌ 不能再修改了(因为 configurable: false)
try {
    Object.defineProperty(obj, 'key', {
        value: 'final'
    });
} catch (e) {
    console.error('无法重新定义不可配置的属性');
}

🎯 在 Vue 中的应用

Vue 2 的响应式系统

// Vue 2 使用 Object.defineProperty 实现响应式
function defineReactive(obj, key, val) {
    const dep = new Dep();  // 依赖收集

    Object.defineProperty(obj, key, {
        configurable: true,  // 允许 Vue 在需要时重新定义
        enumerable: true,

        get() {
            dep.depend();    // 收集依赖
            return val;
        },

        set(newVal) {
            if (newVal === val) return;
            val = newVal;
            dep.notify();    // 通知更新
        }
    });
}

动态添加响应式属性

// Vue 2 中动态添加响应式属性
Vue.set(obj, 'newKey', 'value');

// 内部实现类似:
if (!Object.prototype.hasOwnProperty.call(obj, 'newKey')) {
    // 定义可配置的属性,便于 Vue 管理
    Object.defineProperty(obj, 'newKey', {
        value: 'value',
        configurable: true,  // 允许 Vue 后续管理
        enumerable: true,
        writable: true
    });
}

总结

configurable: true 的含义:

特性 configurable: true configurable: false
删除属性 ✅ 允许 delete obj.prop ❌ 禁止删除
修改描述符 ✅ 允许重新定义 ❌ 禁止修改
修改类型 ✅ 可改为访问器 ❌ 类型固定
Vue 应用 ✅ 适合动态属性 ❌ 适合固定属性

简单记忆:

  • configurable: true = “这个属性可以重新配置”
  • configurable: false = “这个属性已经锁定,不能更改”

在代码中,configurable: true 让这个 name 属性变得灵活,可以被修改或删除! 🎉