如果我们设置undefined的值会发生什么?

59

这行代码是做什么的?

undefined = 'A value';

如果它不改变undefined的值,那么幕后会发生什么?


如果它不改变undefined的值,那么幕后会发生什么?

31
它没有报错这个事实令人担忧。 - JCOC611
刚刚在控制台尝试了一下,甚至没有出现错误,基本上什么都没发生。https://gyazo.com/6703d9f7768e272c1aad7d3750b08ef1 - vahanpwns
@AshishMishra 不是真的。这只是全局上下文的一个属性。 - Pointy
1
@JCOC611 只有在严格模式下才会抛出错误。 - JLRishe
显示剩余3条评论
4个回答

53

undefined是全局对象的属性,也就是说它是全局范围内的变量。 undefined 的初始值是原始值 undefined

参见 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/undefined

所以,它只是一个变量,没有什么特别之处。现在,回答你的问题:

  1. undefined = 'A value';试图将字符串'A value'赋值给全局变量undefined
  2. 在旧版浏览器中,该值会更改,即undefined === 'A value'; // true。在较新的浏览器中,在严格模式下执行此操作会导致错误。

您可以在浏览器控制台中测试以下内容(我在此使用的是现代浏览器 - Google Chrome):

undefined = true;
console.log(undefined); // undefined
// in older browsers like the older Internet Explorer it would have logged true

上面的例子中,undefined 的值没有改变。这是因为(我强调):

在现代浏览器中(JavaScript 1.8.5 / Firefox 4+),根据 ECMAScript 5 规范,undefined 是一个不可配置的、不可写的属性

在严格模式下:

'use strict';
undefined = true; // VM358:2 Uncaught TypeError: Cannot assign to read only property 'undefined' of object

3
在较新的浏览器中,如果处于“非严格”模式下,会出现什么情况?它不会显示任何错误。它是否有任何作用,因为它也不会改变值。 - C graphics
1
@Cgraphics 在非严格模式下的现代浏览器中,什么也不会发生。该值无法被覆盖,并且没有错误... 但未来可能会改变。 - Oleg
这就是为什么有时会看到使用void运算符 - 它评估其参数,然后返回undefined,因为它是一个运算符,所以不能分配一个值。 因此,您始终可以使用表达式void 0void(0)获取undefined(运算符不需要在参数周围使用括号)。 - Aaron Dufour

28

true123null 等不同,undefined 不是 字面量。这意味着使用 undefined 标识符 并非获取 undefined 值 的绝对可靠方法。相反,可以使用 void运算符,例如 void 0

默认情况下,undefined定义了一个全局对象的属性,即全局变量。在ECMAScript 5之前,该属性是可写的,因此

undefined = "A value";

替换了window.undefined的值,假设它没有被本地变量遮蔽。因此,如果您使用"A value" === undefined,则会得到true。而void 0 === undefined将产生false
ECMAScript 5改变了这种行为,现在该属性既不可写也不可配置。因此,在非严格模式下,对undefined的赋值将被忽略,在严格模式下将引发异常。在幕后,
  1. undefined = "A value"; 是一个 简单赋值
  2. 它使用PutValue将值 "A value" 放入基于全局对象的引用中,引用名称为 "undefined",如果在严格模式下进行赋值,则使用严格标志。
  3. 它调用全局对象的 [[Put]] 内部方法,将属性名设置为 "undefined",将值设置为 "A value",将抛出标志设置为严格标志。
  4. 它调用全局对象的 [[DefineOwnProperty]] 内部方法,将属性名称设置为 "undefined",将属性描述符设置为 {[[Value]]: "A value"},将抛出标志设置为 throw flag。
  5. 如果抛出标志为 true,则会拒绝操作,即抛出 TypeError 异常;否则返回 false。
然而,您仍然可以声明本地的undefined变量:
(function() {
  var undefined = "A value";
  alert(undefined); // "A value";
})();

3
不过,你仍然可以声明本地未定义变量:- 很好的观点! - C graphics
从前,NaN也是一个可以写入的全局变量。 - Edwarric

3

我制作了一个小型的POC,有和没有使用严格模式

效果是,如果你不使用严格模式,一切都很好。 如果你使用严格模式,将会出现一个如下的错误:

TypeError: 无法分配给只读属性'undefined'

现在让我们来看一下这个POC:

"use strict"
var c;

if (c === undefined) {
  console.log("nothing happened")
}

undefined = "goofy"

c = "goofy"

if (c === undefined) {
  console.log("c is 'goofy' and it's equal to undefined.. gosh.. we broke js")
}

现在,正如我所说的,使用严格模式将导致您获得一个TypeError,而删除"use strict"则会使脚本正常运行,并且输出仅为nothing happened
我发现这个问题和答案可能会很有用,如果您想了解更多。
注意:我使用Node.js测试了此代码。

为什么选择Node.js?我以为它只用于服务器端。 - C graphics
2
@Cgraphics node.js使用的是V8引擎,这也是Google Chrome所使用的JavaScript引擎,因此基本上遵循相同的规则,但具有不同的API(浏览器有windowquerySelector等,而node则有globalfs.write等)。 - Oleg
1
由于Node.js是在使用ES6的Google Chrome引擎V8上构建的,因此它似乎是创建POC的最快方法。 :) - fredmaggiowski

0

除了Oriol答案之外

你还可以有一个块级未定义变量

{  
    let emptyVar;
    // console.log(emptyVar === undefined); // Cannot access 'undefined' before initialization
    const undefined = "some value";
    console.log(undefined);
    console.log(void 0); // primitive undefined
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接