*** let和const命令:
一.let命令*
1 . let 所声明的变量,只在let命令所在的代码块内有效
for循环的计数器,就很合适使用let命令 for(let I=0;i<10;i++){}
只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个
区域,不再受外部的影响。
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声
明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变
量,就 会报错。
总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这 在语法上,称为**“暂时性死区**”(temporal dead zone,简称 TDZ)
let不允许在相同作用域内,重复声明同一个变量。
2.块级作用域
没有块级作用域,带来以下不便:
第一种场景:内层变量可能会覆盖外层变量。
第二种场景:用来计数的循环变量泄漏为全局变量。
eg:
var s='hello';
for(var i=0;i<s.length;i++){
console.log(s[i]);
}
console.log[i];//输出结果为5 变量只是用来控制循环,但是循环结束后,它并没有消失,从而泄 漏了全局变量。
二.const命令*
const声明一个只读的常量。一旦声明,常量的值就不能改变。const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
const的作用域与let命令相同:只在声明所在的块级作用域内有效。
const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明
的位置后面使用。
const声明的常量,也与let一样不可重复声明。
如果真的想将对象冻结,应该使用Object.freeze方法。
全局环境中,this会返回顶层对象。但是,Node 模块和 ES6 模块中,this 返回的是当前模块。函数里面的this,如果函数不是作为对象的方法运行,而
是单纯作为函数运行,this会指向顶层对象。
对于复合型的变量,变量名不指向数据,而是指向数据所在的地址。const命令指示保证变量名指向的地址不改变,并不保存该地址的数据不变。
eg:
const foo={};常量foo存储的是一个地址,指向一个对象,既不能把foo指向 另一个地址,但是对象本身是可变的,可以为其添加新属性 foo.prop=123; foo.prop//123 foo={}//TypeError:'foo' is read-only不起作用
三.变量的解构赋值
1.数组的解构赋值
‘模式匹配’,只要等号两边相同左边的变量就会被赋予对应的值
eg:
var[a,b,c]=[1,[[2],3]] 解构不成功,变量的值就等于undefined 默认值:解构赋值允许指定默认值 eg:var[foo=true]=[]; foo;//true
2.对象的解构赋值
解构不仅可以用于数组,还可以用于对象
eg:
var {foo,bar}={foo:'aaa',bar:'bbbb'};
foo//'aaa' bar//'bbb' 对象的属性没有次序,变量名必须与属性名相同,才能取到正确的值。 变量名与属性名不同,需要写成下面这样:
eg: var{foo:baz}={foo:'aaa',bar:'bbb'};
baz//'aaa' 对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
let { foo: baz } = { foo: "aaa", bar: "bbb" }; 这种写法是变量和赋值一起进行,一旦赋 值的变量以前声明过,就会报错 baz // "aaa" foo // error: foo is not defined
四.字符串的解构赋值
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。 const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"\
c // "l"
d // "l"
e // "o" 类似于数组的对象都有length属性,因此还可以对这个属性解构赋值
let{length:len}='Hello'; len//5
五.数值和布尔值的解构赋值
如果等号右边是数值或布尔值,则会先转为对象。 let{toString:s}=123; s===Number.prototype.toString//true let{toString:s}true; s=Boolean,prototype,toString//true 由于null和undefined无法转成对象,所以会报错 let{prop:x}=undefined;//TypeError let{prop:y}=null;//TypeError
五.函数参数的解构赋值
函数参数的解构也可以使用默认值。 function move({x = 0, y = 0} = {}) { return [x, y]; } move({x: 3, y: 8}); // [3, 8] move({x: 3}); // [3, 0] move({}); // [0, 0] move(); // [0, 0] 上面代码中,函数move的参数是一个对象,通过对这个对象进行解构,得到变量x和y的值。如果解构失败,x和y等于默认值。 注意,下面的写法会得到不一样的结果。 function move({x, y} = { x: 0, y: 0 }) { return [x, y]; } move({x: 3, y: 8}); // [3, 8] move({x: 3}); // [3, undefined] move({}); // [undefined, undefined] move(); // [0, 0] 上面代码是为函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会得到与前一种写法不同的结果。
五.圆括号问题
不能使用圆括号的情况:
1.变量声明语句中,模式不能带有括号。
var [(a)=[1]];//报错 var {x:©}={};//报错 var {o:({p:p})}={o:{p:2}}//报错
首先它们都是赋值语句,而不是声明语句;其次它们的圆括号都不属于模式的一部分。第一行语句中,模式是取数组的第一个成员,跟圆括号无关;第二行语句中,模式是p,而不是d;第三行语句与第一行语句的性质一致。
五.用途
(1)交换变量的值 [x, y] = [y, x];
(2)从函数返回多个值
函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。
(3)函数参数的定义
解构赋值可以方便地将一组参数与变量名对应起来。
(4)提取 JSON 数据
解构赋值对提取 JSON 对象中的数据,尤其有用。
(5)函数参数的默认值
指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || ‘default foo’;这样的语句。
(6)遍历 Map 结构
任何部署了 Iterator 接口的对象,都可以用for…of循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。
(7)输入模块的指定方法
加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。
const { SourceMapConsumer, Sour