不评估访问器检测 Object.defineProperty 是否有链式数据描述符

Without evaluating accessor detect if Object.defineProperty has a chained data descriptor

在下面的示例代码中,我想检测 属性 ('cv') 是否进一步链接到其他描述符。在处理数据描述符时,这会陷入困境,并且没有尽头,因为 JS 会无限地返回数据描述符。如果在链的深处某处存在访问器,我们可以通过测试是否定义了访问器函数来检测它。

objective 是使用值 属性 的描述符复制描述符的值 属性 ,将其保存在某个地方并使用访问器描述符稍后访问保存的值.但是这需要在不实际调用任何深层访问器的情况下完成(最终返回一个最终将过时的计算值)。以下将不起作用

var newDescriptor = {
  value : oldDescriptor.value
}

以下

var newDescriptor = {}
Object.defineProperty(newDescriptor, value, Object.getOwnPropertyDescriptor(oldDescriptor, 'value'));

可能有效,但在一次又一次调用时最终会出现一堆不必要的描述符链,最终可能会耗尽内存。但是这个解决方案还需要检测是否已经为描述符设置了这样的链,并且可能通过获取叶级数据描述符来减少它们。这就把我们带到了数据描述符的兔子洞!

真正的用例是当一个明显的数据描述符可能不是这样并且已经有一个深层访问器链接时,将现有的数据描述符转换为访问器描述符。我可能缺少其他更好的解决方法。

代码示例

var ob = {cv : 5};
console.log(" ob.cv : " + ob.cv ); // Returns 5  
var cvd1 = Object.getOwnPropertyDescriptor(ob, 'cv');
console.dir( cvd1 ); 
var cvd2 = Object.getOwnPropertyDescriptor(cvd1, 'value');
console.dir( cvd2 ); 
var cvd3 = Object.getOwnPropertyDescriptor(cvd2, 'value');
console.dir( cvd3 ); 

// Deepest chained accessor descriptor
var deepAccessorDescriptor = {};
Object.defineProperty(deepAccessorDescriptor, 'value', { 
  get  : function() { return 74 ; }
} );

// Chained data descriptor
var chainedDataDescriptor = {};
Object.defineProperty(chainedDataDescriptor, 'value', deepAccessorDescriptor );
Object.defineProperty(ob, 'cv', chainedDataDescriptor);
console.log(" ob.cv : " + ob.cv ); // Returns 74 from deepAccessorDescriptor 

不能链接描述符。就这么简单。

当您调用 Object.defineProperty 时,它不会存储您传递的描述符对象 - 它只是查看它并将相关的东西存储在 属性.[=16= 的属性中]

当您调用 Object.getOwnPropertyDescriptor 时,它不会访问以前存储的对象。它检查 属性 的属性,并 创建一个新对象 ,其中包含纯数据属性来描述属性。

var deepDescriptor = {};
Object.defineProperty(deepDescriptor, 'value', { 
  get() {
    console.log("evaluated");
    return 74;
  }
});
console.log("descriptor created");
var ob = {};
Object.defineProperty(ob, 'cv', deepDescriptor);
console.log("property defined");
console.log("ob.cv", ob.cv);

您可以看到 deepDescriptor.value getter 是在 Object.defineProperty(…, deepDescriptor) 调用期间计算的,而不是在 ob.cv 访问期间计算的。