复习

  1. var x=1;
  2. {
  3. let x = x;//ReferenceError: Cannot access 'x' before initialization
  4. console.log(x);
  5. }

let产生块级作用域,拿不到父级的x,取的是、引用的是当前块级作用域声明的x,

TDZ暂时性死区

Temporal Dead Zone暂时性死区

函数默认值

es5简单写法,会被虚值影响

给函数赋予默认值

  1. function foo(x, y) {
  2. x=x||1;
  3. y=y||2;
  4. console.log(x+y);
  5. }
  6. foo();//3
  7. foo(5,6);//11
  8. foo(5);//7
  9. foo(null,6);//7
  10. foo(0,5);//6 造成不是想要的结果,造成错误

image.png
falsy虚值:
falsy虚值,在通过Boolean进行转化的时候,是假的值就是虚值,undefined NaN null 0 false ‘ ‘(空字符串)

因为虚值会被Boolean转换成false,直接走默认值11,会造成不想看到的结果,比如0,5,想要得到0+5=5,结果是1+5=6

es5最终写法

es5代码,这个代码写的比较多,不够简洁,比较累赘,需要单独声明两个变量,麻烦,起名字也费劲,起名a、b不规范,想个规范的又没有必要,就用一次

  1. function foo(x, y) {
  2. var a=typeof (arguments[0])!=='undefined' ? arguments[0] :1;
  3. var b=typeof (arguments[1])!=='undefined' ? arguments[1] :2;
  4. console.log(a+b);
  5. }
  6. foo();//3
  7. foo(5,6);//11
  8. foo(5);//7
  9. foo(null,6);//6
  10. foo(0,5);//5

es6写法:函数默认值

es6写法

  1. function foo(x=1, y=2) {
  2. console.log(x+y);
  3. }
  4. foo();//3
  5. foo(5,6);//11
  6. foo(5);//7
  7. foo(null,6);//6
  8. foo(0,5);//5

底层意思与es5代码一样

作用域探究:参数作用域

例子y=x

参数作用域与块级作用域

  1. let x = 1;
  2. function foo(y = x) {
  3. /*定义在y=x之前,这是暂时性死区*/
  4. let x = 2;
  5. console.log(y);
  6. }
  7. foo();//1

这是因为参数x,也是变量

  1. function foo(x){
  2. let x=1;//SyntaxError: Identifier 'x' has already been declared
  3. console.log(x);
  4. }

例子(x=2),参数名与函数内let声明的变量名,不能重复

  1. let x = 1;
  2. function foo(x=2) {
  3. let x = 2;//SyntaxError: Identifier 'x' has already been declared
  4. console.log(y);
  5. }
  6. foo();
  7. foo(1);

因为给x赋默认值2,影响里面的块级作用域,会影响里面的let x

  1. let x = 1;
  2. function foo(x) {
  3. let x = 2;//SyntaxError: Identifier 'x' has already been declared
  4. console.log(y);
  5. }
  6. foo();
  7. foo(1);

foo(x=x),函数不传值,错误

  1. let x = 1;
  2. function foo(x=x) {
  3. //ReferenceError: Cannot access 'x' before initialization
  4. console.log(x);
  5. }
  6. foo();

因为没有foo()没有传参数,势必运行x=x代码,这是个块级作用域,函数的参数会形成一个单独的作用域,当函数执行完之后作用域会消失
let x形成块级作用域,会在块级作用域中找x,不会从块级作用域外面找了
类似于

  1. let x = 1;
  2. function foo({let x=x}) {
  3. console.log(x);
  4. }
  5. foo();

foo(x=x),函数传值,正确

foo(0)
给x赋值也会运行(x=x)代码, 形参 x=0;let x=x;
~~或者理解成(x=11)第一个x是 let x,第二个x是11这个值 ~~
传值了,就不会走默认值了,而是给x赋值为11

foo() 运行{let x=x},x未定义,没有传值,就走默认值,第二个x没有传值也不会变成值,比如11等值
foo()、foo(参数)这两个不一样

  1. let x = 1;
  2. function foo(x=x) {
  3. console.log(x);
  4. }
  5. foo(0);//0

理解方式1

相当于如下代码

  1. {
  2. //AO{参数x=0},赋值了从AO中取
  3. let x=x;
  4. console.log(0)
  5. }
  1. {
  2. //没有传参,AO中没有参数x,同级AO
  3. let x=x;
  4. console.log(0)
  5. }
  1. let x = 1;
  2. function foo(y=x) {
  3. let x=2;
  4. console.log(y);
  5. }
  6. foo();//1

