读取未定义的对象属性时强制 JavaScript 异常/错误

Force JavaScript exception/error when reading an undefined object property?

本文关键字:JavaScript 异常 错误 未定义 对象 属性 读取      更新时间:2023-09-26

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

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

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

我知道我可以检查"在 JavaScript 中检测未定义的对象属性"中提到的"未定义"的相等性,但这似乎很乏味,因为我经常在代码中读取对象字段。

有没有办法在读取未定义的属性时强制抛出错误或异常?

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

这可以使用 ES6 代理来实现:

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

在我看来

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

也就是说,如果你想按照你的建议抛出错误,你需要在你尝试访问的对象上或在全局范围内定义某种自定义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对未定义的变量而不是未定义的对象属性抛出错误,我不能给出比"因为这是语言规范中的内容"更好的答案。对象返回未定义的属性名称的undefined,但未定义的变量引用会引发错误。

有没有办法在我的时候强制抛出错误或异常 读取未定义的属性?

正如之前的回复中所述,使用 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 

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

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

有没有办法在读取未定义的属性时强制抛出错误或异常?

简而言之,没有。 您始终可以通过与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"值,则此速记可能会导致意外行为,并且您只关心它是否返回未定义。

到目前为止,"正确"的解决方案是使用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 语句的主体。

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

参考

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

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

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