JavaScript参数和作用域

3

对于这篇《JavaScript编程精解》解释中有关参数和作用域的部分,我有点困惑。

它指出,在函数外声明的变量是全局变量,在函数内声明的变量是局部变量,而在函数内部没有前缀var声明的变量实质上引用了同名的全局变量。这很好理解。但是下面这段代码让我感到困惑。

var x = "outside";

var f1 = function() {
  var x = "inside f1";
};
f1();
console.log(x);
// → outside

var f2 = function() {
  x = "inside f2";
};
f2();
console.log(x);
// → inside f2

在第一个函数中注销x的值应该会得到“inside f1”的结果,因为该变量是局部声明的。而第二个函数(包含一个未经var声明的变量,因此引用了在顶部声明的全局变量)应该会得到“outside”的结果。但是,在两种情况下都不是这样。
我大致明白应该发生什么。但除非我读错了,否则似乎与作者描述的相反。这不可能是一个打字错误。
3个回答

3

f1中的x是一个新变量,在f1内部访问,对全局x没有影响。为了更清晰地表示,可以像以下示例代码一样编写:

    var globalX = "outside";
    var f1 = function() {
      var localF1X = "inside f1";
    };
    f1();
    console.log(globalX); // → outside

    var f2 = function() {
      globalX = "inside f2";
    };
    f2();
    console.log(globalX); // → inside f2

1
在JavaScript中,变量的作用域是函数级别(如果您在函数外声明变量,则为全局级别)。
您可以在此处阅读有关JavaScript变量和“提升”的更多信息:http://javascriptissexy.com/javascript-variable-scope-and-hoisting-explained/ 因此:
var x = 'a';
function f1() {
    var x = 1;
    console.log(x);
}

f1(); //outputs 1
console.log(x); //outputs 'a'

function f2() {
    x = 'b';
}

console.log(x); //still outputs 'a'

f2();

console.log(x); //now outputs 'b'

1

在函数内声明的变量只能从该函数内部访问(或者说是局部的)。如果示例代码改为以下形式,则更加清晰:

function f1() {
  var x = "Inside f1"; 
}

console.log(x);

将会导致


ReferenceError: x is not defined

然而,如果一个变量在声明时没有使用var关键字,则会成为一个隐式全局变量(这是不好的实践或者是一个错误):

function f2() {
  y = "Inside f2"; 
}

console.log(y);

会按你期望的工作,同时也声明一个隐式全局变量。

值得一提的是"use strict";,它可以在ES5's Strict Mode中运行代码。通常希望在函数内部声明此代码,这会导致函数在严格模式下运行,并且避免了严格模式的语义与其他代码相互影响

function f3() {
  "use strict";
  z = "Inside f3"; 
}

console.log(z);

会产生

ReferenceError: z is not defined

由于严格模式不允许您声明隐式全局变量。
为了根据您的评论进行澄清,隐式全局变量会“覆盖”彼此。更明确地说,使用JavaScript术语:
  • x = 10将在环境的全局对象x上声明一个属性,对于浏览器环境,这是window.x,对于Node / IO环境,这是global.x
  • x = 20将重新定义上述相同的属性。
这是一个小片段,您可以在任何环境中运行它,以证明这一点。我绝不是在建议您使用隐式全局变量,而是提供另一个示例,说明为什么不应该使用它们。
function functionThatNeedsGreaterThan50(value) {
  // Skip checking the parameter because we trust the 
  // other developers on the team to make sure they call
  // this right. 
}

function f4() {
  q = 42; 
}

function f5() {
  q = 62; 
}

f4();
f5();

console.log(q);

// sometime thousands of calls later, one of which was
f4(); 

// I thought this was 62 but

functionThatNeedsGreaterThan50(q); 

我知道昨晚我接受了这个答案,但是...声明一个隐式全局变量有什么问题吗?我想这样做会使得更难找到由此产生的任何潜在错误的源头。因为全局变量不像其他“正常”的全局变量一样在顶部定义。对吧? - calyxofheld
1
@sabaeus 我也加入了自己的想法。 - jdphenix
所以基本上,为了使用正确的隐式全局变量,您必须首先调用创建它的函数? - calyxofheld
1
隐式全局变量(或者说任何全局变量)容易被改变。如果你只是想确保使用正确的值,最好将其适当地封装在对象或闭包中。 - jdphenix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接