let 和 const命令

1.let命令

基本用法:

        ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let所在命令行所在的代码块内有效。

       {
          let a = 10;
           var b = 1;
        }
        a // ReferenceError: a is not defined.
        b // 1

            上面代码在代码块之中,分别用letvar声明了两个变量。然后在代码块之外调用这两个变量,结果let声明的变量报错,var声明的变量返回了正确的值。这表明,let声明的变量只在它所在的代码块有效。

            for循环的计数器,就很适合let命令

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

                上面代码中,计数器i只在for循环体内有效,在循环体外就会报错。

                 另外for循环还有一个特别之处,设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

不存在变量提升

                var变量会发生“变量提升”的现象,即变量可以在声明之前使用,值为undefined。

                为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明之后使用否则报错。

        // var 的情况
        console.log(foo); // 输出undefined
        var foo = 2;
        // let 的情况
        console.log(bar); // 报错ReferenceError
        let bar = 2;

                报错ReferenceError(引用错误)

暂时性死区

                只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不在受外部的影响。

        var tmp = 123;
        if (true) {
        tmp = 'abc'; // ReferenceError
        let tmp;
        }

ES6 明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

if (true) {
  // TDZ开始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ结束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

上面代码中,在let命令声明变量tmp之前,都属于变量tmp的“死区”。

“暂时性死区”也意味着typeof不再是一个百分之百安全的操作。

typeof x; // ReferenceError
let x;
上面代码中,变量 x 使用 let 命令声明,所以在声明之前,都属于 x 的“死区”,只要用到该变量就会报错。因此, typeof 运行时就会抛出一个 ReferenceError

作为比较,如果一个变量根本没有被声明,使用typeof反而不会报错。

typeof undeclared_variable // "undefined"

上面代码中,undeclared_variable是一个不存在的变量名,结果返回“undefined”。所以,在没有let之前,typeof运算符是百分之百安全的,永远不会报错。现在这一点不成立了。这样的设计是为了让大家养成良好的编程习惯,变量一定要在声明之后使用,否则就报错。

总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

不允许重复声明:

        let不允许在相同作用域内,重复声明同一变量,因此不能在函数内部重新声明参数

function func(arg) {
  let arg; // 报错
}

function func(arg) {
  {
    let arg; // 不报错
  }
}

2.块级作用域

为什么需要块级作用域?

ES5只有全局作用域和函数作用域,这带来很多不合理的场景,

第一种场景,用来计数的循环变量泄露为全局变量

var s = 'hello';

for (var i = 0; i < s.length; i++) {
  console.log(s[i]);
}

console.log(i); 
ES6块级作用域

let实际上为了JavaScript新增了块级作用域

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5
}

上面的函数有两个代码块,都声明了变量n,运行后输出 5。这表示外层代码块不受内层代码块的影响。如果两次都使用var定义变量n,最后输出的值才是 10。

ES6 允许块级作用域的任意嵌套。

{{{{{let insane = 'Hello World'}}}}};
面代码使用了一个五层的块级作用域。外层作用域无法读取内层作用域的变量。
{{{{
  {let insane = 'Hello World'}
  console.log(insane); // 报错
}}}};
内层作用域可以定义外层作用域的同名变量。
{{{{
  let insane = 'Hello World';
  {let insane = 'Hello World'}
}}}};
块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。

3.const命令

基本用法: 

const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.

改变常量的值就会报错!

const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。

const foo;
// SyntaxError: Missing initializer in const declaration

上面的代码对于const来说,只声明不赋值就会报错。

const作用域与let命令相同:只在升级的块级作用域内有效!

const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。

本质

    const实际上保证的并不是变量的值不变,而是变量指向的那块内存地址不得改动。对于简单类型的数据(数值,字符串,布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是数组和对象),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

ES6声明变量的6种方法:

    ES5只有两种声明变量的方法:var 和function

    ES6还添加了const 和let  ,import和class4个命令

4.顶层对象的属性

    顶层对象在浏览器环境指的是window对象,在Node指的是global对象。ES5中顶层对象的属性与全局变量是等价的

    ES6 为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。

var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1

let b = 1;
window.b // undefined

上面代码中,全局变量avar命令声明,所以它是顶层对象的属性;全局变量blet命令声明,所以它不是顶层对象的属性,返回undefined

5.globel对象

ES5的顶层对象本身也是一个问题

浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window

浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self

Node 里面,顶层对象是global,但其他环境都不支持。

同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用this变量,但是有局限性。

全局环境中this会返回顶层对象,但是在Node模块和ES6模块中,this返回的是当前模块。

函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是,严格模式下,这时this会返回undefined

不管是严格模式,还是普通模式,new Function('return this')(),总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全政策),那么evalnew Function这些方法都可能无法使用。



            

            


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值