关于Object.defineProperty()理解与使用

该方法允许精确添加或修改对象的属性。通过赋值操作添加的普通属性是可枚举的,能够在属性枚举期间呈现出来(for…in 或 Object.keys 方法), 这些属性的值可以被改变,也可以被删除。这个方法允许修改默认的额外选项(或配置)。默认情况下,使用 Object.defineProperty() 添加的属性值是不可修改的。
Object.defineProperty(obj, prop, descriptor):

  • obj:要在其上定义属性的对象。
  • prop:要定义或修改的属性的名称。
  • descriptor:将被定义或修改的属性描述符。

属性描述符

对象里目前存在的属性描述符有两种主要形式:数据描述符存取描述符。数据描述符是一个具有值的属性,该值可能是可写的,也可能不是可写的。存取描述符是由getter-setter函数对描述的属性。描述符必须是这两种形式之一;不能同时是两者。

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

此外,所有的属性描述符都是非必须的,但是 descriptor 这个字段是必须的,如果不进行任何配置,你可以这样:

var obj = Object.defineProperty({}, "num", {});
console.log(obj.num); // undefined

描述符可同时具有的键值:
描述符属性
如果一个描述符不具有value,writable,get 和 set 任意一个关键字,那么它将被认为是一个数据描述符。如果一个描述符同时有(value或writable)和(get或set)关键字,将会产生一个异常。

默认值总结:
属性默认值

示例:
var o={};//创建一个新对象
Object.defineProperty(o,"a",{
    //该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined
    value:37,
    // 仅当仅当该属性的writable为 true 时,该属性才能被赋值运算符改变。默认为 false
    writable:true,
    //仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。默认为 false
    enumerable:true,
    // 仅当该属性的 configurable 为 true 时,该属性才能够被改变,也能够被删除。默认为 false
    configurable:true
});
// 对象o拥有了属性a,值为37

var bValue;
Object.defineProperty(o,"b",{
    get:function () { return bValue; },
    set:function (v) { bValue=v; },
    enumerable:true,
    configurable:true
});
o.b=45;
数据和视图联动:

给对象o定义新的属性b,并且定义属性b的get和set方法,当o.b的时候会调用b属性的get方法,给b属性赋值的时候,会调用set方法,这就是修改数据的时候,视图会自动更新的关键。
前端获取数据后,需要根据数据操作dom,视图变化后,需要修改不少代码,有没有方法将数据和dom操作隔离,看一个例子,显示用户信息的html模版。

<div>
    <p>你好,<span id='nickName'></span></p>
    <div id="introduce"></div>
</div> 
//视图控制器
var userInfo = {};
Object.defineProperty(userInfo, "nickName", {
    get: function(){
        return document.getElementById('nickName').innerHTML;
    },
    set: function(nick){
        document.getElementById('nickName').innerHTML = nick;
    }
});
Object.defineProperty(userInfo, "introduce", {
    get: function(){
        return document.getElementById('introduce').innerHTML;
    },
    set: function(introduce){
        document.getElementById('introduce').innerHTML = introduce;
    }
});

//数据
//todo 获取用户信息的代码
....

userInfo.nickName = "xxx";
userInfo.introduce = "我是xxx,我来自云南,..."
示例2

传统的做法:

<span id="container">1</span>
<button id="button">点击加 1</button>
document.getElementById('button').addEventListener("click", function(){
    var container = document.getElementById("container");
    container.innerHTML = Number(container.innerHTML) + 1;
});

使用defineProperty:

var obj = {
    value: 1
}
//存储 obj.value 的值的变量
var value = 1;
Object.defineProperty(obj, "value", {
    get: function() {
        return value;
    },
    set: function(newValue) {
        value = newValue;
        document.getElementById('container').innerHTML = newValue;
    }
});
document.getElementById('button').addEventListener("click", function() {
    obj.value += 1;
});

现在的写法,我们还需要单独声明一个变量value 存储 obj.value 的值,因为如果你在 set 中直接 obj.value = newValue 就会陷入无限的循环中。此外,我们可能需要监控很多属性值的改变,要是一个一个写,也很累呐,所以我们简单写个 watch 函数。

var obj = {
    value: 1
}
watch(obj, "value", function(newvalue){
    document.getElementById('container').innerHTML = newvalue;
})
document.getElementById('button').addEventListener("click", function(){
    obj.value += 1
});

watch 函数:

(function(){
    var root = this;
    function watch(obj, name, func){
       //存储value的变量
        var value = obj[name];
        Object.defineProperty(obj, name, {
            get: function() {
                return value;
            },
            set: function(newValue) {
                value = newValue;
                func(value)
            }
        });
        if (value) obj[name] = value
    }
    this.watch = watch;
})()

内容来源及参考博文:
深入浅出Object.defineProperty() - 简书
Object.defineProperty() - [MDN]
Object.defineProperty()方法详解 - 蒋金柱 - 博客园
Object.defineProperty - 乐乐曹 - 简书

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值