Object.defineProperty如何获取和设置对象中所有未知子项

时间:2019-03-03 09:43:48

标签: javascript ecmascript-6

例如,我定义了一个对象obj

var obj = {}
Object.defineProperty(obj, "a", {
  value : 37,
  writable : true,
  enumerable : true,
  configurable : true
});
console.log(obj.a); // => 37

我想访问所有未知的子项,获取相同的值,例如obj.a.b.c.d.e / obj.c.d.e.f.e.... => 37

4 个答案:

答案 0 :(得分:2)

无法返回这样的 number ,因为如果您希望能够无限期地访问更多嵌套键,则每个嵌套属性必须都将返回一个对象。您可以做的是返回一个可以强制转换为所需字符串的对象,可能使用Proxy:

const handler = {
  get(_, prop) {
    return prop === Symbol['toPrimitive']
    ? () => '37'
    : objProx;
  }
}
const objProx = new Proxy({}, handler);

console.log('' + objProx.a); // => '37'
console.log('' + objProx.a.b); // => '37'
console.log('' + objProx.a.b.c.d.e.foobarbaz); // => '37'

答案 1 :(得分:2)

您可以创建一个将另一个函数作为参数的函数。并在try...catch中执行该函数,如果存在则返回该值,如果存在错误则返回一个默认值:

const DEFAULT_VAL = 37;

// get a function and an optional default value to override
function getAnyDepth(func, def) {
    try {
        return func();
    } catch (e) {
        return typeof def !== "undefined" ? def : DEFAULT_VAL;
    }
}

var obj = { a: 45 }

console.log(getAnyDepth(() => obj.a))
console.log(getAnyDepth(() => obj.a.b.c.d.e))
console.log(getAnyDepth(() => obj.c.d.e, { b: 100 }))

Reference: How to avoid "Cannot read property 'name' of undefined" in JavaScript

答案 2 :(得分:1)

如果您的意思是每次访问对象中的未定义键都需要一个默认值,请执行以下操作:

_.defaults(obj, {value: 37"})

或者您可以进行标准比较:

if(typeof obj.a =='undefined'){
  return 37
}

答案 3 :(得分:1)

如果obj.a等于37,则obj.a.b的计算结果为未定义的37.b。但是,如果将37转换为原语(例如通过字符串连接)的结果是可以的,那么您可以创建一个代理。

演示:

// Preparation
function setDefaultProperty(obj, defProp) {
    return new Proxy(obj, {
        get(target, prop) {
            if (prop in target || typeof prop === "symbol") return target[prop];
            return target[defProp];
        }
    });
}

var sink = setDefaultProperty({}, "_default");
sink._default = sink;
sink.valueOf = () => 37;

// Demo

var obj = {};

obj = setDefaultProperty(obj, "_default");
obj._default = sink;

console.log("" + obj.a.b.c.e); // 37
console.log("" + obj.what.ever); // 37