首页 > 解决方案 > 从函数内重新分配全局变量

问题描述

在关于 JavaScript 对象的(Udacity)课程的一部分中,它说因为原语是不可变的,所以对函数内部参数所做的任何更改都会有效地创建该函数的本地副本,而不会影响它外部的原语。这是提供的示例:

function changeToEight(n) {
  n = 8; // whatever n was, it is now 8... but only in this function!
}

let n = 7;

changeToEight(n);

console.log(n); // 7

但是,如下例所示,您可以在函数内更改分配给全局变量的值(只要变量名不作为参数传递):

let counter = 1;

function changeCounter() {
  counter = 2;
}

changeCounter();
console.log(counter); // 2

如果原语是不可变的,为什么后一个例子中的变量是可变的?课程中提供的示例实际上是否与原语不可变有关,或者仅仅是因为函数中的变量名称与传递给函数的参数名称相同?

标签: javascript

解决方案


值是不可变的,而不是变量。变量可以是恒定的,但这是一个不同的主题。

值不变性意味着你不能做1 = 2'hello'='world'因为它没有意义(如果你有原始值)。

另一方面,对象是可变的,因此您可以更改它们的内部结构。

obj = {
  name: 'John'
};
obj.name = 'Sue';

但是您也可以通过使用使对象不可变Object.freeze(obj)(请小心,因为这只会产生浅的不变性)。


你的意思是一个constant变量 - 不能重新分配的变量。所以你不能做类似的事情

const x = 1;
x = 2;

但同样,如果它是一个对象,您可以更改存储在常量变量中的值的内部状态(对象属性的更改不算作重新分配)。


在您的第一个示例中,它是原始值还是对象实际上并不重要。即使它是一个对象,也会发生同样的事情。生成本地副本的是重新分配。

function changeToEight(n) {
  n = [8]; 
}

let n = [7];
changeToEight(n);
console.log(n);

只有对该对象的就地更改不会产生具有相同名称的新局部变量(例如:Array.prototype.push方法,如果我们考虑一个数组)。

function changeToEight(n) {
  n.push(8); 
}

let n = [7];
changeToEight(n);
console.log(n);


您的第二个示例不同,因为函数changeChouter没有自己的局部变量,称为n. 根据作用域解析规则,变量被引用时,首先在本地作用域中搜索,如果失败,则在下一个封闭作用域中搜索它们。

该变量n,因为它不是您的函数的本地变量,所以在changeChouter的封闭范围内搜索,在这种情况下,它是在全局范围内找到的。这意味着您正在重新分配该全局变量。

所以你的代码基本上相当于

let counter = 1;

counter = 2;

console.log(counter);


推荐阅读