function:JavaScript中的变量范围是什么?

javascript中的变量范围是什么?它们内部的作用域是否与外部的作用域相同?或者这真的很重要吗?此外,如果变量是全局定义的,那么它们存储在哪里?


我想我能做的就是给你们举一些例子来学习。Javascript程序员实际上是根据他们对范围的理解程度来排名的。它有时可能与直觉相反。

一个全局范围的变量

1
2
3
4
5
6
// global scope
var a = 1;

function one() {
  alert(a); // alerts '1'
}

局部作用域

1
2
3
4
5
6
7
8
9
10
11
12
// global scope
var a = 1;

function two(a) { // passing (a) makes it local scope
  alert(a); // alerts the given argument, not the global value of '1'
}

// local scope again
function three() {
  var a = 3;
  alert(a); // alerts '3'
}

中间体:JavaScript (ES5;ES6介绍let)

一个。

1
2
3
4
5
6
7
8
9
var a = 1;

function four() {
  if (true) {
    var a = 4;
  }

  alert(a); // alerts '4', not the global value of '1'
}

b。

1
2
3
4
5
6
7
8
9
var a = 1;

function one() {
  if (true) {
    let a = 4;
  }

  alert(a); // alerts '1' because the 'let' keyword uses block scoping
}

中级:对象属性

1
2
3
4
5
6
7
var a = 1;

function Five() {
  this.a = 5;
}

alert(new Five().a); // alerts '5'

高级:关闭

1
2
3
4
5
6
7
8
9
10
11
var a = 1;

var six = (function() {
  var a = 6;

  return function() {
    // JavaScript"closure" means I have access to 'a' in here,
    // because it is defined in the function in which I was defined.
    alert(a); // alerts '6'
  };
})();

高级:基于原型的范围解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var a = 1;

function seven() {
  this.a = 7;
}

// [object].prototype.property loses to
// [object].property in the lookup chain. For example...

// Won't get reached, because 'a' is set in the constructor above.
seven.prototype.a = -1;

// Will get reached, even though 'b' is NOT set in the constructor.
seven.prototype.b = 8;

alert(new seven().a); // alerts '7'
alert(new seven().b); // alerts '8'

全局+局部:一个额外的复杂情况

1
2
3
4
5
6
7
var x = 5;

(function () {
    console.log(x);
    var x = 10;
    console.log(x);
})();

这将输出undefined10,而不是510,因为JavaScript总是将变量声明(而不是初始化)移到作用域的顶部,使得代码等价于:

1
2
3
4
5
6
7
8
var x = 5;

(function () {
    var x;
    console.log(x);
    x = 10;
    console.log(x);
})();

抓住clause-scoped变量

1
2
3
4
5
6
7
8
var e = 5;
console.log(e);
try {
    throw 6;
} catch (e) {
    console.log(e);
}
console.log(e);

这将打印出565。在catch子句e中隐藏全局和局部变量。但是这个特殊的作用域只适用于捕获的变量。如果您在catch子句中编写var f;,那么它与您在try-catch块之前或之后定义它完全相同。


Javascript使用范围链来为给定的函数建立范围。通常有一个全局范围,每个定义的函数都有自己的嵌套范围。在另一个函数中定义的任何函数都有一个局部作用域,该作用域链接到外部函数。定义范围的总是源中的位置。

作用域链中的元素基本上是一个映射,带有指向其父作用域的指针。

当解析一个变量时,javascript从最内层的作用域开始,并向外搜索。


全局声明的变量具有全局作用域。在函数中声明的变量的作用域是该函数,以及同名的影子全局变量。

(我敢肯定,真正的JavaScript程序员能够在其他答案中指出许多细微之处。我特别注意到这一页关于this在任何时候的确切含义。不过,希望这个介绍性的链接足以让你开始学习。)


老派JavaScript

传统上,JavaScript实际上只有两种类型的作用域:

全局范围:变量在整个应用程序中都是已知的,从应用程序开始(*)函数作用域:从函数(*)开始,变量在函数中声明的函数中是已知的。

我不会详细说明这一点,因为已经有许多其他的答案可以解释这种差异。

现代JavaScript

最新的JavaScript规范现在还允许第三个作用域:

块作用域:变量在声明它们的块中是已知的,从它们被声明的那一刻起(**)我如何创建块范围变量

传统上,你这样创建变量:

1
var myVariable ="Some text";

块范围变量是这样创建的:

1
let myVariable ="Some text";

那么,函数作用域和块作用域有什么区别呢?

要理解函数范围和块范围之间的区别,请考虑以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

在这里,我们可以看到我们的变量j只在第一个for循环中被知道,而不是在之前和之后。然而,我们的变量i在整个函数中是已知的。

此外,请考虑块作用域变量在声明之前是未知的,因为它们没有挂起。还不允许在同一个块中重新声明相同的块作用域变量。这使得块作用域变量比全局作用域变量或函数作用域变量更不容易出错,全局作用域变量被挂起,并且在多次声明时不会产生任何错误。

现在使用block scope变量安全吗?

现在使用是否安全,取决于你所处的环境:

如果正在编写服务器端JavaScript代码(Node.js),可以安全地使用let语句。

如果您正在编写客户端JavaScript代码并使用转置器(如Traceur),您可以安全地使用let语句,但是就性能而言,您的代码可能不是最优的。

如果您正在编写客户端JavaScript代码而不使用转置器,那么您需要考虑浏览器支持。

今天,2016年2月23日,这些浏览器要么不支持let,要么只支持部分:

internetexplorer10及以下版本(不支援)firefox43及以下版本(不支援)Safari 9及以下版本(不支持)Opera Mini 8及以下版本(不支持)Android浏览器4及以下版本(不支持)Opera 36及以下版本(部分支援)Chome 51及以下(部分支持)

enter image description here

如何跟踪浏览器支持

在阅读本文时,有关哪些浏览器支持let语句的最新概述,请参见这个Can I Use页面。

(*)全局变量和函数作用域变量可以在声明之前初始化和使用,因为JavaScript变量是挂起的。这意味着声明总是位于范围的顶部。

(**)块范围的变量不挂起


这里有一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script>

var globalVariable = 7; //==window.globalVariable

function aGlobal( param ) { //==window.aGlobal();
                            //param is only accessible in this function
  var scopedToFunction = {
    //can't be accessed outside of this function

    nested : 3 //accessible by: scopedToFunction.nested
  };

  anotherGlobal = {
    //global because there's no `var`
  };

}

</script>

您将研究闭包,以及如何使用闭包创建私有成员。


据我所知,关键在于Javascript具有函数级范围,而不是更常见的C块范围。

这是一篇关于这个主题的好文章。


在"Javascript 1.7"(Mozilla对Javascript的扩展)中,还可以使用let语句声明块范围变量:

1
2
3
4
5
 var a = 4;
 let (a = 3) {
   alert(a); // 3
 }
 alert(a);   // 4


最初由Brendan Eich设计的JavaScript中的作用域概念来自于HyperCard脚本语言HyperTalk。

在这种语言中,显示类似于一堆索引卡。有一张万事达卡被称为背景。它是透明的,可以看作是底部的卡片。此基本卡上的任何内容都是通过放置在其上的卡片共享的。每一张放在上面的卡片都有自己的优先于前一张卡片的内容,但是如果需要,仍然可以访问前一张卡片。

这正是JavaScript作用域系统的设计方式。只是名字不同。JavaScript中的卡片称为执行上下文ECMA。每个上下文都包含三个主要部分。变量环境、词汇环境和这个绑定。回到卡片引用,词法环境包含堆栈中较低位置的先前卡片的所有内容。当前上下文位于堆栈的顶部,其中声明的任何内容都将存储在变量环境中。在命名冲突的情况下,变量环境将优先考虑。

这个绑定将指向包含的对象。有时范围或执行上下文会在不改变包含对象的情况下改变,例如在声明的函数中,包含对象可能是window或构造函数。

这些执行上下文是在传输控制时创建的。控制在代码开始执行时转移,这主要是通过函数执行完成的。

这就是技术上的解释。在实践中,在JavaScript中记住这一点很重要

范围在技术上是"执行上下文"上下文构成存储变量的环境堆栈堆栈的顶部优先(底部是全局上下文)每个函数都创建一个执行上下文(但并不总是一个新的this绑定)

将此应用于前面的示例之一(5。在这个页面上,可以跟随执行上下文的堆栈。在本例中,堆栈中有三个上下文。它们由外部上下文、var six调用的立即调用函数中的上下文以及var six立即调用的函数中返回的函数中的上下文定义。

i)外部环境。它的可变环境是a = 1ii)在IIFE上下文中,它的词法环境为a = 1,但变量环境为a = 6,在堆栈中优先iii)返回的函数上下文,它的词法环境为a = 6,这是调用警报时引用的值。

enter image description here


1)有全局作用域、函数作用域、with和catch作用域。一般来说,变量没有"块"级范围——with和catch语句将名称添加到它们的块中。

范围由函数嵌套到全局范围。

3)通过原型链解析属性。with语句将对象属性名带入with块定义的词法范围。

编辑:ECMAAScript 6(和谐)被指定支持let,我知道chrome允许一个'和谐'标志,所以也许它支持它。

Let将支持块级范围,但是您必须使用关键字来实现它。

编辑:基于Benjamin在评论中指出的with和catch语句,我编辑了这篇文章,并添加了更多内容。with和catch语句都将变量引入各自的块中,这就是块作用域。这些变量根据传递给它们的对象的属性进行别名。

1
2
3
4
5
6
7
 //chrome (v8)

 var a = { 'test1':'test1val' }
 test1   // error not defined
 with (a) { var test1 = 'replaced' }
 test1   // undefined
 a       // a.test1 = 'replaced'

编辑:澄清的例子:

test1的作用域是with块,但是别名是a.test1。'Var test1'在上面的词法上下文中创建一个新的变量test1(函数或全局变量),除非它是a的一个属性——它确实是。

呵!使用with时要小心——就像var是一个noop(如果变量已经在函数中定义了)一样,对于从对象导入的名称,它也是一个noop !稍微注意一下已经定义的名称,这会更安全。我个人永远不会用因为这个。


我发现很多JavaScript新手很难理解这种语言的默认继承是可用的,而且到目前为止函数作用域是惟一的作用域。去年年底,我写了一个名为JSPretty的美容师,我提供了一个扩展。代码中的feature colors函数作用域,并且总是将颜色与该作用域中声明的所有变量相关联。当在不同的范围中使用来自一个范围的颜色的变量时,闭包将在视觉上得到演示。

试试这个功能:

http://prettydiff.com/jspretty.xhtml?c=white&jsscope

参见演示:

http://prettydiff.com/jspretty.xhtml?c=white&jsscope&s=http://prettydiff.com/lib/markup_beauty.js

请在以下网址浏览程式码:

http://prettydiff.com/lib/jspretty.jshttps://github.com/austincheney/Pretty-Diff/blob/master/lib/jspretty.js

目前,该特性支持16个嵌套函数的深度,但目前不为全局变量着色。


为了添加到其他答案中,scope是所有声明标识符(变量)的查找列表,并强制执行一组严格的规则,以确定当前执行代码如何访问这些标识符(变量)。这种查找可能是为了给变量赋值,这是一个LHS(左侧)引用,也可能是为了检索它的值,这是一个RHS(右侧)引用。这些查找是JavaScript引擎在编译和执行代码时在内部执行的操作。

所以从这个角度来看,我认为我在凯尔·辛普森的电子书《作用域和闭包》中找到的一张图片会有所帮助:

image

引用他的电子书:

