var = [];
for(var i = 0;i<10;i++){
a[i]= function(){
console.log(i);
}
}
arr[6](); //10
复制代码
上面代码中,变量i是var申明的,在全局范围内都有效,因此全局只有一个变量i,每一次循环,变量的值都会发生改变,而循环内被赋值给数组a的function在运行时,会经过闭包读到这同一个变量i,致使最后一轮输出最后一轮i的值,就是10javascript
而若是使用let,声明的变量仅在块级做用域内有效,最后输出的是6java
var = [];
for(let i = 0;i<10;i++){
a[i]= function(){
console.log(i);
}
}
arr[6](); //6
复制代码
上面代码中,变量i是let声明的,当前的i只在本轮循环中有效,因此每一次循环中的i都是一个新的变量,因此最后输出的是6,。 另外,for循环还有一个特别之处,就是循环语句部分是一个父做用域,而循环内部是一个单独子做用域。数组
for(let i = 0;i<3;i++){
let i ='abc';
console.log(i)
}
//abc
//abc
//abc
复制代码
var 命令会发生“变量提高”现象,即变量能够在声明以前使用,值为underfined。为了纠正这种现象,let命令改变了语法行为,他所声明的变量必定要在声明后使用,不然报错bash
//var状况
console.log(foo); //输出underfined
var foo;
//let状况
console.log(bar); //报错
let bar ;
复制代码
只要块级做用域内存在let命令,他所声明的变量就绑定(binding)这个区域,不在受外部的影响。闭包
var tmp = 123;
if(true){
tmp = 'abc'; //报错
let tmp;
}
复制代码
上面代码中,存在全局变量tmp,可是块级做用域内let又声明了一个局部变量tmp,致使后者绑定这个块级做用域,因此在let声明变量前,对tmp赋值会报错。ide
ES6明确规定,若是区块中存在let和const变量,从一开始就造成了封闭做用域,凡是在声明以前使用这些变量,就会报错。函数
总之,在代码块内,使用let命令声明变量以前,该变量都是不可用的。这在语法上叫作“暂时性死区”ui
let不容许在相同做用域内重复声明同一个变量spa
//报错
function(){
let a =10;
var a =1;
}
//报错
function(){
let a = 10;
let a = 1;
}
复制代码
所以,不能在函数内部从新声明参数code
function func(arg){
let arg ; //报错
]
function func(arg){
{
let arg; //不报错
}
}
复制代码
ES5只有全局做用域和函数做用域,没有块级做用域
var tmp = new Data();
function f(){
console.log(tmp);
if(false){
var tmp = 'hello world'
}
}
f(); //undefined
复制代码
上面代码的意思是,if代码块的外部使用外层的tmp变量,内层使用内层的tmp变量。可是,函数f执行后,输出结果为undefined,缘由在于变量提高,致使内层的tmp变量覆盖了外层的tmp变量
var s = 'hello';
for(var i = 0;i<s.length;i++){
console.log(s[i]);
}
console.log(i); //5
复制代码
上面代码中,变量i只用来控制循环,可是循环结束后,它并无消失,泄漏成了全局变量
let其实是为javascript新增了块级做用域
function f1(){
let n = 5;
if(true){
let n = 10
}
console.loga(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'}
}}}
复制代码
块级做用域的出现,实际上使得得到普遍应用的当即执行函数再也不必要了
function f(){
console.log('i am outside')
}
(function(){
if(false){
functon f(){
console.log('i an inside')
}
}
f();
}())
复制代码
上面代码中,会获得“i am inside”,ES6就彻底不同了,会获得“i am outside”.由于块级做用域内声明的函数相似let,对做用域以外没有影响。
//函数声明语句
{
let a = 'secret';
function f(){
return a;
}
}
//函数表达式
{
let a = 'secret';
let f = function(){
return a;
}
}
复制代码
本质上,块级做用域是一个语句,将多个操做封装在一块儿,没有返回值
{
let f = f();
t = t*t+1;
}
复制代码
上面代码中,块级做用域将两个语句分装在一块儿。可是,在块级做用域之外,没有办法获得t的值,由于块级做用域不返回值,除非t是全局变量。
let x = do{
let t = f();
t * t + 1;
]
复制代码
上面代码中,变量x会获得整个块级做用域的返回值
const a = 200;
a //200
a =600; //报错
复制代码
const foo
//报错
复制代码
var message = 'hello';
let age = 25;
//如下两行都会报错
const message = 'goodbye';
const age = 30;
复制代码
const foo();
//为foo添加一个属性,能够添加
foo.prop = 123;
foo.prop //123
//将foo指向另外一个对象,就会报错
foo ={] //报错
复制代码
下面是另外一个例子
const a = [];
a.push('hello') //可执行
a.length = 0; //可执行
a = ['dave'] //报错
复制代码
上面代码中,常量a是一个数组,这个数组自己是可写的,可是若是将另外一个数组赋值给a,就会报错
const foo = Object.freeze({});
//常规模式下,下面一行不起做用
//严格模式下,改行会报错
foo.prop = 123;
复制代码