复习
var x=1;
{
let x = x;//ReferenceError: Cannot access 'x' before initialization
console.log(x);
}
let产生块级作用域,拿不到父级的x,取的是、引用的是当前块级作用域声明的x,
TDZ
Temporal Dead Zone暂时性死区
给函数赋予默认值
function foo(x, y) {
x=x||1;
y=y||2;
console.log(x+y);
}
foo();//3
foo(5,6);//11
foo(5);//7
foo(null,6);//7
foo(0,5);//6 造成不是想要的结果,造成错误
falsy虚值:
falsy虚值,在通过Boolean进行转化的时候,是假的值就是虚值,undefined NaN null 0 false ‘ ‘(空字符串)
es5代码,这个代码写的比较多,不够简洁,比较累赘,需要单独声明两个变量,麻烦,起名字也费劲,起名a、b不规范,想个规范的又没有必要,就用一次
function foo(x, y) {
var a=typeof (arguments[0])!=='undefined' ? arguments[0] :1;
var b=typeof (arguments[1])!=='undefined' ? arguments[1] :2;
console.log(a+b);
}
foo();//3
foo(5,6);//11
foo(5);//7
foo(null,6);//6
foo(0,5);//5
es6写法
function foo(x=1, y=2) {
console.log(x+y);
}
foo();//3
foo(5,6);//11
foo(5);//7
foo(null,6);//6
foo(0,5);//5
底层意思与es5代码一样
作用域探究
参数作用域与块级作用域
let x = 1;
function foo(y = x) {
/*定义在y=x之前,这是暂时性死区*/
let x = 2;
console.log(y);
}
foo();//1
这是因为参数x,也是变量
function foo(x){
let x=1;//SyntaxError: Identifier 'x' has already been declared
console.log(x);
}
let x = 1;
function foo(x=2) {
let x = 2;//SyntaxError: Identifier 'x' has already been declared
console.log(y);
}
foo();
foo(1);
因为给x赋默认值2,影响里面的块级作用域,会影响里面的let x
let x = 1;
function foo(x=x) {
//ReferenceError: Cannot access 'x' before initialization
console.log(x);
}
foo();
因为没有foo()没有传参数,势必运行x=x代码,这是个块级作用域,函数的参数会形成一个单独的作用域,当函数执行完之后作用域会消失
let x形成块级作用域,会在块级作用域中找x,不会从y找了
类似于
let x = 1;
function foo({let x=x}) {
console.log(x);
}
foo();
foo(0)
给x赋值也会运行(x=x)代码, 形参 x=0;let x=x;
或者理解成(x=11)第一个x是 let x,第二个x是11这个值
foo()
运行{let x=x},x未定义
let x = 1;
function foo(x=x) {
console.log(x);
}
foo(0);//0
这两个不一样
相当于如下代码
{
//AO{参数x=0},赋值了从AO中取
let x=x;
console.log(0)
}
{
//没有传参,AO中没有参数x,同级AO
let x=x;
console.log(0)
}
let x = 1;
function foo(y=x) {
let x=2;
console.log(y);
}
foo();//1
参数可以拿到上级的作用域里面的值
function foo(x=2) {
let x=2;//SyntaxError: Identifier 'x' has already been declared
console.log(x);
}
foo(11);
这个的结果比较奇怪,用({x=2})解释不清楚,
可以理解成
function foo() {
let x=x||2;
let x=2;//SyntaxError: Identifier 'x' has already been declared
console.log(x);
}
foo(11);
不管foo传不传参都运行了let x=2这段代码在foo下面,在{}下面
var w=1,y=6;
function foo(x=w+1,y=x+1,z=z+1){
//ReferenceError: Cannot access 'z' before initialization
console.log(x,y,z)
}
foo()
var w=1,y=6;
function foo(x=w+1,y=x+1){
console.log(x,y)//2,3
}
foo()
等价于
var w=1,y=6;
function foo(){
let x=w+1;
let y=x+1;
console.log(x,y)//2,3
}
foo()
等价于
var w=1,y=6;
/*function foo(){
let x=w+1;
let y=x+1;
console.log(x,y)//2,3
}
foo()*/
{
let x=w+1;
let y=x+1;
console.log(x,y)//2,3
}
当函数的参数赋值完就没有用处了,运行时AO确定,上下文确定,函数的变量都确定,参数就没有用处了,就可以取消{}里面的参数
每次都会计算b=a+1
惰性求值:每一次都需要重新计算表达式的值
let a=99;
function foo(b=a+1){
console.log(b);
}
foo();//100
a=100;
foo();//101
解构赋值
模式匹配(结构化赋值)
数组的模式匹配,一一对应的
let [a,b,c]=[1,2,3];
console.log(a,b,c);//1,2,3
console.log(window.a,window.b,window.c);
//undefined undefined undefined
结构赋值var也可以用
[a, b, c] = [1, 2, 3];/*与var结果一样*/
// var [a, b, c] = [1, 2, 3];
console.log(a, b, c);//1,2,3
console.log(window.a, window.b, window.c);//1,2,3
let [d,[e],[f]]=[1,[2],[3]];
console.log(d,e,f);//1,2,3
let [a, [b, c], [d, [e, f, [g] ] ] ] = [1, [2, 3], [4, [5, 6, [7] ] ] ];
console.log(a,b,c,d,e,f,g)//1,2,3,4,5,6,7
两边结构完全一样,完全匹配
解构失败,变量多了,有变量才能解构,有变量解构但解构时没有值,所以失败
let [a, [b, c], [d, [e, f, [g] ] ] ] = [1, [2, 3], [, [, , [7] ] ] ];
console.log(a,b,c,d,e,f,g)//1,2,3,undefined,undefined,undefined,7
不完全解构,值多了,属性少了,没有通过属性把所有值都给拿出来
let [a, [b, c], [, [, , [g] ] ] ] = [1, [2, 3], [, [, , [7] ] ] ];
console.log(a,b,c,g)//1,2,3,7
默认值,如果a不赋值,a值就是6
let [a=6]=[1];
console.log(a);//1
let [a,b=2]=[1];
console.log(a,b);//1 2
let [a,b=2]=[1,undefined];
console.log(a,b);//1,2
let [a,b=2]=[1,null];
console.log(a,b);//1,null
结果不同,与给默认值的函数写法不一样,除了undefined,因为js引擎默认认为没有填值,就是空,就是undefined
其它的都是输入什么就返回什么
给变量赋值为函数
因为赋值了,函数并不会运行,x值为1
function test(){
console.log(10);
console.log(10);
}
let [x=test()]=[1];
console.log(x)//1
function test(){
console.log(10);
console.log(10);
// return undefined;
}
let [x=test()]=[];
console.log(x);
函数执行,并打印返回值,undefined,没有返回值,就返回undefined
let [x=1,y=x]=[];
console.log(x,y);//1 ,1
let x=5;
let [x=1,y=x]=[];//SyntaxError: Identifier 'x' has already been declared
console.log(x,y);
报错,同一个块级作用域报错了
let [x=1,y=x]=[1,2];
console.log(x,y);//1,2
let [x=y,y=1]=[];//ReferenceError: Cannot access 'y' before initialization
console.log(x,y);
对象解构
es6对象扩展
es5定义对象的三种方式
let obj={};
let obj1=new Object();
let obj2=Object.create(null);
es5修改属性
let obj={};
/*let obj1=new Object();
let obj2=Object.create(null);*/
obj.name='zhangsan';
obj['name']='zhaosi';
delete obj.name;
var person={
name : 'zhangsan',
age : 14,
sex : 'male'
}
console.log(person)
//{ name: 'zhangsan', age: 14, sex: 'male' }
obj对象属性的值可以是外界的变量,变量赋值
obj属性赋值可以用变量的形式,属性:变量 ,属性:特定值(字符串、数字)
var name='zhangsan';
var age=14;
var person={
name : name,
age : age,
sex : 'male'
}
console.log(person)
//{ name: 'zhangsan', age: 14, sex: 'male' }
es6简写,当属性名与(对应的)变量名一致的时候可以简写
var name='zhangsan';
var age=14;
var person={
name,
// name : name,
age,
// age : age,
sex : 'male'
}
console.log(person)
//{ name: 'zhangsan', age: 14, sex: 'male' }
var name='zhangsan';
var age=14;
var person={
name,
// name : name,
age,
// age : age,
sex : 'male',
/* eat:function() {
console.log(1);
},*/
eat() {
console.log(1);
},
}
console.log(person)
//{ name: 'zhangsan', age: 14, sex: 'male', eat: [Function: eat] }
person.eat();//1
let firstName='ai';
let secondName = 'xiaoye';
let name='ai xiaoye';
let person={
/*变量名可以用字符串拼接*/
[firstName+secondName]:name
// [firstName+'xiaoye']:name
// ['ai'+'xiaoye']:name
}
console.log(person);
对象解构
let {a:a,b:b,c:c}={a:1,b:2,c:3};
console.log(a,b,c);//1 2 3
通过属性名a找到属性名a
let {a:a1,b1:b2,cc:c3}={a:1,b1:2,cc:3};
console.log(a1,b2,c3);//1 2 3
通过属性名一致找对应的内容,a:a1与a:1是对应的,之后把a1赋值1,a1是变量
a是属性名:a1是变量,给a1赋值
简写
// let {a:a,b:b,c:c}={a:1,b:2,c:3};
let {a,b,c}={a:1,b:2,c:3};
console.log(a,b,c);//1 2 3
不完全解构
let {a = 2, b, c} = {b: 2, c: 3, e: 4, f: 5};
console.log(a, b, c);//2 2 3
解构失败,解构失败就是
let {a = 2, b, c, d, e, f, g, h} = {b: 2, c: 3, e: 4, f: 5};
console.log(a, b, c, d, e, f, g, h);//2 2 3 undefined 4 5 undefined undefined
数组的结构存在顺序问题,对象解构不存在顺序问题,因为有键值对
/*let [d,[e],[f]]=[1,[2],[3]];
console.log(d,e,f);//1,2,3*/
let [d,[e],[f]]=[2,[1],[3]];
console.log(d,e,f);//2,1,3
对象的解构是不存在顺序的
/* let {a, b, c} = {a: 1, b: 2, c: 3};
console.log(a, b, c);//1 2 3*/
let {a, b, c} = { b: 2,a: 1, c: 3};
console.log(a, b, c);//1 2 3
实战
var data = [{"id": "1", "course": "前端开发之", "classes": "19"}, {
"id": "1",
"course": "前端开发之",
"classes": "19"
}, {"id": "1", "course": "前端开发之", "classes": "19"}]
// let [{"course": course1}, {"course": course2}] = data;
let [{course: course1}, {"course": course2}] = data;
// let [{course: course}, {"course": course}] = data;
//Uncaught SyntaxError: Identifier 'course' has already been declared
console.log(course1,course2);//前端开发之 前端开发之
取少量json数据可以用,非常好,比较方便
大量还是转换成js对象,再去操作,循环操作等
var person = {
name: 'zhangsan',
age: 50,
son: {
name: 'lisi',
age: 30,
son: {
name: 'wangwu',
age: 12
}
}
}
let {son:{son}}=person;
console.log(son);//name: 'wangwu', age: 12
var person = {
name: 'zhangsan',
age: 50,
son: {
name: 'lisi',
age: 30,
son: {
name: 'wangwu',
age: 12
}
}
}
/*son是对应的属性,第二个son是对应的属性,:前面的都是查找,后面的是变量*/
let {son:{son:son1}}=person;
console.log(son1);//name: 'wangwu', age: 12
解析
var person = {
name: 'zhangsan',
age: 50,
son: {
name: 'lisi',
age: 30,
son: {
name: 'wangwu',
age: 12
}
}
}
/*解构对象,解构当前对象,但我想结构里面的变量son*/
let {son} = person;
console.log(son);
var person = {
name: 'zhangsan',
age: 50,
son: {
name: 'lisi',
age: 30,
son: {
name: 'wangwu',
age: 12
}
}
}
/*解构对象,解构当前对象,但我想结构里面的变量son*/
// let {son} = person;
let {son:{}} = person;
/*这句话只是一个取值,但没有定义son变量,不打印就不出错,但变量没有定义*/
console.log(son);//Uncaught ReferenceError: son is not defined
var person = {
name: 'zhangsan',
age: 50,
son: {
name: 'lisi',
age: 30,
son: {
name: 'wangwu',
age: 12
}
}
}
/*解构对象,解构当前对象,但我想结构里面的变量son*/
// let {son} = person;
// let {son:{}} = person;
/*这句话只是一个取值,但没有定义son变量,不打印就不出错,但变量没有定义*/
// let {son:{son}} = person;
// let {son:{son:son}} = person;
let {son: {son: son1}} = person;
/*取变量,
* 如果son加:{}代表在son对象中取子对象
* son:{子对象}*/
console.log(son1);//name: 'wangwu', age: 12