var,let,const,for循环原理

目录

var

let

const

块级作用域:

原理:


var

  • 声明一个变量,可选初始化一个值
  • 会预解析
  • 同一作用域可以重复声明变量
  • 在函数作用域内有效

let

  • 声明一个块作用域的局部变量,可选初始化一个值
  • 不会预解析
  • 同一作用域不可重复声明变量
  • 在块级作用域内有效
  • 存在暂时性死域(当一个区域存在let声明时,这个区域就形成了一个封闭的作用域,在let声明前使用这个变量就会报错,也就是只能先声明再使用,这种语法也称为暂时性死域。)
{
  let a = 1;
  {
    console.log(a);//报错
    let a =2;
  }
}

const

  • 声明一个块作用域的只读属性
  • 声明后必须初始化赋值,否则会报错
const a=123;
  • 不会预解析
console.log(a);
const a=10;  //a is not defined
  • 不可以重复声明
const a=1;
const a=2; //Identifier 'a' has already been declared
  • 简单类型的值不可以改变,相当于常量;复杂类型的值可以改变,相当于保存了内存地址,指向的保存数据的地址不变,但是数据结构变不变就不可以保证了
//复杂对象有数组和对象
const Obj={};
Obj.name=123;
console.log(Obj);  //输出:{name:123}
  • 全局或块级作用域
const a=1;
window.onload=function f1(){
    const b=2;
    console.log(a);   //1
    console.log(b);   //2
}
console.log(b); //b is not defined

块级作用域:

产生的原因:避免在for循环中的变量泄露

//for循环中的变量泄露
for(let i=0;i<3;i++){
    console.log(i);
}
console.log(i);    // 0 1 2


for(let i=0;i<3;i++){
    console.log(i);
}
console.log(i); //i is not defined

for循环的块级作用域

结论1:在for循环中使用let的情况下,由于块级作用域的影响,导致每次迭代过程中的 i 都是独立的存在。

结论2:既然说每次迭代的i都是独立的存在,那i自增又是怎么知道上次迭代的i是多少?这里通过ES6提到的,我们知道是js引擎底层进行了记忆

原理:

这是在for语句中的var与let的差异:

for (let x...)的循环在每次迭代时都为x创建新的绑定

以下用代码直接看会比较容易的理解。这个改进主要是为了要解决在for语句中的闭包结构的问题。

原来的使用var的代码,与去糖(desugar)后来看它在执行时是这样的模拟代码:

//原来代码
for (var i = 0; i < 10; i++) { setTimeout(()=>console.log("i:",i), 1000); }
// 不需要加区块符,因为区块也不会影响
var i;
i = 0;
if (i < 10)
    setTimeout(()=>console.log("i:",i), 1000);
    i++;
    if (i < 10)
        setTimeout(()=>console.log("i:",i), 1000);
        i++;
//...

而使用了let后,会有块级作用域的影响,原来的代码与执行时的去糖模拟代码如下:

// 原来代码
for (let i = 0; i < 10; i++) { setTimeout(()=>console.log("i:",i), 1000); }
// 用区块符区分每次循环的语句
// 每次for语句开始,i指定为一个全域刻度__status,这只是方便说明而已
// __status会记录for语句i最后的值
{ let i;
  i = 0;
  __status = {i};
}
{ let {i} = __status;
  if (i < 10)
      setTimeout(()=>console.log("i:",i), 1000);
      __status = {i};
}   
    { let {i} = __status;
      i++;
      if (i < 10)
          setTimeout(()=>console.log("i:",i), 1000);
          __status = {i};
    }
    //...

 为何可以这样模拟?因为在ES标准中,有一段是关于CreatePerIterationEnvironment,也就是for语句每次循环所要建立环境的步骤,里面有提及有关词法环境的相关步骤(LexicalEnvironment),这与使用let时会有关。所以,如果你使用了let而不是var,let的变量除了作用域是在for区块中,而且会为每次循环执行建立新的词法环境(LexicalEnvironment),拷贝所有的变量名称与值到下个循环执行。以最简单的方式改写原先的问题中的代码,相当于下面这样写:

var a = [];
{ let k;
    for (k = 0; k < 10; k++) {
      let i = k; //注意这里,每次循环都会创建一个新的i变量
      a[i] = function () {
        console.log(i);
      };
    }
}
a[6](); // 6

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值