【问题标题】:Define getter on object so all undefined property lookups return ""在对象上定义 getter,以便所有未定义的属性查找返回“”
【发布时间】:2018-03-30 02:23:05
【问题描述】:

基本上我需要能够做到这一点:

var obj = {"foo":"bar"},
    arr = [];
with( obj ){
   arr.push( foo );
   arr.push( notDefinedOnObj ); // fails with 'ReferenceError: notDefinedOnObj is not defined'
}
console.log(arr); // ["bar", ""] <- this is what it should be.

我正在寻找 {}.__defineGetter__{get} 的“全局”等效项,以便为所有未定义的属性获取器返回一个空字符串(请注意,这与 undefined 的属性不同)。

【问题讨论】:

  • 你能用proxy吗?
  • 看起来Proxy 在任何节点版本中都不可用。 :-(
  • 是的。看起来 V8 是still working on it
  • Proxy 在 0.7.8 上可用,带有 --harmony 命令行标志。
  • 并且(一辆越野车)Proxy 在节点 0.6.18 中通过 --harmony_proxies 标志可用。

标签: javascript node.js


【解决方案1】:

您可以创建一个Proxy,以便在访问未定义的属性时返回一个空字符串。

app.js:

var obj = {"foo":"bar"},
    arr = [],
    p = Proxy.create({
        get: function(proxy, name) {
            return obj[name] === undefined ? '' : obj[name];
        }
    });
arr.push( p.foo );
arr.push( p.notDefinedOnObj );

console.log(arr);

正如问题作者 David Murdoch 所指出的,如果您使用的是 node v0.6.18(撰写本文时的最新稳定版本),则在运行脚本时必须传递 --harmony_proxies 选项:

$ node --harmony_proxies app.js
[ 'bar', '' ]

请注意,如果您使用 with,此解决方案将不起作用,如下所示:

var obj = {"foo":"bar"},
    arr = [],
    p = Proxy.create({
        get: function(proxy, name) {
            return obj[name] === undefined ? '' : obj[name];
        }
    });
with ( p ) {
   arr.push( foo ); // ReferenceError: foo is not defined
   arr.push( notDefinedOnObj );
}

console.log(arr);

with 在将代理添加到作用域链时似乎没有调用代理的get 方法。

注意:在此示例中传递给Proxy.create() 的代理处理程序是不完整。详情请见Proxy: Common mistakes and misunderstanding

【讨论】:

  • 不同的代理实现无处不在。如果您真的想传递代理,0.6.x 中的代理将不起作用。在 0.7.8 中 Object.getPropertyDescriptor 不存在,即使 getPropertyDescriptor 方法在代理上是必需的,并且在您查找不存在的属性时被调用(您可以通过使用 Object.get**Own**PropertyDescriptor 来伪造它)。
  • 我发现 node-proxy(现在不能在 Windows 上编译,从 here 获取 node-proxy.bin)在 v 0.6.x 上工作,没有任何特殊的命令行标志。但是,您必须从代理上的hasOwn 方法返回true,而不是getPropertyDescriptor。不幸的是,这意味着 if( (name in obj) ) 检查将始终返回 true。
【解决方案2】:

javascript 中没有全局缺失成员处理程序。你需要引入一个函数来抽象出行为

function getOrEmpty(obj, name) {
  if (!obj.hasOwnProperty(name)) {
    return "";
  }
  return obj[name];
}

var obj = {"foo":"bar"},
    arr = [];
arr.push(getOrEmpty(obj, "foo"));
arr.push(getOrEmpty(obj, "someUndefinedProperty"));
console.log(arr);

【讨论】:

  • 对,但是正在运行的代码是用户生成的(来自模板)。此外,getOrEmpty 函数需要调用Object.prototype.hasOwnProperty.call(obj, name),而不是根据未定义检查属性本身的值。 undefined 可能是有意的。
  • p.s.,我建议使用原型的hasOwnProperty 而不是obj,因为如果obj 以某种方式获得hasOwnProperty 属性,则调用将失败。我知道在示例中不可能发生这种情况,但要注意这是一件好事。
  • @DavidMurdoch 我想这就是你建议的原因。但是,如果 javascript 代码开始替换预定义的成员,那么您基本上就完蛋了。不知道他们炸了什么。
【解决方案3】:

使用 ES6 及更高版本,您可以使用 Proxy,就像建议的接受答案一样。但是如果你被 ES5 卡住了,这里有一个答案。

使用 ES5,您必须创建自己的类,就像在这个快速示例中一样

function StrictObject() {
  var values = Object.create(null);
  this.set = function (key, value) {
    values[key] = value;
  };
  this.get = function (key) {
    if (!(key in values)) {
      throw new Error("Could not find " + key);
    }
    return values[key];
  };
}
var obj = new StrictObject();

obj.set('dad', 'homer');
console.log(obj.get('dad'));    // homer
console.log(obj.get('uncle'));  // throws error

【讨论】:

    【解决方案4】:

    Proxy.create 似乎不再存在了。

    这是一个新的例子:

    const p = new Proxy({foo:1}, {
        get(obj, name) {
            return Object.hasOwnProperty.call(obj, name) ? obj[name] : '';
        }
    })
    
    console.log(p.foo);
    console.log(p.bar);

    你可以[ab]用它来做一些有趣的小事,比如创建 React 助手:

    const cc = new Proxy(Object.create(null), {
        get(proxy, name) {
            return ({className,...props}) => React.createElement(name, {className: classcat(className), ...props})
        }
    })
    
    <cc.tr className={[theme.tr,theme.hrow]}>...</cc.tr>
    // renders: <tr class="datatable_tr--2vnM1 datatable_hrow--_PG2G">...</tr>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-04
      • 2021-11-10
      • 2019-06-14
      • 2020-04-30
      • 2018-11-16
      • 1970-01-01
      • 2019-06-17
      • 1970-01-01
      相关资源
      最近更新 更多