let & const 命令

1、let命令

用于声明变量。javascript

1) 所声明的变量只在let命令所在代码块内有效。(块级做用域html

{ let a=10; var b=1; } a // ReferenceError: a is not defined
b // 1
var li=document.getElementsByTagName("li"); for(let i=0;i<li.length;i++){ li[i].addEventListener("click",function(){ console.log(i+1); }) }

在上面的代码中,变量i是let声明的,当前的i只在本轮循环有效,因此每一次循环的i都是一个新变量,因而最后输出的是6。这样每一个li元素输出的都是不同的值,好比第一个li单击会输出1,第二个li单击会输出2,第三个li单击会输出3... java

 

2) 不存在变量提高浏览器

let不像var那样会发生“变量提高”现象。因此变量必定要在声明后使用,不然报错。安全

console.log(foo); // ReferenceError
let foo=2; console.log(bar); // undefined
var bar=2;

 因此typeof再也不是一个百分之百安全的操做了。ide

typeof x; // ReferenceError
let x;

 

3) 暂时性死区函数

只要块级做用域内存在let命令,它所声明的变量就“绑定”到这个区域,再也不受外部的影响。ES6明确规定,若是区块中存在let和const命令,则这个区块对这些命令声明的变量从一开始就造成封闭做用域。只要在声明以前就使用这些变量,就会报错。在代码块内,使用let命令声明变量以前,该变量都是不可用的。这在语法上称为“暂时性死区”(TDZ)。spa

if(true){ // TDZ开始
    temp="abc"; // ReferenceError
    console.log(temp); // ReferenceError
 let temp; // TDZ结束
    console.log(temp); // undefined
 temp=123; console.log(temp); // 123
}

 有些死区比较隐蔽,不太容易发现。code

function bar(x=y,y=2){ return [x,y]; } bar(); // 报错

 调用bar函数报错,是由于参数x的默认值等于另外一个参数y,而此时y尚未声明,属于死区。htm

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

 

4) 不容许重复声明

let不容许在相同的做用域内重复声明同一个变量。

function func(){ // 报错重复声明变量
    let a=10; var a=1; } function func(arg){ let arg; // 报错,重复声明变量
} function func(arg){ // 不报错
 { let arg; } }

 

 2、块级做用域

 let实际上为javascript新增了块级做用域。

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

上面的函数有两个代码块,都声明了变量n,运行后输出5.这表示外层代码块不受内层代码块的影响。

ES6容许块级做用域任意嵌套。外层做用域没法读取内层做用域的变量。内层做用域能够定义外层做用域的同名变量。

函数自己的做用域在其所在的块级做用域内

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

上面的代码在ES5中运行,会获得I am inside(函数变量提高)。可是在ES6中运行会获得I am outside。无论会不会进入if代码块,其内部声明的函数皆不会影响到做用域的外部。

{ let a='secret'; function f(){ return a; } } f() // 报错

块级做用域外部没法调用块级做用域内部定义的函数。若是确实须要调用,则要像下面这样处理

let f; { let a='secret'; f=function(){ return a; } } f() // secret

 若是在严格模式下,函数只能在顶层做用域和函数内声明,其余状况(好比if代码块,循环代码块)下的声明都会报错

3、const命令

const用来声明常量。一旦声明,其值就不能改变。const一旦声明常量,就必须当即初始化,不能留到之后赋值,只声明不赋值就会报错。

const PI=3.14; PI // 3.14
PI=3; // TypeError:"PI" is read-only

 const做用域与let命令相同:只在声明所在的块级做用域内有效。const命令声明的常量也不能提高,一样存在暂时性死区,只能在声明后使用。而且不能重复声明常量。

对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,因此将一个对象声明为常量必须很是当心。

const foo={}; foo.prop=123; foo={} // TypeError:"foo" is read-only

上面的代码中,常量foo储存的是一个地址,指向一个对象。不可变的只是这个地址,既不能把foo指向另外一个地址,但对象自己是可变的,因此依然能够为其添加新属性。

const a=[]; a.push("Hello"); // 可执行
a.length=0;  // 可执行
a=["Dave"]; // 报错

若是真的想将对象冻结,应该使用Object.freeze方法。

const foo=Object.freeze({}); foo.prop=123; // 不起做用

上面的代码中,常量foo指向一个冻结的对象,因此添加新属性不起做用。除了将对象自己冻结,对象的属性也应该冻结。下面是一个将对象完全冻结的函数。

var constantize=(obj)=>{ Object.freeze(obj); Object.keys(obj).forEach((key,value)=>{ if(typeof obj[key]==='object'){ constantize(obj[key]); } }) }

ES6有6种声明变量的方法: var function let const import class

跨模块常量

上面说过,const声明的常量只在当前代码块有效。若是想设置跨模块的常量,能够采用下面的写法:

// constants.js 模块
export const A=1; export const B=3; export const C=4; // test1.js
import * as constants from './constants'; console.log(constants.A); // 1
console.log(constants.B);  // 3

// test2.js
import {A,B} from './constants'; console.log(A); // 1
console.log(B); // 3

 

4、全局对象的属性

全局对象是最顶层的对象,在浏览器环境指的是window对象,在Node.js中指的是global对象。

ES6规定var 命令和function命令声明的全局变量依旧是全局对象的属性let命令、const命令和class命令声明的全局变量不属于全局对象的属性

window.a=1; a; //1
 a=2; window.a //2
 let b=1; window.b // undefined
相关文章
相关标签/搜索