The building represents our program’s nested scope ruleset. The first
floor of the building represents your currently executing scope,
wherever you are. The top level of the building is the global scope.
You resolve LHS and RHS references by looking on your current floor,
and if you don’t find it, taking the elevator to the next floor,
looking there, then the next, and so on. Once you get to the top floor
(the global scope), you either find what you’re looking for, or you
don’t. But you have to stop regardless.

值得注意的是,"范围查找一旦找到第一个匹配项就停止"。

"范围级别"的概念解释了为什么如果在嵌套函数中查找新创建的范围,则可以使用新创建的范围更改"This"。这里有一个链接,它涉及所有这些细节,所有您想了解的关于javascript作用域的内容


JavaScript只有两种类型的作用域:

全局范围:全局只是一个窗口级范围。这里,变量出现在整个应用程序中。函数作用域:使用var关键字在函数中声明的变量具有函数作用域。

无论何时调用函数,都会创建一个变量范围对象(并包含在范围链中),然后在JavaScript中创建变量。

1
2
3
4
5
6
        a ="global";
         function outer(){
              b ="local";
              console.log(a+b); //"globallocal"
         }
outer();

作用域链- - >

窗口级别- aouter函数位于范围链的顶层。当外部函数调用一个新的variable scope object(并包含在范围链中)并在其中添加变量b时。

现在,当一个变量a要求它首先搜索最近的变量作用域,如果没有变量,它将移动到变量作用域链的下一个对象。这里是窗口级。


运行代码。希望这将提供一个关于范围的概念

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
    Name: 'object data',
    f: function(){
        alert(this.Name);
    }
};

myObj.newFun = function(){
    alert(this.Name);
}

function testFun(){
    alert("Window Scope :" + window.Name +
         "
Local Scope :"
+ Name +
         "
Object Scope :"
+ this.Name +
         "
Current document Scope :"
+ document.Name
         );
}


testFun.call(myObj);
})(window,document);

全球范围:

全球变量就像全球明星一样(成龙,纳尔逊·曼德拉)。您可以从应用程序的任何部分访问它们(获取或设置值)。全球功能就像全球事件(新年、圣诞节)。您可以从应用程序的任何部分执行(调用)它们。

1
2
3
4
5
6
7
//global variable
var a = 2;

//global function
function b(){
   console.log(a);  //access global variable
}

本地范围:

如果你在美国,你可能认识臭名昭著的名人金·卡戴珊(Kim Kardashian)(不知怎的,她成功地登上了小报)。但是美国以外的人不会认出她。她是当地的明星,与她的领土息息相关。

局部变量就像局部恒星。您只能在范围内访问它们(获取或设置值)。本地函数类似于本地事件——您只能在该范围内执行(celebrate)。如果您想从范围之外访问它们,您将得到一个引用错误

1
2
3
4
5
6
7
8
9
function b(){
   var d = 21; //local variable
   console.log(d);

   function dog(){  console.log(a); }
     dog(); //execute local function
}

 console.log(d); //ReferenceError: dddddd is not defined

查看本文,深入了解范围


JavaScript作用域几乎只有两种类型:

每个var声明的范围都与最直接的封闭函数相关联如果var声明没有封闭函数,那么它就是全局作用域

因此,函数之外的任何块都不会创建新范围。这就解释了为什么for循环会覆盖外部作用域的变量:

1
2
3
4
var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5

使用功能:

1
2
3
4
var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10

在第一个示例中,没有block作用域,因此覆盖了最初声明的变量。在第二个例子中,由于函数的关系,出现了一个新的作用域,所以最初声明的变量是隐藏的,而不是覆盖的。

这几乎是所有你需要知道的JavaScript范围,除了:

try/catch只为异常变量本身引入新的作用域,其他变量没有新的作用域with-子句显然是另一个例外,但是使用with-子句是非常不鼓励的(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with)

因此,可以看到JavaScript作用域实际上非常简单,尽管并不总是直观的。需要注意的几件事:

var声明被提升到范围的顶部。这意味着无论var声明发生在哪里,对于编译器来说,它就像var本身发生在顶部一样在同一范围内合并多个var声明

