一、函数默认值
(1)暂时性死区
暂时性死区 TDZ(Temporal Dead Zone)
var x = 1;
{
let x = x; //报错
log(x)
}
这里的x取的是let产生的块级作用域中的x,由于暂时性死区问题,let 声明的x并没有赋值,所以报错
侧面印证了let声明的变量,访问不到父级作用域
(2)参数默认值
ES写法
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(虚值Boolean为假的值),我赋值的是0
ES5写法
//es5解决方案
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 null转换成了0
foo(0, 5);//5
虚值:在通过boolean转化的时候可以转化为假的值就是falsy(虚值)
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
作用域深入
let x =1;
function foo(y = x){
let x =2;
console.log(y);
}
foo();//输出1,这里可以打印出1的原因是let声明的是y产生了块级作用域,所有y访问不到父级作用域的变量,但x可以拿到
let x =1;
function foo(x = 2){ // ()里的x是let声明的,且与{}的作用域是同级的,x重复声明所以报错
let x = 2;
console.log(x);
}
foo();//报错
let x = 1;
function foo(x = x){ // ()里的x是let声明的,且与{}的作用域是同级的,x重复声明所以报错
let x = 2;
console.log(x);
}
foo(); //报错
let x = 1;
function foo(x = x) { // 暂时性死区(包括let之前与当前),x还未声明
console.log(x);
}
foo(); //报错
let x = 1;
function foo(x = x) { // 传了实参,默认参数就不会再赋值,所以不报错
console.log(x);
}
foo(1); //输出1
默认值运算
var w = 1, z = 2;
function foo(x = w + 1, y = x + 1, z = z + 1) { // 暂时性死区,z还未声明
console.log(x, y, z)
}
foo(); // 报错
var w = 1, z = 2;
function foo(x = w + 1, y = x + 1) {
console.log(x, y)
}
foo(); // 2、3
惰性求值
每一次都要重新计算表达式的值
// 函数的默认参数为表达式的情况下的加载方式是一个惰性求值的方式,即不会缓存默认值,每次调用都会重新计算
let a = 99;
function foo(b = a + 1){
console.log(b);
}
foo();
a = 100;
foo();//输出100,101 惰性求值
二、解构赋值(数组)
模式匹配(结构化复制)
两边的结构要一致
let [a, b, c] = [1, 2, 3]
console.log(a, b, 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]] = [1, [2,3], [,]]
console.log(a,b,c,d,e) // 1 2 3 undefined undefined
不完全解构
值多了,变量少了
let [a, [,], [d,e]] = [1, [2,3], [4,5]]
console.log(a,b,c,d,e) // 1 4 5
解构默认值
let [a = 6] = [1];
console.log(a); // 1
let [a = 6] = [];
console.log(a); // 2
let [a, b = 2] = [1];
console.log(a, b); // 1 2
let [a, b = 2] = [1, undefined]; // 除了undefined取默认值以外取的所有值都是原本的值,JS引擎会认为是空
console.log(a, b); // 1 2
let [a, b = 2] = [1, null];
console.log(a, b); // 1 null
function test() {
console.log(10);
}
let [x = test()] = [1];
console.log(x); // 1
function test() { // 函数默认返回undefined
console.log(10);
}
let [x = test()] = [];
console.log(x); // undefined
let [x = 1, y = x] = [];
console.log(x, y) // 1 1
let x = 5;
let [x = 1, y = x] = []; // 这个不存在块级作用域,这个x已经被定义,重复声明报错
console.log(x, y) // 报错
let [x = 1, y = x] = [2];
console.log(x, y) // 2 2
let [x = 1, y = x] = [1,2]
console.log(x,y) // 1 2
let [x = y, y = 1] = []; // 暂时性死区,y还未声明
console.log(x, y); // 报错
三、解构赋值(对象)
属性和方法的简写
var _name = 'zhangsan';
var age = 18
var person = {
_name,
age,
sex: 'male',
eat() {console.log(1)}
}
console.log(person) // { _name: 'zhangsan', age: 18, sex: 'male', eat: [Function: eat] }
属性拼接
let firstName = 'ai';
let secondName = 'xiaoye';
let _name = 'ai xiaoye';
let person = {
[firstName + secondName]: _name,
// [firstName + 'xiaoye']: _name,
// ['ai' + 'xiaoye']: _name,
}
console.log(person); // { aixiaoye: 'ai xiaoye' }
对象的解构
结构一致,属性名称一致
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 } = { a: 1, b: 2, c: 3, e: 4, f: 5 };
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 } = { c: 3, b: 2, a: 1 };
console.log(a, b, c) // 1 2 3
现象
const {son} = person;
我们经常看到这样的解构,其实就是拿取person里的son属性,然后与取出来的变量同名
三、实战
实战1:拿到JSON里面的course数据
// 思路:首先结构要一致,然后用一个变量来接收
var data = [{ "id": 1, "course": "前端开发", "classes": 100, "teacher": "小野" }, { "id": 2, "course": "后端开发", "classes": 120, "teacher": "小夏" }, { "id": 1, "course": "全栈开发", "classes": 200, "teacher": "哈默" }];
let [{ course: course1 }, { course: course2 }] = data;
console.log(course1, course2); // 前端开发 后端开发
实战2:取到wangwu儿子
var pserson = {
name: "张三",
age: 50,
son: {
name: 'lisi',
age: 30,
son: {
_name: 'wangwu',
age: 12
}
}
}
let { son: { son } } = pserson;
console.log(son) // { _name: 'wangwu', age: 12 }
let { son: { son: son1 } } = pserson;
console.log(son1) // { _name: 'wangwu', age: 12 }
这里其实就是多层解构,把第一层解构的结果拿到然后以:{属性}或:{属性:变量名}的形式再继续解构