Let & Const

Let & Const

let 基础用法

很简单就能说明这个问题

if(false)
{
    var a = 'heihei'
}
a = undefined

if(true) {
    var a = 'heihei'
}
a = heihei

也就是说. { } 是木有作用域的.

里面声明的外面依然能够访问.

if(true) { let b = 'heihei_b' }
b = undefined

这样就有作用域了.

我想 w3c 如果不是为了兼容老代码。 可能直接强制用var 也遵循 代码块有作用域吧.

例子

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6]();  //6

这个是文章中的一个列子.

书中的解释是

上面代码中,变量ilet声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。

也就是说。 每一次都是一个新的循环,

对于新的循环来说 i 就是新的局部变量.

不存在变量提升

首先得明白什么是变量提升.

var a = 'haha';
(function() {
  alert(a)
})();

会弹出 haha

var a = 'haha';
(function() {
  var a = 'haha inside';
  alert(a);
})()

这个就是 haha inside 因为你调用的是局部变量 a.

var a = 'haha';
(function() {
  alert(a);
  var a = 'haha inside';
})()

这个时候弹出来 undefined

其实这段代码相当于

var a = 'haha';
(function() {
  var a;
  alert(a);
  a = 'haha inside';
})()

这个就是变量提升.

书中的不会存在变量提升就是指.

我不会弹出 undefined 哟.

我会报错. xxxx is not defined

就是这个意思.

暂时性死区

let 或 const 声明的变量拥有暂时性死区(TDZ):当进入它的作用域,它不能被访问(获取或设置)直到执行到达声明。

首先暂时性死区 就是变量提升的另一种说法.

var a = 'haha';
(function() {
  alert(a);
  var a = 'haha inside';
})()

这个之所以会弹出. undefined 是因为 var a = 'haha inside';

相当于在自执行函数顶部声明了一个 var a; 然后后面来赋值.

使用 let or const 你在声明之前使用会报错

不管你是否去 typeof

避免了 变量提升 的危险.

这个区域 就有一个吊炸天的名字 暂时性死区

本质就是叫你 别提莫 声明之前去使用.

不允许重复声明

var a = 1;
var a = 2;

var 可以重复声明。 谁后面声明用谁.

但是 let or const 不行.

不管对方使用的 var or let or const

以下情况都会报错

var a;
let a;

var b;
const b = '2';

let c;
var c;

const d = '2';
var d;

以上仅针对于同一级别的作用域。

块级作用域

以前 javascript 并没有块级作用域. 也就是说.

var a = 'b';
if(true)
    var a = 'c' 

a 等于 c

也就是说. 你 if 中声明的任何变量.

都将是和if同一层级的变量.

谈不上坑爹. 可是毕竟很多时候是需要块级作用域

要不也不用每次都写匿名自执行的函数

var a = (function(){ var a = ''; })();

难免会有污染的情况

还有书中说的.

for(var i=0;i<10;i++)
{

}

console.log(i); //10.

由于没有块级作用域. 所以泄露到了外部.

书中还提到了变量提升

var tmp = new Date();

function f() {
  console.log(tmp);
  if (false) {
    var tmp = "hello world";
  }
}

f(); // undefined

其实。 有良好的书写习惯的话 这种问题很少遇到.

当你使用 let or const 的时候就没有这种烦恼.

for(let i=0;i<10;i++)
{

}

console.log(i); // undefined

任意嵌套也没问题

for(let i=0;i<10;i++)
{
    if(true)
    {
        let i = 'wao';
    }

    console.log(i); // 1,2,3,4,5...
}

不同的 {} 就是一个作用域.

这引申出几个问题.

一. 是否是 {} 就是一个作用域。 switch case 呢?

function switchTest(o) {
    switch(o)
    {
      case '1':
        let a = '1';
        break;
      case '2':
        let a = '2';
        break;
    }
}

然后并不可以 直接报错.

Identifier 'a' has already been declared

继续来

function switchTest(o) {
    switch(o)
    {
      case '1':
        let a = '1';
        break;
      case '2':
        let b = '2';
        break;
    }

    console.log(a);
    console.log(b);
}

不管怎么都会报错.

因为变量死区.

就算你只输出一个 例如

console.log(a); //undefined

然而 真的有块级作用域

顺便提一句.

switch case 是一个很神奇的东西.

你在其中声明一样的变量,他会告诉你 变量已经声明过了. 一副我们里面是一起的样子

可是呢.

它和if有相同的功能.

如果没有 case 到. 那么里面代码也是不会执行.

如果你用var 该泄露还是泄露..

二. 书中提到的. function

首先书中提到了几个东西.

  1. es5 中不允许在 块级作用域 中声明函数
  2. es6 中. 允许声明,并且是类似 let 的行为,外部不能访问.

然而并没有声明卵用..

ES5. 浏览器没有遵守这个规定,还是支持在块级作用域之中声明函数。

而且 es5 & es6 混杂的情况下. 也很难按照规定来做.

以下是我测试. chrome 51.

目测只要执行过的 function 是不会遵循es6 let 声明.. 外部都能访问.

try {
  function f() {}
}
catch(e) { }

if (true) {
  function f() {}
}

都会影响外部.

如果不执行. 就没有这个问题.

如果在 function 中声明函数。 是不会影响外部的.

有点儿类似于 是声明的表达式.

可是有一个奇葩的

function f() { console.log('I am outside!'); }
(function () {
  if (false) {
    function f() { console.log('I am inside!'); }
  }

  f();
}());

按照我刚才的说法.

应该是执行 i am outside. 毕竟没有执行.

可是 ie9 是 I am inside! 如果在外部调用。 依然是 I am outside!'

chrome 是直接报错. 在外部 I am outside!'

然后茫然不知所措.

只能说各个浏览器,解析的方式各有不同.

考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。

三. 块级作用域

之前突发奇想. 如果在一个里面,同事使用 let & var

是不是 外部能访问 b 不能访问 a

if(true) {
    var b = 'b';
    let a = 'a'
}

是可以的.

也就是说. 所谓的块级作用域其实和 {} 无关.

你必须使用 let 罢了

const

可以说他就是一个 固定的 let

const a;

你必须一开始就赋值. 不然会报错.

赋值以后,如果是值类型是不能更改的.

const a = 1;
a = 2

这样是会报错的.

可是引用类型就不一样了.

const 只能保证在 栈内存上的地址是不变的.

也就是说.

const a = {};
a['b'] = 'b';

这样是ok的.

内存地址不变,可是堆内存的实际的东西发生了变化.

如果你这样直接硬来是不行的。

const a = {};
a = {}

因为你这样是会改变地址的..

所以。

const 就用开放放字符串,数值吧.

全局对象的属性

如果你这样写.

var a = 'a'
console.log(window.a);

也就是说 var 在顶层声明会自动成为 window 属性.

但是 let 不会..

就是这样..

如果你用全部用 let

作用域就是 window -> 1层 -> 2层.

var

就是 (window & 1层) > 2层..

以上.

thx

上一篇:arcgis python脚本工具实例教程—栅格范围提取至多边形要素类


下一篇:DIOCP之获取在线用户列表