使用变量时到底发生了什么?
What is really happening when using variables?
我有一个非常基本的问题,关于我以前从未关注过的事情:
我注意到,当创建一个使用外部作用域变量的函数(在 JS 或 Python 中)时,该函数不是使用变量的值定义的,而是使用变量本身定义的。因此,如果我更改变量的值,函数将使用新值。
这就是我的意思
let a = 10;
function printA(){
console.log(a);
}
printA(); // => 10
a = 20;
printA(); // => 20
a = 10
def printA():
print(a)
printA() # => 10
a = 20
printA() # => 20
我认为这只适用于对象,因为您可以在函数内修改对象,但不能修改原始变量,因为如果不重新分配它们就无法更改它们的值。我想这是一个不同的故事。
我想了解的是:当输入变量名时输入它的内存地址时我真正在做什么?所有语言都会出现这种情况吗?
when I create a function like printA() that uses a variable that is not an argument, is the variable bound forever to the function by its address?
函数a
变量"captured"。 如何 发生的细节通常是实现细节,可能会导致 compiler/interpreter 生成与原始代码不太相似的代码。
例如,在 C# 中(我知道,不是你提到的语言之一,但它是我最熟悉的语言),编译器将创建一个单独的隐藏 class,它实际上包含字段对于由 lambda 或嵌套函数捕获的变量。然后它访问这些字段而不是普通变量。
by its address
变量通常 没有 地址。例如,每次您调用一个方法时,它通常会创建某种 "activation record",通常会包含它的变量。但请注意,这些记录不在某些 固定 位置,这是您可以并行执行方法、递归等而不受干扰的方式。 (一些较旧的 BASIC 确实有固定的激活记录,这就是它们不允许递归的原因)。这些激活记录通常可以放置在某种 stack.
中
但正如我所说,对于捕获的变量,编译器通常需要做更多的事情,以便这些变量不仅存储在激活记录中,而且 它们的生命周期 不再绑定到单个调用。
我有一个非常基本的问题,关于我以前从未关注过的事情:
我注意到,当创建一个使用外部作用域变量的函数(在 JS 或 Python 中)时,该函数不是使用变量的值定义的,而是使用变量本身定义的。因此,如果我更改变量的值,函数将使用新值。 这就是我的意思
let a = 10;
function printA(){
console.log(a);
}
printA(); // => 10
a = 20;
printA(); // => 20
a = 10
def printA():
print(a)
printA() # => 10
a = 20
printA() # => 20
我认为这只适用于对象,因为您可以在函数内修改对象,但不能修改原始变量,因为如果不重新分配它们就无法更改它们的值。我想这是一个不同的故事。
我想了解的是:当输入变量名时输入它的内存地址时我真正在做什么?所有语言都会出现这种情况吗?
when I create a function like printA() that uses a variable that is not an argument, is the variable bound forever to the function by its address?
函数a
变量"captured"。 如何 发生的细节通常是实现细节,可能会导致 compiler/interpreter 生成与原始代码不太相似的代码。
例如,在 C# 中(我知道,不是你提到的语言之一,但它是我最熟悉的语言),编译器将创建一个单独的隐藏 class,它实际上包含字段对于由 lambda 或嵌套函数捕获的变量。然后它访问这些字段而不是普通变量。
by its address
变量通常 没有 地址。例如,每次您调用一个方法时,它通常会创建某种 "activation record",通常会包含它的变量。但请注意,这些记录不在某些 固定 位置,这是您可以并行执行方法、递归等而不受干扰的方式。 (一些较旧的 BASIC 确实有固定的激活记录,这就是它们不允许递归的原因)。这些激活记录通常可以放置在某种 stack.
中但正如我所说,对于捕获的变量,编译器通常需要做更多的事情,以便这些变量不仅存储在激活记录中,而且 它们的生命周期 不再绑定到单个调用。