【发布时间】:2014-02-14 06:29:48
【问题描述】:
我已经在JavaScript 编程了几个月,主要使用jQuery。我了解 闭包 并且已经使用过它们,但是,我仍然无法理解 在其他语言(例如 >C#。我一直在尝试自学,但在该主题上没有任何结果。有人可以用一些简单的例子来解释我吗?
【问题讨论】:
标签: c# javascript function scope
我已经在JavaScript 编程了几个月,主要使用jQuery。我了解 闭包 并且已经使用过它们,但是,我仍然无法理解 在其他语言(例如 >C#。我一直在尝试自学,但在该主题上没有任何结果。有人可以用一些简单的例子来解释我吗?
【问题讨论】:
标签: c# javascript function scope
在 ES6(当前版本的 JavaScript)之前,JavaScript 只有函数级作用域。也就是如下:
function foo() {
console.log('before block: ' + bar); // prints 'undefined'
if(true) {
var bar = 1;
console.log('inside block: ' + bar); // prints 1
}
console.log('outisde block: ' + bar); // prints 1
}
完全等价于:
function foo() {
var bar;
console.log('before block: ' + bar); // prints 'undefined'
if(true) {
bar = 1;
console.log('inside block: ' + bar); // prints 1
}
console.log('outisde block: ' + bar); // prints 1
}
(事实上,我刚刚展示的就是所谓的“提升”,这正是 JavaScript 所做的:所有变量 声明 都被提升到函数的顶部;赋值是离开他们所在的地方。)
相比之下,像 C# 这样的语言具有块级范围。这会导致编译错误:
public void Foo() {
if(true) {
var foo = 1;
Console.WriteLine("inside block: " + foo);
}
Console.WriteLine("outside block: " + foo); // WILL NOT COMPILE
}
但是你可以拥有这个:
public void Foo() {
var foo = 1;
if(true) {
foo = 2;
Console.WriteLine("inside block: " + foo); // prints 2
}
Console.WriteLine("outside block: " + foo); // prints 2
}
【讨论】:
function scopeTest() {
/* consider this simple for loop
to be the "block" that we were
talking about earlier
*/
for (var i = 0; i <= 5; i++)
{
var inFor = i;
}
alert(inFor); // what happens here?
}
// call the function defined above
scopeTest( );
在上面的代码中,我们有一个名为 inFor 的变量,它在 for 循环中声明。然后我们尝试在 alert 语句的 for 循环之外访问 inFor 变量。
如果上面的代码没有提醒任何东西,那么我们知道这是因为 Javascript 使用了块作用域。在块范围语言中,变量 inFor 在 for 循环之外将不可见。这意味着如果 Javascript 是块范围语言,则调用“alert(inFor);”将无法识别 inFor 变量,并且不会向警告框输出任何内容。
但是,上面的代码实际上输出了一个“5”,这意味着 inFor 变量确实存在于 for 循环之外,这一定意味着 Javascript 没有块范围。这就是我们的答案 - Javascript 没有块作用域。
function scopeTest() {
var x = 2;
//this is always true:
if(x == 2)
{
var y = 15;
for (var i = 0; i <= 5; i++)
{
var inFor = i;
}
}
console.log(y); // y is defined, prints 15
console.log(i); // i is defined, prints 6
console.log(inFor); // inFor is defined, prints 5
}
您可以在上面的代码中看到变量 y、i 和 inFor 是在 if 语句或 for 循环中声明的。但是,即使这些变量是在这些单独的“块”内声明的,它们仍然对函数的其余部分可见。这是因为所有这些变量都在一个函数中声明——这就是函数作用域的全部意义所在。
块范围与函数范围
那么,如果 Javascript 不使用块作用域,那么它使用什么样的作用域呢?
好吧,Javascript 使用了一种叫做函数作用域的东西。
基本上,函数作用域和块作用域之间的区别在于,在使用函数作用域的语言中,函数内声明的任何变量在同一函数内的任何位置都是可见的。但是对于块作用域,变量的可见性仅限于由花括号括起来的任何给定块(无论是 if 语句、where/for 循环等)。
http://www.programmerinterview.com/index.php/javascript/javascript-block-scope/ http://www.programmerinterview.com/index.php/javascript/javascript-function-scope/
{
here you can't access both a and b
var a=1
here you can access only a
{
here you can access only a
var b=3
here you can access both a and b
{
here you can access both a and b
}
here too you can access both a and b
}
here you can access only a
}
here you can't access both a and b
【讨论】:
继续@Ethan Brown 的回答,如果我们使用 let 或 const 而不是 var,我们会得到“referenceError”,因为 let 和 const 是块作用域的。
function foo() {
console.log('before block: ' + bar); // ReferenceError: bar is not defined
if (true) {
let bar = 1; // bar is not let and not var
console.log('inside block: ' + bar); // prints 1
}
console.log('outisde block: ' + bar); // ReferenceError: bar is not defined
}
只是想让答案完整。
【讨论】: