闭包以及let var

var list = document.getElementById('list');

for (let i = 1; i <= 5; i++) {
  let item = document.createElement('li');
  item.appendChild(document.createTextNode('Item ' + i));

  item.onclick = function(ev) {
    console.log('Item ' + i + ' is clicked.');
  };
  list.appendChild(item);
}

// to achieve the same effect with 'var'
// you have to create a different context
// using a closure to preserve the value
for (var i = 1; i <= 5; i++) {
  var item = document.createElement('li');
  item.appendChild(document.createTextNode('Item ' + i));

  (function(i){
    item.onclick = function(ev) {
      console.log('Item ' + i + ' is clicked.');
    };
  })(i);
  list.appendChild(item);
}


我们先看一个正常的for循环,普通函数里面有一个for循环,for循环结束后最终返回结果数组

复制代码
function box(){
    var arr = [];
    for(var i=0;i<5;i++){
        arr[i] = i;        
    }
    return arr;
}
alert(box())                                    //正常情况不需要闭包,就可以达到预期效果,输出结果为一个数组0,1,2,3,4
复制代码

有时我们需要在for循环里面添加一个匿名函数来实现更多功能,看下面代码

复制代码
//循环里面包含闭包函数
function box(){
    var arr = [];
    for(var i=0;i<5;i++){
        arr[i] = function(){
            return i;                            //由于这个闭包的关系,他是循环完毕之后才返回,最终结果是4++是5
        }                                        //这个匿名函数里面根本没有i这个变量,所以匿名函数会从父级函数中去找i,
    }                                            //当找到这个i的时候,for循环已经循环完毕了,所以最终会返回5
    return arr;
}
//alert(box());                                    //执行5次匿名函数本身
//alert(box()[1]);                   //执行第2个匿名函数本身
//alert(box().length);                            //最终返回的是一个数组,数组的长度为5
alert(box()[0]());                                //数组中的第一个数返回的是5,这是为什么?
复制代码

上面这段代码就形成了一个闭包:

闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的常见的方式,就是在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量。

在for循环里面的匿名函数执行 return i 语句的时候,由于匿名函数里面没有i这个变量,所以这个i他要从父级函数中寻找i,而父级函数中的i在for循环中,当找到这个i的时候,是for循环完毕的i,也就是5,所以这个box得到的是一个数组[5,5,5,5,5]。


腾讯的一个笔试题,先看一下

var a = 100;
function fn() {
    alert(a);   //undefined
    var a = 200;
    alert(a);   //200
}
fn();
alert(a);   //100
var a;
alert(a);    //100
var a = 300;
alert(a);   //300
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

前两个很简单,不解释 了,涉及到声明提前的问题。

后面仨为啥呢,这要总结下重复声明的问题:
1.使用var语句多次声明一个变量不仅是合法的,而且也不会造成任何错误.

2.如果重复使用的一个声明有一个初始值,那么它担当的不过是一个赋值语句的角色.

3.如果重复使用的一个声明没有一个初始值,那么它不会对原来存在的变量有任何的影响.


声明后未赋值,表现相同

复制代码
复制代码
(function() {
      var varTest;
      let letTest;
      console.log(varTest); //输出undefined
      console.log(letTest); //输出undefined
    }());
复制代码
复制代码

使用未声明的变量,表现不同:

复制代码
复制代码
(function() {
  console.log(varTest); //输出undefined(注意要注释掉下面一行才能运行)
  console.log(letTest); //直接报错:ReferenceError: letTest is not defined

  var varTest = 'test var OK.';
  let letTest = 'test let OK.';
}());
复制代码
复制代码

重复声明同一个变量时,表现不同:

复制代码
复制代码
(function() {
      "use strict";
      var varTest = 'test var OK.';
      let letTest = 'test let OK.';

      var varTest = 'varTest changed.';
      let letTest = 'letTest changed.'; //直接报错:SyntaxError: Identifier 'letTest' has already been declared

      console.log(varTest); //输出varTest changed.(注意要注释掉上面letTest变量的重复声明才能运行)
      console.log(letTest);
    }());
复制代码
复制代码

变量作用范围,表现不同:

复制代码
复制代码
(function() {
  var varTest = 'test var OK.';
  let letTest = 'test let OK.';

  {
    var varTest = 'varTest changed.';
    let letTest = 'letTest changed.';
  }

  console.log(varTest); //输出"varTest changed.",内部"{}"中声明的varTest变量覆盖外部的letTest声明
  console.log(letTest); //输出"test let OK.",内部"{}"中声明的letTest和外部的letTest不是同一个变量
}());
复制代码
复制代码

备注:

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

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

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


var array = [1, 2, 3];
var q = 1;

array = array.map((v) => {
    return v + q;
})

console.log(array);

var q = 1;

array = array.map((v) => {
    return v + q;
})

console.log(array);

结果:

Array [ 2, 3, 4 ]

Array [ 3, 4, 5 ]


var array = [1, 2, 3];
var q = 1;

array = array.map((v) => {
    return v + q;
})

console.log(array);

let q = 1;

array = array.map((v) => {
    return v + q;
})

console.log(array);

结果:

SyntaxError: redeclaration of var q

猜你喜欢

转载自blog.csdn.net/liduanwh/article/details/80508351
今日推荐