【问题标题】:Force JavaScript exception/error when reading an undefined object property?读取未定义的对象属性时强制 JavaScript 异常/错误?
【发布时间】:2011-09-24 14:07:52
【问题描述】:

我是一名经验丰富的 C++/Java 程序员,第一次使用 Javascript。我使用 Chrome 作为浏览器。

我已经创建了几个带有字段和方法的 Javascript 类。当我读取不存在的对象字段时(由于我的拼写错误),Javascript 运行时不会引发错误或异常。显然,这样的读取字段是“未定义的”。例如:

var foo = new Foo();
foo.bar = 1;
var baz = foo.Bar; // baz is now undefined

我知道我可以检查“Detecting an undefined object property in JavaScript”中提到的“未定义”是否相等,但这似乎很乏味,因为我经常在我的代码中读取对象字段。

当我读取未定义的属性时,有什么方法可以强制引发错误或异常?

为什么当我读取未定义的变量(而不是未定义的对象属性)时会引发异常?

【问题讨论】:

  • 看看 JavaScript 代理。
  • 这不会回答这个问题(停止阅读未定义的属性),但是如果您想防止由于错字而意外创建新属性(例如,如果您执行 foo.barr = 1 这会创建一个新的属性栏)。所以如果你想阻止它,你可以调用 Object.preventExtensions(foo);并将其与“严格模式”一起使用 - 应该会引发类型错误。
  • 我建议您查看my answer,如果您觉得满意,请将其标记为已接受。我也遇到了同样的问题,目前,这是克服这个问题的最直接、最简单(干净)的解决方案。

标签: javascript


【解决方案1】:

这可以使用ES6 proxies来实现:

function disallowUndefinedProperties(obj) {
    const handler = {
        get(target, property) {
            if (property in target) {
                return target[property];
            }

            throw new Error(`Property '${property}' is not defined`);
        }
    };

    return new Proxy(obj, handler);
}

// example
const obj = { key: 'value' };
const noUndefObj = disallowUndefinedProperties(obj);

console.log(noUndefObj.key);
console.log(noUndefObj.undefinedProperty); // throws exception

【讨论】:

  • 这有一些不幸的副作用,因为它在检查对象时不起作用(例如,在运行 REPL 或使用 console.log 时)。
  • zealint(下面提到)缓解了这个问题github.com/Bootstragram/zealit/blob/…
  • 哇,太棒了!
  • 这看起来棒极了。这种方法有什么明显的缺点吗?
  • 这太棒了!如果您还想防止意外创建新属性,请设置: Object.preventExtensions(noUndefObj);并使用严格模式
【解决方案2】:

在我看来,这是一个试图将一种语言硬塞进另一种语言范式的经典案例——恕我直言,改变你的编码风格以遵循 Javascript 的工作方式,而不是试图使其符合 C++ 概念和期望。

p>

也就是说,如果您想按照您的建议抛出错误,您需要在您尝试访问的对象上或在全局范围内定义某种自定义 getProperty 函数。实现可能如下所示:

function getProperty(o, prop) {
    if (o.hasOwnProperty(prop)) return o[prop];
    else throw new ReferenceError('The property ' + prop + 
        ' is not defined on this object');
}

var o = {
    foo: 1,
    bar: false,
    baz: undefined
};

getProperty(o, 'foo'); // 1
getProperty(o, 'bar'); // false
getProperty(o, 'baz'); // undefined
getProperty(o, 'foobar'); 
// ReferenceError: The property baz is not defined on this object

但这很丑陋,现在您的所有代码中都有这种自定义语言结构,这使得它的可移植性降低(例如,如果您想将代码的任何部分复制到另一个脚本中,您可以也必须复制你的新函数)并且对其他程序员来说不太易读。所以我真的建议在 Javascript 范式中工作并在访问您需要的属性之前检查 undefined(或设置您的代码,以便预期 false-y 值并且不会破坏事情)。

关于您的第二个问题,为什么 Javascript 会为未定义的变量而不是未定义的对象属性抛出错误,我无法给出比“因为这是语言规范中的内容”更好的答案。 Objects return undefined for undefined property names,但是undefined variable references throw an error

