一、补充

    1. var x = 123;
    2. {
    3. let x = x;
    4. //将右侧x赋值给左侧x时,会先读取x值,而当前块级作用域中变量x会通过let声明
    5. //在声明前引用变量,所以报错
    6. console.log(x)
    7. }
    8. //报错

    二、函数默认值
    es5中,函数默认值的写法,需要在函数体内创建两个变量,根据实参的值来赋值,麻烦。

    1. function test (a, b){
    2. //不能直接判断实参的值,如果实参的值为0、''、false等虚值falsy,判断就会出错
    3. let a = arguments[0] === undefined ? 6 : arguments[0],
    4. b = arguments[1] === undefined ? 8 : arguments[1];
    5. return a + b
    6. }

    es6中提供了更方便的语法,函数参数默认值

    1. function test (a = 6, b = 8){
    2. return a + b
    3. }

    (1)函数参数作用域
    es6中,设置函数参数后,调用函数时,参数会产生一个单独的作用域。函数形参值会在传入实参后进行计算。

    1. var x = 1;
    2. function f(x, y = x) {
    3. //函数调用时,参数形成一个作用域,对变量y进行求值时,x的值为2。
    4. //参数默认值变量x指向形参x,所以y被赋值为2
    5. console.log(y);
    6. }
    7. f(2) // 2

    如果参数默认值变量在参数作用域中未找到,则会到往外层作用域中查找,直至找到相应变量或报引用错误。

    1. let a = 123;
    2. function test( x = a , y =6){
    3. return x + y
    4. }
    5. test( undefined, 8 ) //如果想让前面形参取默认值,实参需要传undefined,传null不能达到目的。

    难题:
    1、参数作用域是一种块级作用域

    1. let x = 123;
    2. function test (x = x){
    3. // 相当于 let x = x 声明前引用,会报错 Cannot access 'y' before initialization
    4. console.log(x)
    5. }
    6. test() // Uncaught ReferenceError: Cannot access 'x' before initialization

    2、

    1. let x = 123;
    2. function test ( x , y = function(){ x = 2 }){
    3. //let x = 567 // 执行函数体代码时,形参作用域已经消失,不能冗余声明变量?
    4. //如果像上述所说,形参作用域消失后,形参x放哪儿,函数体内部通过var声明的x又放在哪儿?
    5. //let声明的变量在词法环境中,var声明的变量在变量环境中?
    6. var x = 567
    7. y()
    8. console.log(x)
    9. }
    10. test(1) // => 567
    1. 2)形参默认值表达式 都是 **惰性求值**(每次都重新计算)

    二、解构赋值
    数组结构
    (1)为了简化声明变量的同时进行赋值的操作,es6增加了解构赋值 Destructuring
    解构赋值的策略为 模式匹配,只要两边结构相等,左边的变量就会被赋予对应的值。

    1. let [a, b, c] = [1,2,3] // a,b,c => 1,2,3
    2. let [a,[b],c] = [1,[2],3] // a,b,c => 1,2,3
    3. let [, , c] = [1, 2, 3] // c => 3
    1. 2)解构数组时,还可利用 拓展符 获得包含对应元素的数组,如果没有对应的元素**解构失败**时,返回**空数组**
    1. let [a, b, ...c] = [1,2,3,4,5,6];
    2. console.log(c) // => [3,4,5,6]
    1. 3)单个变量没有对应值时,赋值为undefined
    1. let [a,b,...c] = [8]
    2. console.log(a,b,c) // => 8, undefined, []
    1. 4)解构赋值的时候也可以设置默认值,用默认值的话传undefined,传null也会赋值的。
    1. let [a = 6] = [];
    2. console.log(a) // => 6
    1. 5)**默认值**也可以设为**变量**
    1. let [x = y, y = 1] = []
    2. //解构失败的时候会报错,会用到变量y给x赋值
    3. let [x = y, y = 1] = [null]
    4. //结构成功时,不会提前引用变量y,也就不会报错

    对象结构
    声明变量时,给对应key赋值。对象解构时,只写一个属性名时,属性值为同名变量

    1. let {a, b, c} = {a: 1, b:2, c:3};
    2. // let {a:a, b:b, c:c} = {a: 1, b:2, c:3}
    1. 默认值也可以是个变量,**结构失败才会去引用默认值变量**
    1. let { a = b, b} = {a:123, b:567}
    2. console.log(a,b) // => 123 567
    3. let { a = b, b } = {b:567}
    4. //报错
    1. 解构赋值时,取对应值并重新命名结构为 { 'key' : 'newName' },新key值不能为字符串,不然会报错。<br />对象的解构赋值的**内部机制**,是**先找到同名属性,然后再赋给对应的变量,被赋值的是后者,前者是匹配模式,不是变量。**
    1. let {a: 'newA', b: 'newB'} = {a:'a', b: 'b'}
    2. console.log(newA,newB)
    1. 结构对应:<br />**左边解构也要写清晰,增加可读性**
    1. let obj = {
    2. p:{
    3. foo(){},
    4. arr: [1,2,3]
    5. }
    6. };
    7. //结构比较复杂的话,最好把结构也写清楚,增加代码可读性
    8. let {
    9. p :
    10. {
    11. foo:fn,
    12. arr:newArr
    13. }
    14. } = obj
    15. console.log(fn,newArr)
    16. // p 是匹配模式
    17. //如果要结构变量p,可以写成
    18. let {p, p:{foo:fn, arr:newArr}} = obj
    19. console.log(p, fn, newArr)

    注意点
    (1)结构一个已经声明的变量时,大括号不能放在行首,解决方式为用圆括号抱起来。

    1. let x;
    2. {x} = { x: 1 }
    3. 大括号放在行首,引擎会将 {x} 解析为一个代码块。