在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
如果原语是不可变的,为什么变量在后一个例子中是可变的?本课程中提供的示例实际上与原语不是不可变的有关,还是仅仅因为函数中的变量名称与传递给函数的参数名称相同?
答案 0 :(得分:4)
值是不可变的,而不是变量。变量可以是常量,但这是一个不同的主题。
价值不变性意味着您无法执行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);
答案 1 :(得分:1)
function changeToEight(n)
将局部变量指定为n
,并且您将changeToEight
函数中的局部变量赋值为8.它不会影响全局n
变量。如果你做过像
function changeToEight(m) {
n = 8; // global variable n is now 8...! but local variable m is 7..!
}
let n = 7;
changeToEight(n);
console.log(n); // 8 cool..!
一切都如预期的那样......