Object.defineProperty遇到的问题

问题描述

  • 在给对象中的引用对象继续定义时候的失效问题

附上代码

    var obj = {};
    function defineObj(obj, key, v) {
        Object.defineProperty(obj, key, {
            set: function (newv) {
                console.log("set",this);
                v = newv;
            },
            get: function () {
                console.log("get",this);
                return v;//疑点在这里,现在是形参传入进来形成闭包,实现了私有的持久化变量
            }
        })
    }
    defineObj(obj,"data",{num:111});
    defineObj(obj.data,"num",222);
    console.log("----------------------------------------------------------------");
    console.log("result:",obj.data.num);

而这样连续给内部引用对象赋值,调用最终对象的值,就会打印出访问这个值所需要的引用步骤数目的get
图片描述

如上,obj.data---1次 obj.data.num---两次
实际记录这个次数主要为了验证给obj.data定义属性num是否生效,如上是可以的
但是如果把代码改成这样

    var obj = {};
    function defineObj(obj, key, v) {
        Object.defineProperty(obj, key, {
            set: function (newv) {
                console.log("set",this);
                v = newv;
            },
            get: function () {
                console.log("get",this);
                return {num:333};//在get中强制返回定义好的对象字面量
            }
        })
    }
    defineObj(obj,"data",{num:111});
    defineObj(obj.data,"num",222);//没生效
    console.log("----------------------------------------------------------------");
    console.log("result:",obj.data.num);

而这时返回的结果是
图片描述
如上,再次给obj.data定义num这一步并没有生效,也就是说一旦在get中返回了声明好的字面量,那后续对这个字面量的扩展就无效了,所以想问下这个是什么原因

自己理解的可能原因:

  • 一 因为defineProperty使用访问器描述符创建属性的时候,使用set和get,而定义的这个参数需要set和get都能访问到,类似上面第一段代码中形参v,意思就是我我可拿到这个v给你赋值,也可以给你返回(感觉有些牵强)
    defineProperty文档中:

链接描述
图片描述

  • 二 obj.data.num这个属性的描述configurable是否可以继续定义set和get
    var obj = {};
    function defineObj(obj, key, v) {
        Object.defineProperty(obj, key, {
            set: function (newv) {
                console.log("set",this);
                v = newv;
            },
            get: function () {
                console.log("get",this);
                return v;
            }
        })
    }
    defineObj(obj,"data",{num:111});
    console.log("属性描述:",Object.getOwnPropertyDescriptor(obj.data,"num"));
    defineObj(obj.data,"num",222);
    console.log("----------------------------------------------------------------");
    console.log("result:",obj.data.num);

图片描述

    var obj = {};
    function defineObj(obj, key, v) {
        Object.defineProperty(obj, key, {
            set: function (newv) {
                console.log("set",this);
                v = newv;
            },
            get: function () {
                console.log("get",this);
                return {num:333};
            }
        })
    }
    defineObj(obj,"data",{num:111});
    console.log("属性描述:",Object.getOwnPropertyDescriptor(obj.data,"num"));
    defineObj(obj.data,"num",222);
    console.log("----------------------------------------------------------------");
    console.log("result:",obj.data.num);

图片描述
两种定义方式num的属性描述都一样。。。。

阅读 4.9k
1 个回答

第二种情况的defineObj(obj.data,"num",222);js内部执行了这句话,之所以你访问obj.data.num的时候输出的是333,跟你定义obj.data时的get方法有关。

//你强制返回来了一个{num:333}对象
get: function () {
    console.log("get",this);
    return {num:333};
}

//也就是说你每次访问obj.data都会返回{num:333},关键还在于每次返回的对象是个新对象,这意味着:
obj.data===obj.data               //false,这是两个不同的对象,即使看起来它们是一样的
defineObj(obj.data,"num",222)     //这句话表示你定义了这个时候的obj.data的num属性;
console.log("result:",obj.data.num);   
//可是当你再次访问obj.data.num时,它会先获取obj.data值此时这又是一个新的{num:333}对象,因此你再访问num属性时,返回的是333
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题