所以这段代码:

1
2
3
4
5
6
var i = 1;
function abc() {
  i = 2;
  var i = 3;
}
console.log(i);     // outputs 1

等价于:

1
2
3
4
5
6
7
var i = 1;
function abc() {
  var i;     // var declaration moved to the top of the scope
  i = 2;
  i = 3;     // the assignment stays where it is
}
console.log(i);

这似乎违反直觉,但从命令式语言设计器的角度来看,这是有意义的。


现代Js ES6 + constlet"

应该对创建的每个变量使用块范围,就像大多数其他主要语言一样。var已经过时了。这使您的代码更安全,更易于维护。

95%的病例应使用const。它使变量引用不能改变。数组、对象和DOM节点属性可以更改,应该是const

let应该用于任何希望重新分配的变量。这包括在for循环中。如果在初始化之外更改值,请使用let

块作用域意味着变量只在声明它的方括号内可用。这扩展到内部范围,包括在范围内创建的匿名函数。


JS中只有函数作用域。不是块范围!你也能看到什么在提升。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var global_variable ="global_variable";
var hoisting_variable ="global_hoist";

// Global variables printed
console.log("global_scope: - global_variable:" + global_variable);
console.log("global_scope: - hoisting_variable:" + hoisting_variable);

if (true) {
    // The variable block will be global, on true condition.
    var block ="block";
}
console.log("global_scope: - block:" + block);

function local_function() {
    var local_variable ="local_variable";
    console.log("local_scope: - local_variable:" + local_variable);
    console.log("local_scope: - global_variable:" + global_variable);
    console.log("local_scope: - block:" + block);
    // The hoisting_variable is undefined at the moment.
    console.log("local_scope: - hoisting_variable:" + hoisting_variable);

    var hoisting_variable ="local_hoist";
    // The hoisting_variable is now set as a local one.
    console.log("local_scope: - hoisting_variable:" + hoisting_variable);
}

local_function();

// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable:" + local_variable);


试试这个奇怪的例子。在下面的示例中,如果a是初始值为0的数值,那么您将看到0和1。除了a是一个对象,javascript将传递给f1一个指针的a,而不是它的副本。结果是两次都得到相同的警告。

1
2
3
4
5
6
7
8
var a = new Date();
function f1(b)
{
    b.setDate(b.getDate()+1);
    alert(b.getDate());
}
f1(a);
alert(a.getDate());

我的理解是有三个范围:全局范围,全球可用;局部作用域,对整个函数可用,无论块大小;和块范围,仅对使用它的块、语句或表达式可用。全局作用域和局部作用域用关键字"var"表示,可以在函数内部,也可以在函数外部,块作用域用关键字"let"表示。

对于那些认为只有全局和本地作用域的人,请解释为什么Mozilla会有一个完整的页面来描述JS中块作用域的细微差别。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let


在JavaScript中有两种类型的作用域:

局部作用域全局作用域

下面的函数有一个局部作用域变量carName。这个变量在函数外部是不可访问的。

1
2
3
4
5
function myFunction() {
    var carName ="Volvo";
    alert(carName);
    // code here can use carName
}

下面的类有一个全局作用域变量carName。这个变量在类中的任何地方都可以访问。

1
2
3
4
5
6
7
8
9
10
11
class {

    var carName =" Volvo";

    // code here can use carName

    function myFunction() {
        alert(carName);
        // code here can use carName
    }
}

ES5:早些时候,

Javascript中的变量最初(pre ES6)是按词法定义函数作用域的。术语lexically scoped意味着您可以通过"查看"代码来查看变量的范围。

使用var关键字声明的每个变量都限定在函数的作用域内。但是,如果在该函数中声明了其他函数,那么这些函数就可以访问外部函数的变量。这称为范围链。它的工作方式如下:

当一个函数要解析一个变量值时,它首先要查看它自己的作用域。这是函数体,即大括号{}之间的所有内容(除了在此范围内的其他函数中的变量)。如果在函数体中找不到变量,它将爬到函数链上,查看函数中定义函数的变量范围。这就是词法作用域的含义,我们可以在定义该函数的代码中看到它,因此仅通过查看代码就可以确定作用域链。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// global scope
var foo = 'global';
var bar = 'global';
var foobar = 'global';

function outerFunc () {
 // outerFunc scope
 var foo = 'outerFunc';
 var foobar = 'outerFunc';
 innerFunc();
 
 function innerFunc(){
 // innerFunc scope
  var foo = 'innerFunc';
  console.log(foo);
  console.log(bar);
  console.log(foobar);
  }
}

outerFunc();

当我们试图将变量foobarfoobar记录到控制台时,会发生以下情况:

我们试图将foo记录到控制台,foo可以在函数innerFunc本身中找到。因此,foo的值被解析为字符串innerFunc。我们尝试将bar日志记录到控制台,但在函数innerFunc本身中找不到bar。因此,我们需要攀登范围链。我们首先查看定义函数innerFunc的外部函数。这是函数outerFunc。在outerFunc的范围内,我们可以找到变量栏,它包含字符串'outerFunc'。无法在innerFunc. .中找到页脚。因此,我们需要将范围链攀升到innerFunc范围。它也不能在这里找到,我们爬到全局范围的另一个层次(即最外层的范围)。我们在这里找到变量foobar,它包含字符串"global"。如果在攀爬范围链之后没有找到变量,JS引擎将抛出referenceError。ES6 (ES 2015)及更老版本:

同样的词域和作用域的概念仍然适用于ES6。然而,引入了一种声明变量的新方法。以下是:

let:创建一个块范围的变量const:创建一个必须初始化且不能重新分配的块作用域变量

varlet/const之间最大的区别是var是函数作用域,而let/const是块作用域。下面是一个例子来说明这一点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let letVar = 'global';
var varVar = 'global';

function foo () {
 
  if (true) {
    // this variable declared with let is scoped to the if block, block scoped
    let letVar = 5;
    // this variable declared with let is scoped to the function block, function scoped
    var varVar = 10;
  }
 
  console.log(letVar);
  console.log(varVar);
}


foo();

在上面的例子中,letVar记录全局值,因为用let声明的变量是块范围的。它们在各自的块之外不再存在,因此不能在if块之外访问变量。


在EcmaScript5中,主要有两个作用域,局部作用域和全局作用域,但是在EcmaScript6中,我们主要有三个作用域,局部作用域、全局作用域和一个称为块作用域的新作用域。

块范围的例子是:-

1
2
3
4
5
for ( let i = 0; i < 10; i++)
{
 statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}

ECMAScript 6引入了let和const关键字。这些关键字可以用来代替var关键字。与var关键字相反,let和const关键字支持在块语句中声明局部范围。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var x = 10
let y = 10
const z = 10
{
  x = 20
  let y = 20
  const z = 20
  {
    x = 30
    // x is in the global scope because of the 'var' keyword
    let y = 30
    // y is in the local scope because of the 'let' keyword
    const z = 30
    // z is in the local scope because of the 'const' keyword
    console.log(x) // 30
    console.log(y) // 30
    console.log(z) // 30
  }
  console.log(x) // 30
  console.log(y) // 20
  console.log(z) // 20
}

console.log(x) // 30
console.log(y) // 10
console.log(z) // 10

JavaScript中有两种类型的作用域。

全局作用域:在全局作用域中声明的变量可以在程序的任何地方非常顺利地使用。例如:

1
2
3
4
5
6
7
var carName =" BMW";

// code here can use carName

function myFunction() {
     // code here can use carName
}

函数作用域或局部作用域:在此作用域中声明的变量只能在其自身的函数中使用。例如:

1
2
3
4
5
// code here can not use carName
function myFunction() {
   var carName ="BMW";
   // code here can use carName
}


全局:函数外部声明的变量

局部:在函数内部声明的变量,只能在该范围内调用