js中的神奇方法Object.defineProperty

Dec 28, 2018 00:00 · 834 words · 2 minute read js object.defineProperty

一年多前开始接触前端,从用原生(html+js+css)的简单页面到使用框架(jquery, vue, angular, ionic)构建的稍微复杂的前端页面/app. 十分感慨前端技术的进步迅速, 今天要说的 Object.deineProperty 其实是ES5.1 就存在的一个js的方法, vue与angular利用它实现了数据与视图的变化绑定(MV)


认识 Object.deineProperty

语法

Object.defineProperty(obj, prop, descriptor)

参数:

  • obj: 要在其上定义属性的对象
  • prop: 要定义或修改的属性的名称
  • descriptor: 将被定义或修改的属性描述符(可选参数)

descriptor的6个属性:

属性名 默认值 作用
configurable false 当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除
enumerable false 是否能被 for in, Object.keys 枚举
value undefine 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等
writable false 当且仅当该属性的writable为true时,value才能被赋值运算符改变
get undefine 一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入this对象(由于继承关系,这里的this并不一定是定义该属性的对象)
set undefine 一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值

阅读官方文档

例子

1.configurable, enumerable, value, writable的使用

/**
 * 先看一个普通的对象定义
 */
var user = {name: 'Simeon'};
Object.getOwnPropertyDescriptor(user, 'name');
// {value: "Tom", writable: true, enumerable: true, configurable: true}

/**
 * 使用 Object.defineProperty 方法定义
 */
var user = {};
Object.defineProperty(user, 'name', {
    value: 'Simeon'
});
Object.getOwnPropertyDescriptor(user, 'name');
// {value: "Simeon", writable: false, enumerable: false, configurable: false} (注意属性的默认值)
console.log(user.name);    // "Simeon"
user.name = 'nobody';
console.log(user.name);    // "Simeon" 这是因为 "writable" 为false
console.log(Object.keys(user)); // "[]" 这是因为 "enumerable" 为false
Object.defineProperty(user, 'name', {
    value: 'Simeon',
    configurable: true,
    enumerable: true,
    writable: true,
}); // 报错: "Uncaught TypeError: Cannot redefine property: name" 这是因为 首次设置的"configurable"为 默认值 false

2.get, set的使用

var user = {};
Object.defineProperty(user, 'name', {
    get: function() {
        console.log('get');
        return user._name;
    },
    set: function(value) {
        console.log('set');
        user._name = value;
    }
})
console.log(user.name);     // get\n undifined
user.name = 'Simeon';       // set
console.log(user.name);     // get\n Simeon

上面的例子还有一种简便的写法

// 这种方式只能在声明时使用
var user = {
    get name() {return this._name;},
    set name(value) {this._name = value;}
};

一个简单的”数据与视图的变化绑定”的实现

直接看源码 直接看Demo