【讨论】:

  • 你完全错了。这里没有什么可以“拔尖”的。 C 结构和 C++/C#/Java 类的行为都正确:如果您尝试读取不存在的字段,编译器将抛出错误。这不是上述语言的一些怪癖;这也是常识。
  • @stackoverflowuser2010 - 我的意见在这里无关紧要,但显然 ECMAScript/Javascript 设计者不同意你的观点。您不妨声称 Javascript 不遵循“常识”,因为它的类型很松散。
  • 完全同意“鞋拔”一词和论点。但是,(此处为特定情况!)在 .net 上下文中,您可以使用 T4 技术自动生成属性访问器(我认为 edmx 文件中的 javascript 中的实体自动生成是一个很好的例子)。这样,代码“不那么难看”了,因为这部分代码只是变成了一个黑盒子,可以解决问题。
  • 这个答案是错误的。考虑o = { really: undefined }getProperty(o, 'really') 会抛出,但不应该。不要使用!== undefined,而是考虑使用if (prop in o)if(o.hasOwnProperty(prop))
  • 目前,我认为最好的答案是使用 Flow 或 Typescript 来强制执行静态类型安全。当我编写原始答案时,这些选项并不真正可用,但它们提供了比 OP 要求的更好的选项 - 通过正确的设置,您可以在编辑器中看到这些错误,而不是在运行时意外命中。
【解决方案3】:

有什么方法可以强制在我的时候抛出错误或异常 读取未定义的属性?

正如之前的回复中所说,使用 ES6 代理是可能的。 我已经完成了小节点模块“zealit”以避免每次都必须实现它。

如果有人感兴趣: https://www.npmjs.com/package/zealit

const zealit = require('zealit')

const ref = { foo: true, bar: undefined }
ref.foo // true 
ref.bar // undefined 
ref.baz // undefined 

const zealed = zealit(ref)
zealed.foo // true 
zealed.bar // undefined 
zealed.baz // throws a ReferenceError 

【讨论】:

    【解决方案4】:

    Firefox 有一个选项javascript.options.strict(在about:config 中)。如果启用此功能,则会在控制台中记录许多常见错误的警告,包括读取未定义的属性、在 if 中使用 = 而不是 == 等。

    (当然,这并不是说这样的代码就一定是错误的。)

    【讨论】:

      【解决方案5】:

      当我读取未定义的属性时,有什么方法可以强制引发错误或异常?

      简而言之,没有。您始终可以通过与undefined 进行比较(如您所说)或尝试访问二级属性来测试您是否以 undefined 结束:

      s = Foo()
      
      s.bar = 1
      
      s['Bar'] // returns undefined.
      
      s['Bar']['Baz'] // Throws TypeError, s.Bar is undefined.
      

      此外,undefined 在条件检查中失败,因此您可以将其作为比较的简写:

      if (s['Bar']) {
        // Something here only if s['Bar'] is set.
      }
      

      请注意,如果设置了 s['Bar'],但它是一个 'Falsey' 值,那么这种简写可能会导致意外行为,并且您只关心它是否返回未定义。

      【讨论】:

      • 而且,正如另一个答案所表明的那样,您因缺少属性而未定义但未声明变量的错误的原因是由于 JavaScript 语言规范。
      【解决方案6】:

      到目前为止,“正确”的解决方案是使用 TypeScript(或其他类型检查库,例如 Flow)。示例:

      const a = [1,2,3];
      
      if (a.len !== 3) console.log("a's length is not 3!");
      

      在 JavaScript 上,此代码将打印“a 的长度不是 3!”。原因是数组上没有 len 这样的属性(请记住,您使用 a.length 而不是 a.len 获得数组的长度)。因此,a.len 将返回 undefined,因此该语句基本上等于:

      if (undefined !== 3) console.log("a's length is not 3!");
      

      由于undefined确实不等于3,所以会运行if语句的主体。

      但是,on TypeScript,您将在“编译时间”(在您的编辑器上,甚至在您运行代码之前)收到错误 Property 'len' does not exist on type 'number[]'

      Reference

      【讨论】:

        【解决方案7】:

        一致性有很大的力量(就像 Stroustrup 在 C++ 中采用的 Alexander Stepanov 的 STL)。未声明属性与未声明变量处理不一致的一个简单原因可能是反映了演变不同语言的思想和努力,另一个可能是相关人员的能力。

        它还会影响您委托给任何给定语言的应用程序类型。例如,您希望不要尝试编写运行价值数百万美元的游轮发动机管理系统的关键任务软件。

        (对于 javascript 爱好者来说,这可能不是一个流行的答案。)

        【讨论】:

        • 这如何回答这个问题?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-10-26
        • 2021-02-22
        • 2016-12-18
        • 2016-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多