一、var 、 let 和 const
1.1 let特性
- 不可声明前置
- 不可重复声明
- 块级作用域
- 暂时性死区(TDZ):在let声明变量之前都是该变量的死区,在死区内该变量不可使用。
// 使用var
for (var i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
});
} // => 5 5 5 5 5
// 使用let
for (let i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
});
} // => 0 1 2 3 4
1.2 const
const声明一个只读的常量。一旦声明,常量的值就不能改变。const实际上保证的是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
我们使用const时,不能只声明而不初始化值,否则会报错:
const a;
// SyntaxError: Missing initializer in const declaration
二、解构赋值
2.1 数组解构赋值
// 1. 解构声明
const [a, b, c] = [value1, value2, value3]
// 2. 修改变量的值
[a, b, c] = [value1, value2, value3]
// 3 复杂数组 (保证两边的数组形式一致)
const [a, [b], [c, [d,e]]] = [100, [200], [300, [400, 500]]]
// 4. 声明变量的时候可以有默认值 (与函数传参类似)
const [a, b, c, d = 5] = arr
console.log(d) // 5
2.2 对象解构赋值
// 简写形式
{name, age} = {name: '张三', age: 18} //张三 ,18
// 对象形式
const obj = {
name: '小明',
age: 18,
sex: '男',
love: {
eat: '吃饭',
sleep: '睡觉',
peas: '打豆豆',
}
}
const { name, age, sex } = obj
console.log(name, age, sex) // 小明 18 男
// 解构重名
const { name: myname } = obj
console.log(myname) // 小明
// 嵌套解构
const { love: { sleep } } = obj
console.log(sleep) // 睡觉
三、字符串扩展
两个反引号 ``
特点:
${变量} 直接解析
${表达式} 得到表达式的结果
四、函数扩展
4.1 参数默认值
// ES6的写法
function fn(a,b=默认值) {
}
// ES6之前的写法
function fn(a,b) {
if (b === undefined) {
b = 默认值
}
}
4.2 箭头函数
// 以前定义函数的方式 (表达式方式)
const fn = function () {}
// 箭头函数写法
const fn = () => {}
// 箭头函数简写,如果参数只有一个,可以省略括号
const fn = name => {}
// 只有一个参数,且只有一条返回语句
const fn = num => num * num
// 如果返回的是对象
const fn = name => ({ name: name })
特点:
- this指向与谁调用了箭头函数无关,与声明箭头函数位置有关。看声明箭头函数的地方,是不是嵌套在函数内,如果嵌套在了函数内,看外层函数的this指向;如果没有被函数嵌套,指向window。
- 箭头函数内无法获取aruguments,可以使用rest参数。
- 箭头函数不能作为构造函数。
- 箭头函数不能作为生成器。
适用场景
- 使用场景:作为回调函数;
- 不适合的场景:给对象添加方法(this指向)、构造函数、生成器函数。
五、Class语法
5.1 定义类(构造函数)
// 定义类
class Person {
// 属性,会添加到实例上
// 把所有的属性在这里声明
name = null;
age = null;
// 定义构造方法 实例化的时候自动执行
constructor(name, age = 10) {
this.name = name;
this.age = age;
}
// 方法,添加到原型上
say() {
console.log('MY Name is ' + this.name);
}
eat() {
console.log('My age is ' + this.age);
}
// 静态方法 没有添加到实例上,构造函数本身的方法
// static getClassName() {
// console.log('类名是 Person 构造函数本身的方法');
// }
}
// Person.getClassName(); // 相当于 Person.getClassName = function(){}
console.log(Person); //输出整个函数
console.log(typeof Person); // Function
console.log(Person.name); // Person ===> name指的是这个对象的名字
// 不能调用
// Person();
// 实例化
var p = new Person('曹操', 19);
console.log(p); // Person {name: "曹操", age: 19}
p.say(); // MY Name is 曹操
var p1 = new Person('吕布', 21);
console.log(p1); // Person {name: "吕布", age: 21}
p1.say(); // MY Name is 吕布
var p2 = new Person();
console.log(p2); // Person {name: undefined, age: 10}
5.2 getter 和 setter
class Person {
firstName = '东方';
lastName = '不败';
get fullName() {
return this.firstName + '_' + this.lastName;
}
set fullName(val) {
const name = val.split('_');
this.firstName = name[0];
this.lastName = name[1];
}
}
let p = new Person();
console.log(p); //Person {firstName: "东方", lastName: "不败"}
console.log(p.fullName); //可读可写 东方_不败
5.3 继承
- 使用 extends 来继承
- 继承之后:子类的实例的原型指向父类的一个实例,子类自己的原型指向父类 (静态方法也可以继承)
- 可以在子类上添加属性和方法
- 在子类上重写父类的方法,子类重写的方法必须调用super()
六、模块
6.1 模块中导出数据
// 模块内部
function say() {}
function eat() {}
export {
say,
eat
}
6.2 导入数据
import {say, eat} from '模块文件路径';