【问题标题】:Why does referencing undeclared variables throw a reference exception but referencing undeclared properties doesn't?为什么引用未声明的变量会引发引用异常,而引用未声明的属性却不会?
【发布时间】:2018-04-14 10:20:22
【问题描述】:

Mozilla says that variables are properties of the global object。如果一个对象有一个未定义的属性,那么尝试访问它不会创建引用异常——它只是返回该属性未定义。

如果存在这样一个全局对象 - 那么为什么访问其不存在的属性(即:变量)会产生引用错误?这两种情况的具体区别是什么?

例子:

console.log(x) //x is not declared -> reference error


var x = new Object();
console.log(x.property); //console.log: undefined

【问题讨论】:

    标签: javascript undefined referenceerror


    【解决方案1】:

    tl;dr:访问变量的方式会有所不同,而不是存储方式。


    先介绍一下背景:

    “存储”变量的方式基本上有两种。

    declarative environment 中,变量存储在用户代码无法访问的内部数据结构中。

    object environment 中,变量存储为用户代码可访问对象的属性。全局环境恰好是一个对象环境(它比这更复杂一些,但让它保持简单)。因此全局变量是全局对象的属性。


    那么为什么访问一个不存在的全局变量会引发错误呢?因为变量的存储方式相关,只有变量的访问方式如何。

    foowindow.foo 只是访问全局变量的两种不同方式。

    评估变量的语言规则 (foo) 明确规定,如果变量不存在,则抛出引用错误(同样,不管它是如何存储的)。*

    The language rules 用于评估属性访问 (window.foo) 表示如果该属性不存在,则应返回 undefined

    如果您考虑一下,从一致性的角度来看,这更有意义。访问foo 应该有相同的结果,无论变量存储在声明性环境还是对象环境中。


    *:更准确地说:是 GetValue 函数导致错误被抛出。在解析变量时,GetValue 几乎在任何地方都被调用(例外是typeof 和分组运算符(...))。

    【讨论】:

    • 所以,简短的版本:“为什么”是“因为 JavaScript 的标准是这样说的”,而“为什么”可能是“因为没有人为 JavaScript 做大量计划,所以一致性是白日梦,而这一切都与唾液、吊线和保持向后兼容性的绝望尝试结合在一起”。
    • @ShadowRanger 我看不出有什么不一致的地方。访问可能存在或不存在的字典的键不是错误,并且在它不存在时简单地获取undefined。相反,访问未在任何地方声明的变量肯定是(程序员)错误并证明异常是合理的。
    • @Bergi:我们不是在谈论字典,而是在谈论对象;即使 JS 人经常将它们用作字符串键字典,但这并不意味着这是他们的主要目的。读取任意属性只是愉快地假装它们存在是很奇怪的(需要在理论上提供异常的语言中明确测试缺失,或者在“真实”错误发生很久之后等待它在某个任意时间点失败) .在大多数其他语言中,如果属性不存在,像这样的鸭子类型访问会立即引发错误。
    • @ShadowRanger JS 对象是为 all 目的而设计的 :-) 当然在访问记录字段时抛出异常是有意义的,因此这些相互冲突的选择并不是最优的,但显然,只有一种对象类型的简单性更受重视。
    猜你喜欢
    • 1970-01-01
    • 2021-01-15
    • 1970-01-01
    • 2012-09-21
    • 2021-07-24
    • 1970-01-01
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    相关资源
    最近更新 更多