参数可以拿到上级的作用域里面的值

参数默认值x与let x重复,报错

  1. function foo(x=2) {
  2. let x=2;//SyntaxError: Identifier 'x' has already been declared
  3. console.log(x);
  4. }
  5. foo(11);

这个的结果比较奇怪,用({x=2})解释不清楚,

理解方式1

可以理解成

  1. function foo() {
  2. let x=x||2;
  3. let x=2;//SyntaxError: Identifier 'x' has already been declared
  4. console.log(x);
  5. }
  6. foo(11);

不管foo传不传参都运行了let x=2这段代码在foo下面,在{}下面

题目1

  1. var w=1,y=6;
  2. function foo(x=w+1,y=x+1,z=z+1){
  3. //ReferenceError: Cannot access 'z' before initialization
  4. console.log(x,y,z)
  5. }
  6. foo()
  1. var w=1,y=6;
  2. function foo(x=w+1,y=x+1){
  3. console.log(x,y)//2,3
  4. }
  5. foo()

等价于

  1. var w=1,y=6;
  2. function foo(){
  3. let x=w+1;
  4. let y=x+1;
  5. console.log(x,y)//2,3
  6. }
  7. foo()

等价于

  1. var w=1,y=6;
  2. /*function foo(){
  3. let x=w+1;
  4. let y=x+1;
  5. console.log(x,y)//2,3
  6. }
  7. foo()*/
  8. {
  9. let x=w+1;
  10. let y=x+1;
  11. console.log(x,y)//2,3
  12. }

当函数的参数赋值完就没有用处了,运行时AO确定,上下文确定,函数的变量都确定,参数就没有用处了,就可以取消{}里面的参数

每次都会计算b=a+1
惰性求值:每一次都需要重新计算表达式的值

  1. let a=99;
  2. function foo(b=a+1){
  3. console.log(b);
  4. }
  5. foo();//100
  6. a=100;
  7. foo();//101

解构赋值

数组解构

模式匹配(结构化赋值)
数组的模式匹配,一一对应的

  1. let [a,b,c]=[1,2,3];
  2. console.log(a,b,c);//1,2,3
  3. console.log(window.a,window.b,window.c);
  4. //undefined undefined undefined

let声明的内容不会挂载到window上

  1. let d=4;
  2. console.log(d,window.d);//4 undefined

解构赋值用var也可以

结构赋值var也可以用

  1. [a, b, c] = [1, 2, 3];/*与var结果一样*/
  2. // var [a, b, c] = [1, 2, 3];
  3. console.log(a, b, c);//1,2,3
  4. console.log(window.a, window.b, window.c);//1,2,3
  1. let [d,[e],[f]]=[1,[2],[3]];
  2. console.log(d,e,f);//1,2,3
  1. let [a, [b, c], [d, [e, f, [g] ] ] ] = [1, [2, 3], [4, [5, 6, [7] ] ] ];
  2. console.log(a,b,c,d,e,f,g)//1,2,3,4,5,6,7

两边结构完全一样,完全匹配

解构失败,变量(左)的数量>值(右)的数量

解构失败,变量多了,有变量才能解构,有变量解构但解构时没有值,所以失败

  1. let [a, [b, c], [d, [e, f, [g] ] ] ] = [1, [2, 3], [, [, , [7] ] ] ];
  2. console.log(a,b,c,d,e,f,g)//1,2,3,undefined,undefined,undefined,7

不完全解构,变量<值

不完全解构,值多了,属性少了,没有通过属性把所有值都给拿出来

  1. let [a, [b, c], [, [, , [g] ] ] ] = [1, [2, 3], [, [, , [7] ] ] ];
  2. console.log(a,b,c,g)//1,2,3,7

默认值

默认值,如果a不赋值,a值就是6

  1. let [a=6]=[1];
  2. console.log(a);//1
  1. let [a,b=2]=[1];
  2. console.log(a,b);//1 2
  1. let [a,b=2]=[1,undefined];
  2. console.log(a,b);//1,2
  1. let [a,b=2]=[1,null];
  2. console.log(a,b);//1,null

