我很好奇声明变量和初始化变量的区别,例如:
var example; // this is declaring
var example = "hi" // initializing? Or just "adding a value"?
我不认为我是正确的,但每个术语的确切定义是什么?还是它们基本上意思相同?
我很好奇声明变量和初始化变量的区别,例如:
var example; // this is declaring
var example = "hi" // initializing? Or just "adding a value"?
我不认为我是正确的,但每个术语的确切定义是什么?还是它们基本上意思相同?
编辑:@ThisClark在评论中说了些什么,我去证明他是错的,读完规范后我学到了一些东西:
以下是来自规范的相关内容:
var
语句声明的变量作用域为运行执行上下文的VariableEnvironment。在创建词法环境时创建var
变量,在创建时被初始化为undefined
。[...] 由带有初始化程序的VariableDeclaration定义的变量在执行VariableDeclaration时分配其初始化程序的AssignmentExpression的值,而不是在创建变量时。
根据我的理解,以下几点描述了你在问题中提到的行为(以及术语的“正确-ish”使用):
变量声明(例如,var foo
)会导致该变量在“词法环境”实例化时立即被创建。例如,如果该变量在函数体内定义,则该函数是“词法环境”,因此变量的创建与函数本身的实例化同时发生。
显然,变量声明可以有或没有初始化程序(即,解析为变量初始值的右侧表达式)。不过,这是术语“初始值”的相当非规范化的用法...让我们深入探讨一下:
从技术上讲,根据规范说明,所有变量都使用undefined
值初始化:
变量被创建[...]并初始化为未定义
强调“从技术上讲”,因为如果还提供了一个初始化程序,这在很大程度上是无关紧要的。
根据我们已经讨论的内容,应该明白语句var foo;
可以存在于函数体的任何位置,并且将其移动到同一函数内的其他位置对函数本身的运行时语义没有影响(无论是否存在对foo
的实际赋值或其他引用发生的位置)。如果仍然感到困惑,请重新阅读前面的内容。
最后一部分的行为是最直观的部分,即初始化程序的分配。这个分配是在代码行实际被执行时进行的(再次强调,这并不是变量在技术上得到创建的时间点)。
因此,快速概括一下:
var
声明的变量都在它们的词法环境初始化时始终使用undefined
进行初始化。希望这有所帮助(也希望我没有严重误解规范!)。
@jmar777的回答绝对是规范解释和分析。然而,我发现对于我们这些动手学习者来说,一些示例代码会很有帮助!;)
基本思想
window.varName = value
)。undefined
(即使它们在代码的第一行立即被赋予不同的值)。因此,初始化并不是一个对我们有影响的术语。我们声明和赋值,JavaScript引擎进行初始化。
因此,直接回答您问题中的示例:
var example;
声明一个变量,在初始化期间被赋值为undefined
。var example = "hi"
声明一个变量,最初也被赋值为undefined
,但当执行到该行代码时,它会被重新赋值为字符串"hi"。
示例代码
function testVariableDeclaration() {
// This behaves 'as expected'....
console.log(test2, 'no value assigned yet'); // --> undefined 'no value assigned yet'
// ....but shouldn't our actual expectation instead be that it'll throw an error since
// it doesn't exist yet? See the final console.log() below!
// As we all know....
test1 = 'global var'; // ....a variable assignment WITHOUT declaration in the current
// scope creates a global. (It's IMPLICITLY declared.)
// But a little counter-intuitively....
test2 = 'not global'; // Although this variable also appears to be assigned without
// declaration like 'test1', the declaration for 'test2' that
// appears *later* in the code gets hoisted so that it's already
// been declared in-scope prior to this assignment.
console.log( test1, window.test1 === test1 ); // --> 'global var' TRUE
console.log( test2, window.test2 === test2 ); // --> 'not global' FALSE
var test2; // As shown by the above console.log() outputs, this variable is scoped.
console.log( test3 ); // Throws a ReferenceError since 'test3' is not declared
// anywhere, as opposed to the first console.log() for 'test2'.
}
“范围”对声明/赋值的影响
声明和赋值之间的区别更加明显的原因是,声明一个变量总是在当前作用域内创建一个新变量(myVar
scopeB),即使同名变量已经存在于父级作用域中(myVar
scopeA)。然后我们可以在当前作用域的任何点上给myVar
scopeB赋一个新值而不必重新声明它。(此赋值不会影响myVar
scopeA的值。)一旦到达scopeB的结尾,myVar
scopeB将不再可用于赋值。
另一方面,如果我们在给定作用域内将一个变量赋值,而没有在该作用域中声明它,则赋值将被分配到“作用域链”的下一个声明(如果找不到更高的声明,则隐式声明为全局变量)。
因此,每个作用域只需要声明一次变量,每个声明都会覆盖父级作用域中所做的任何声明(即创建一个不同的变量)。但是,如果要使变量在该作用域内唯一,则必须在该作用域内声明。赋值可以发生多次,但仅影响最“密切声明”的变量(没有更好的术语)。
var
语句将会对任何声明但没有赋值的变量进行初始化,其值为undefined
。
在这两个例子中,您都在声明一个变量。
如果您在不使用var
语句的情况下给变量赋值,它会沿着作用域链寻找已声明的变量,最终回到全局的window
对象。
声明:在相应的作用域内(例如函数内部),使用给定名称注册变量。
初始化:当您声明一个变量时,它会自动初始化,这意味着JavaScript引擎为变量分配内存。
赋值:这是将特定值赋给变量的过程。
let x; // Declaration and initialization
x = "Hello World"; // Assignment
// Or all in one
let y = "Hello World";
Source: SitePoint
你在这里忽略了一个小细节。理解这个概念的一种比喻是这样的:每个变量都必须分配一些值。
如果没有明确说明,默认情况下所有变量的值为未定义(undefined)。
1) let example; // this is declaring and initializing with undefined
2) example="hi"; // this is assigning the value to hi
3) let example = "hi" // this is declaring and initializing with "hi"
因此,第三条语句实际上与1 + 2相同。
现在,可能会出现一个问题,当第三个语句是可能的时,我们为什么需要第一个语句?
原因是扩大变量的范围。
例如,假设在第8行需要一个变量。但是该值直到较晚时刻才在代码块中可用。
1) {
2) let a;
3) try{
4) a=someFunctionWhichMayThroeException();
5) }
6) catch(e){
7) a=100;
8) }
9) someFunctionOnA(a);// the variable is required here
10)
11) }
声明基本上意味着向程序引入一个新实体。初始化是给变量赋予它的第一个值。因此,你上面的例子是正确的。
//equivalent expressions
var ex1;
var ex2 = undefined;
//true!
alert(ex2 === ex1);
目前我不知道也无法测试的是,这个警告框在浏览器历史记录中能够显示多少步。例如,在IE6或某些鲜为人知的黑莓手机上,这个警告框是否有效?我不能确定这是普遍适用的,但至少在撰写本文时,它可以在最新版本的Firefox、Chrome和Safari中正常工作。
var example; // this is declaring
var example = "hi" // initializing? Or just "adding a value"?
它们是两件事,
var example;
的意思是声明了变量 example
,并且初始化为默认值 'undefined'
var example = "hi"
表示 example
被声明并且用字符串 "hi"
进行了初始化。
声明是程序中引入新名称的介绍。
var test; // Is this a declaration ?
初始化是指“赋值”的过程。
var test = {first:"number_one"} // Now that object is initialized with value
undefined
的初始值。你回答中的第二个例子实际上是'赋值',正如你所说,但由于变量可以多次被赋予新值,因此重要的是要注意它并不会在每次赋值时都被'初始化'。它只会被初始化一次。 - Marcus Hughes
example
,定义并赋值为 undefined。example
,定义为字符串并赋值为"hi"
。