var 全局,函数级,let 作用域限制在块级域 JS

shuke 2018-3-23 1617

  • let与var

  在js中声明一个变量除了一个var 还有一个let的声明。对于var 在前面的作用域中已经讲过,这次主要说下二者的区别:

var list = document.getElementById("list");for (var i = 1; i <= 5; i++) {  var item = document.createElement("LI");
  item.appendChild(document.createTextNode("Item " + i));
  let j = i;
  item.onclick = function (ev) {
    console.log("Item " + j + " is clicked.");
  };
  list.appendChild(item);
}

上面这段代码的意图是创建5个li,点击不同的li能够打印出当前li的序号。如果不用let,而改用var的话,将总是打印出 Item 5 is Clicked,因为 j 是函数级变量,5个内部函数都指向了同一个 j ,而 j 最后一次赋值是5。

对于上面的结果如果不使用let的话,也是有办法破的。方法就是用一个闭包把j的作用域给包起来。修改如下:

<script>var list = document.getElementById("list");for (var i = 1; i <= 5; i++) {  var item = document.createElement("LI");
  item.appendChild(document.createTextNode("Item " + i));  var j = i;
  item.onclick = (function(j){    return function () {
    console.log("Item " + j + " is clicked.");
  }
})(j);
  list.appendChild(item);
}</script>

上面的是采用的闭包的方式在绑定的时候已经把j的值已经传递给对应的click事件了,所以能够实现相同的结果。如此很是精妙!但是对于程序的易性来说是一个不小的考验。

 

下面开始说说let为什么能够实现如此的结果:

let 允许把变量的作用域限制在块级域中。与 var 不同处是:var 申明变量要么是全局的,要么是函数级的,而无法是块级的。再看几个官方的demo.

在程序或者函数的顶层,let 的表现就象 var 一样:

function varTest() {  var x = 31;  if (true) {    var x = 71;  // same variable!
    console.log(x);  // 71  }
  console.log(x);  // 71}function letTest() {
  let x = 31;  if (true) {
    let x = 71;  // different variable
    console.log(x);  // 71  }
  console.log(x);  // 31}

上面的结果说明了let只在{}内使用。说到这里对开篇的那个问题就容易解释了。

用了let后,j 变成块级域(也就是花括号中的块,每进入一次花括号就生成了一个块级域),所以 5 个内部函数指向了不同的 j 。如果两个定义都在最外层则效果是一样,如下:

var x = 'global';
let y = 'global';
console.log(this.x);
console.log(this.y);
  • let 的暂存死区与错误

在同一个函数或同一个作用域中用let重复定义一个变量将引起 TypeError.

if (x) {
  let foo;
  let foo; // TypeError thrown.}

 然而,在变量声明之前引用这个变量会导致一个 ReferenceError的结果, 因为let变量 在"暂存死区" (从块的开始到声明这段).

function do_something() {
  console.log(foo); // ReferenceError
  let foo = 2;
}

在 switch 申明中你可能会遇到这样的错误,因为一个switch只有一个作用块.

switch (x) {  case 0:
    let foo;    break;    
  case 1:
    let foo; // TypeError for redeclaration.
    break;
}

 

循环体中是可以引用在for申明时用let定义的变量,尽管let不是出现在大括号之间.

var i=0;for ( let i=i ; i < 10 ; i++ ) {
  console.log(i);
}

let提供了一种在块的范围内获取变量的值,而不会影响块外面名字相同的变量的值的方法。

var x = 5;var y = 0;

let (x = x+10, y = 12) {
  console.log(x+y); // 27}

console.log(x + y); // 5

总结一下,对于let来说在某些地方确实有其长处的地方,同样也弥补了的js中块作用域的空白。


最新回复 (1)
全部楼主
  • shuke 2018-3-23
    2


    let variable1 = value1

    variable1

    要声明的变量的名称。

    value1

    赋给变量的初始值。

    使用 let 语句声明一个变量,该变量的范围限于声明它的块中。  可以在声明变量时为变量赋值,也可以稍后在脚本中给变量赋值。  

    使用 let 声明的变量,在声明前无法使用,否则将会导致错误。

    如果未在 let 语句中初始化您的变量,则将自动为其分配 JavaScript 值 undefined

    示例

    下面的示例阐释了 let 语句的用法。

    var  l = 10;
    {
        let l = 2;
       // At this point, l = 2.}// At this point, l = 10.// Additional ways to declare a variable using let.let index;
    let name = "Thomas Jefferson";
    let answer = 42, counter, numpages = 10;
    let myarray = new Array();

    要求

    在 Internet Explorer 11 标准文档模式下支持此项。 此外,也在应用商店应用(Windows 8.1 和 Windows Phone 8.1)中受支持。 请参阅版本信息

    在以下文档模式中不受支持:Quirks、Internet Explorer 6 标准模式、Internet Explorer 7 标准模式、Internet Explorer 8 标准模式、Internet Explorer 9 标准模式和 Internet Explorer 10 标准模式。 在 Windows 8 中不受支持。


返回