结果不同,与给默认值的函数写法不一样,除了undefined,因为js引擎默认认为没有填值,就是空,就是undefined
其它的都是输入什么就返回什么

给变量赋值为函数

因为赋值了,函数并不会运行,x值为1

  1. function test(){
  2. console.log(10);
  3. console.log(10);
  4. }
  5. let [x=test()]=[1];
  6. console.log(x)//1
  1. function test(){
  2. console.log(10);
  3. console.log(10);
  4. // return undefined;
  5. }
  6. let [x=test()]=[];
  7. console.log(x);

image.png
函数执行,并打印返回值,undefined,没有返回值,就返回undefined

解构赋值作用域

一个块级作用域,从前到后,从左到右运行,可以变量赋值,类似于新建块级作用域变量

  1. let [x=1,y=x]=[];
  2. console.log(x,y);//1 ,1
  1. let x=5;
  2. let [x=1,y=x]=[];//SyntaxError: Identifier 'x' has already been declared
  3. console.log(x,y);

报错,同一个块级作用域报错了

  1. let [x=1,y=x]=[1,2];
  2. console.log(x,y);//1,2
  1. let [x=y,y=1]=[];//ReferenceError: Cannot access 'y' before initialization
  2. console.log(x,y);

对象解构

对象定义的三种方式

es6对象扩展
es5定义对象的三种方式

  1. let obj={};
  2. let obj1=new Object();
  3. let obj2=Object.create(null);

es5对象属性名与变量名

es5修改属性

  1. let obj={};
  2. /*let obj1=new Object();
  3. let obj2=Object.create(null);*/
  4. obj.name='zhangsan';
  5. obj['name']='zhaosi';
  6. delete obj.name;
  1. var person={
  2. name : 'zhangsan',
  3. age : 14,
  4. sex : 'male'
  5. }
  6. console.log(person)
  7. //{ name: 'zhangsan', age: 14, sex: 'male' }

es5对象属性名与变量名,名称重复

obj对象属性的值可以是外界的变量,变量赋值
obj属性赋值可以用变量的形式,属性:变量 ,属性:特定值(字符串、数字)

  1. var name='zhangsan';
  2. var age=14;
  3. var person={
  4. name : name,
  5. age : age,
  6. sex : 'male'
  7. }
  8. console.log(person)
  9. //{ name: 'zhangsan', age: 14, sex: 'male' }

es6重复时的简写方式

es6简写,当属性名与(对应的)变量名一致的时候可以简写

  1. var name='zhangsan';
  2. var age=14;
  3. var person={
  4. name,
  5. // name : name,
  6. age,
  7. // age : age,
  8. sex : 'male'
  9. }
  10. console.log(person)
  11. //{ name: 'zhangsan', age: 14, sex: 'male' }

es6函数的简写方式

  1. var name='zhangsan';
  2. var age=14;
  3. var person={
  4. name,
  5. // name : name,
  6. age,
  7. // age : age,
  8. sex : 'male',
  9. /* eat:function() {
  10. console.log(1);
  11. },*/
  12. eat() {
  13. console.log(1);
  14. },
  15. }
  16. console.log(person)
  17. //{ name: 'zhangsan', age: 14, sex: 'male', eat: [Function: eat] }
  18. person.eat();//1

用字符串拼接对象属性

  1. let firstName='ai';
  2. let secondName = 'xiaoye';
  3. let name='ai xiaoye';
  4. let person={
  5. /*变量名可以用字符串拼接*/
  6. [firstName+secondName]:name
  7. // [firstName+'xiaoye']:name
  8. // ['ai'+'xiaoye']:name
  9. }
  10. console.log(person);

image.png
image.png

对象解构,不省略

对象解构

  1. let {a:a,b:b,c:c}={a:1,b:2,c:3};
  2. console.log(a,b,c);//1 2 3

通过属性名a找到属性名a

  1. let {a:a1,b1:b2,cc:c3}={a:1,b1:2,cc:3};
  2. console.log(a1,b2,c3);//1 2 3

通过属性名一致找对应的内容,a:a1与a:1是对应的,之后把a1赋值1,a1是变量
a是属性名:a1是变量,给a1赋值

对象解构简写

简写

  1. // let {a:a,b:b,c:c}={a:1,b:2,c:3};
  2. let {a,b,c}={a:1,b:2,c:3};
  3. console.log(a,b,c);//1 2 3

不完全解构

  1. let {a = 2, b, c} = {b: 2, c: 3, e: 4, f: 5};
  2. console.log(a, b, c);//2 2 3

解构失败,解构失败就是

  1. let {a = 2, b, c, d, e, f, g, h} = {b: 2, c: 3, e: 4, f: 5};
  2. console.log(a, b, c, d, e, f, g, h);//2 2 3 undefined 4 5 undefined undefined

顺序问题

数组的结构存在顺序问题,对象解构不存在顺序问题,因为有键值对

  1. /*let [d,[e],[f]]=[1,[2],[3]];
  2. console.log(d,e,f);//1,2,3*/
  3. let [d,[e],[f]]=[2,[1],[3]];
  4. console.log(d,e,f);//2,1,3

对象的解构是不存在顺序的

  1. /* let {a, b, c} = {a: 1, b: 2, c: 3};
  2. console.log(a, b, c);//1 2 3*/
  3. let {a, b, c} = { b: 2,a: 1, c: 3};
  4. console.log(a, b, c);//1 2 3

实战

先在数组里面取出对象,再往对象里面取属性

  1. var data = [{"id": "1", "course": "前端开发之", "classes": "19"}, {
  2. "id": "1",
  3. "course": "前端开发之",
  4. "classes": "19"
  5. }, {"id": "1", "course": "前端开发之", "classes": "19"}]
  6. // let [{"course": course1}, {"course": course2}] = data;
  7. let [{course: course1}, {"course": course2}] = data;
  8. // let [{course: course}, {"course": course}] = data;
  9. //Uncaught SyntaxError: Identifier 'course' has already been declared
  10. console.log(course1,course2);//前端开发之 前端开发之

取少量json数据可以用,非常好,比较方便
大量还是转换成js对象,再去操作,循环操作等

  1. var person = {
  2. name: 'zhangsan',
  3. age: 50,
  4. son: {
  5. name: 'lisi',
  6. age: 30,
  7. son: {
  8. name: 'wangwu',
  9. age: 12
  10. }
  11. }
  12. }
  13. let {son:{son}}=person;
  14. console.log(son);//name: 'wangwu', age: 12
  1. var person = {
  2. name: 'zhangsan',
  3. age: 50,
  4. son: {
  5. name: 'lisi',
  6. age: 30,
  7. son: {
  8. name: 'wangwu',
  9. age: 12
  10. }
  11. }
  12. }
  13. /*son是对应的属性,第二个son是对应的属性,:前面的都是查找,后面的是变量*/
  14. let {son:{son:son1}}=person;
  15. console.log(son1);//name: 'wangwu', age: 12

解析

  1. var person = {
  2. name: 'zhangsan',
  3. age: 50,
  4. son: {
  5. name: 'lisi',
  6. age: 30,
  7. son: {
  8. name: 'wangwu',
  9. age: 12
  10. }
  11. }
  12. }
  13. /*解构对象,解构当前对象,但我想结构里面的变量son*/
  14. let {son} = person;
  15. console.log(son);

image.png

  1. var person = {
  2. name: 'zhangsan',
  3. age: 50,
  4. son: {
  5. name: 'lisi',
  6. age: 30,
  7. son: {
  8. name: 'wangwu',
  9. age: 12
  10. }
  11. }
  12. }
  13. /*解构对象,解构当前对象,但我想结构里面的变量son*/
  14. // let {son} = person;
  15. let {son:{}} = person;
  16. /*这句话只是一个取值,但没有定义son变量,不打印就不出错,但变量没有定义*/
  17. console.log(son);//Uncaught ReferenceError: son is not defined
  1. var person = {
  2. name: 'zhangsan',
  3. age: 50,
  4. son: {
  5. name: 'lisi',
  6. age: 30,
  7. son: {
  8. name: 'wangwu',
  9. age: 12
  10. }
  11. }
  12. }
  13. /*解构对象,解构当前对象,但我想结构里面的变量son*/
  14. // let {son} = person;
  15. // let {son:{}} = person;
  16. /*这句话只是一个取值,但没有定义son变量,不打印就不出错,但变量没有定义*/
  17. // let {son:{son}} = person;
  18. // let {son:{son:son}} = person;
  19. let {son: {son: son1}} = person;
  20. /*取变量,
  21. * 如果son加:{}代表在son对象中取子对象
  22. * son:{子对象}*/
  23. console.log(son1);//name: 'wangwu', age: 12