一、声明变量
使用let、const
,会创建块级作用域
二、字符串和正则
字符串多了个codePointAt
方法,找到字符串的码点
正则多了个标志u
,使用码点进行匹配
三、函数
参数默认值、剩余参数、展开运算符、箭头函数
四、类
- 使用
class
关键字创建构造函数(类)
class User {
constructor(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
sayHello() {
console.log(`我叫${this.name},${this.age}岁,${this.gender}`)
}
}
const user1 = new User('张三', 16, '男');
user1.sayHello();
- 使用
getter
setter
对属性设置、读取
class User {
constructor(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
get age() {
return this._age;
}
set age(val) {
if (val < 0) {
this._age = 0;
} else if (val > 100) {
this._age = 100;
} else {
this._age = val;
}
}
sayHello() {
console.log(`我叫${this.name},${this.age}岁,${this.gender}`)
}
}
- 静态成员 关键字
static
挂载类上,实例上没有
class User {
constructor(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
static hobit = '敲代码'
static youSaySay() { console.log('我不想修水管') }
// ...
}
- 类的继承 使用关键字
extends
super
class User {
constructor(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
print(){
console.log('我是父类方法')
}
// ...
}
class VipUser extends User {
constructor(name, age, gender){
super('李四', 19, 女)
this.vip = '我是VIP'
}
print(){
super.print();
console.log('我是子类方法,还想用父类的同名方法,要使用super关键字')
}
// ...
}
// 或者
class VipUser extends User {
// 不写constructor,系统会自动创建并调用,参数是父类所需参数
}
- 可以使用
new.target
来制作抽象类(抽象类:一般是父类,不能通过该类创建对象)
class A{
constructor() {
if (new.target === A) {
throw Error('不能直接创建父类')
}
}
print() {
console.log('我是父类')
}
}
class AA extends A {
print() {
console.log('我是子类')
}
}
const a = new A(); // 报错
const aa = new AA();
五、解构
对数组、对象、参数结构
六、符号Symbol
创建对象的私有属性
使用Symbol('符号描述')
创建符号
特点:
- 没有字面量
- type of 得到symbol
- 每次调用Symbol函数得到的符号永远不相等
- 可以作为对象的属性名存在,叫做符号属性
1、这些符号属性通常不能被外界访问
2、符号属性不能被枚举,for-in 循环、Object.keys()方法无法得到符号属性
3、Object.getOwnPropertyNames 可以得到所有无法枚举的属性,但得不到符号属性
4、Object.getOwnPropertySymbols 可以得到符号属性
共享符号Symbol.for('符号描述')
知名符号:
1、Symbol.hasInstance
会影响 instanceof 的判定
Object.defineProperty(A, Symbol.hasInstance, {
value: function (obj) {
return false
}
})
2、Symbol.isConcatSpreadable
会影响数组的 concat 方法
const arr = [3];
const arr2 = [5, 6, 7, 8];
const result = arr.concat(56, arr2)
// arr2[Symbol.isConcatSpreadable] = false;
// [3, 56, [5,6,7,8]]
// arr2[Symbol.isConcatSpreadable] = true; 默认会分割
// [3, 56, 5, 6, 7, 8]
console.log(result)
const arr = [1];
const obj = {
0: 3,
1: 4,
length: 2,
[Symbol.isConcatSpreadable]: true // [1, 2, 3, 4]
// [Symbol.isConcatSpreadable]: false // [1, 2, {0: 3, 1: 4, length: 2}]
}
const result = arr.concat(2, obj)
console.log(result)
3、Symbol.toPrimitive
会影响类型转换的结果
class Temperature {
constructor(degree) {
this.degree = degree;
}
[Symbol.toPrimitive](type) {
if (type === "default") {
return this.degree + "摄氏度";
}
else if (type === "number") {
return this.degree;
}
else if (type === "string") {
return this.degree + "℃";
}
}
}
const t = new Temperature(30);
console.log(t + "!"); // 30摄氏度!
console.log(t / 2); // 15(并且是数字类型)
console.log(String(t)); // 30℃
4、Symbol.toStringTag
会影响 Object.prototype.toString 的返回值
class Person {
[Symbol.toStringTag] = "Person"
}
const p = new Person();
const arr = [32424, 45654, 32]
console.log(Object.prototype.toString.apply(p)); // [object Person]
console.log(Object.prototype.toString.apply(arr)); // [object Array]
七、Promise与async\await
Promise
基本使用方法:then、catch、finally
const pro = new Promise((res, rej) => {
// 处理函数
// res(args)
// rej(args)
}).then(res => {
// 成功的处理函数
// 返回的还是Promise对象
}, rej => {
// 失败的处理函数
// 返回的还是Promise对象
}).catch(err => {
// 失败的处理函数
}).finally(() => {
// 不管成功失败,都会处理的函数
})
Promise
的静态方法:resolve、reject、all、race
,返回一个Promise对象
const pro = Promise.resolve(args)
const pro = Promise.reject(args)
const pro = Promise.all(iterable).then(...) // 获取接口速度不一致时,全部成功后才会执行then
const pro = Promise.race(iterable).then(...) // 获取接口速度不一致时,最先完成的才会执行then
async\await
Promise 的语法糖,返回一个Promise对象
async function test1(){
console.log(1);
return 2;
}
async function test2(){
const result = await test1();
console.log(result);
}
test2();
//等效于
function test1(){
return new Promise((resolve, reject)=>{
console.log(1);
resolve(2);
})
}
function test2(){
return new Promise((resolve, reject)=>{
test1().then(data => {
const result = data;
console.log(result);
resolve();
})
})
}
test2();
八、迭代器Iterator
与生成器Generator
迭代器:一个对象有next
方法,并且返回一个对象,对象格式为{value: xx, done: xx}
// 将普通对象转换为可迭代对象,并且可以修改可迭代对象返回值的格式
const obj = {
a: 1,
b: 2,
[Symbol.iterator]() {
const keys = Object.keys(this);
let i = 0;
return {
next: () => {
const propName = keys[i];
const propValue = this[propName];
const result = {
value: {
propName,
propValue
},
done: i >= keys.length
}
i++;
return result;
}
}
}
}
可迭代对象可以使用for-of
循环进行遍历
const arr = [5, 7, 2, 3, 6];
// const iterator = arr[Symbol.iterator]();
// let result = iterator.next();
// while (!result.done) {
// const item = result.value; //取出数据
// console.log(item);
// //下一次迭代
// result = iterator.next();
// }
// 与上面的方法等价
for (const item of arr) {
console.log(item)
}
生成器:是一个迭代器的同时,是一个可迭代对象
创建生成器:使用生成器函数
function* method() {}
生成器函数中取值要配合yield
关键字
注意点:
- 生成器函数可以有返回值,返回值出现在第一次done为true时的value属性中
function* test() {
console.log("第1次运行")
yield 1;
console.log("第2次运行")
yield 2;
console.log("第3次运行");
return 10;
}
const generator = test();
generator.next() // 第1次运行 {value: 1, done: false}
generator.next() // 第2次运行 {value: 2, done: false}
generator.next() // 第3次运行 {value: 10, done: false}
generator.next() // {value: undefined, done: true}
- 调用生成器的next方法时,可以传递参数,参数会交给yield表达式的返回值
- 第一次调用next方法时,传参没有意义
function* test() {
console.log("函数开始")
let info = yield 1;
console.log(info)
info = yield 2 + info;
console.log(info)
}
const generator = test();
generator.next() // 函数开始 {value: 1, done: false}
generator.next('abc') // abc {value: '2abc', done: false}
generator.next('xyz') // xyz {value: undefined, done: true}
- 生成器函数内部可以调用其他生成器函数,要加上
*
function* t1(){
yield "a"
yield "b"
}
function* test() {
yield* t1();
yield 1;
yield 2;
yield 3;
}
const generator = test();
生成器的其他API
return
:可以提前结束生成器函数,让整个迭代过程结束
throw
:可以在生成器中产生一个错误
生成器异步控制小方法:
function* task() {
const d = yield 1;
console.log(d)
// //d : 1
const resp = yield fetch("http://www.baidu.com")
const result = yield resp.json();
console.log(result);
}
run(task);
function run(generatorFunc) {
const generator = generatorFunc();
let result = generator.next(); //启动任务(开始迭代), 得到迭代数据
handleResult();
//对result进行处理
function handleResult() {
if (result.done) {
return; //迭代完成,不处理
}
//迭代没有完成,分为两种情况
//1. 迭代的数据是一个Promise
//2. 迭代的数据是其他数据
if (typeof result.value.then === "function") {
//1. 迭代的数据是一个Promise
//等待Promise完成后,再进行下一次迭代
result.value.then(data => {
result = generator.next(data)
handleResult();
})
} else {
//2. 迭代的数据是其他数据,直接进行下一次迭代
result = generator.next(result.value)
handleResult();
}
}
}
九、Set
与Map
功能与数组和对象有点类似,都是用于存放数据的集合
- Set:用于存放不重复的数据,可以用来数组去重
创建set集合
new Set(iterable)
对set集合进行操作:
1).add(数据)
:添加一个数据到set集合末尾,若数据已存在(使用Object.is判断两个数据是否相同,除+0-0会判断相等),则不进行任何操作
2).has(数据)
:判断set集合中是否存在数据
3).delete(数据)
:删除匹配的数据,返回值为是否删除成功
4).clear()
:清空set集合
5).size
:获取set集合元素的数量,只读
和数组进行相互转换
使用const s = new Set([1, 2, 3]) const arr = [...s]
for-of
遍历
使用for (const item of s) { console.log(item) }
forEach
遍历,参数分别为值、值、本身
set集合中不存在下标,所以用forEach遍历时s.forEach((item, item, s)=>{ console.log(item, item, s) })
item
===index
- Map:用于存储多个键值对数据,键名可以是任意值,例如对象
创建map集合
new Map(iterable) // 要求每一次迭代的结果必须是一个长度为2的数组,数组第一项表示键,数组的第二项表示值
例:const mp = new Map([['a', 1], ['b', 2], ['c', 3]])
对set集合进行操作:
1).set(键, 值)
:设置一个map键值对,键、值都可以是任意类型
如果键不存在,则添加;如果存在,则修改。判断方式同set
2).get(键)
:获取键的值
2).has(键)
:判断map集合中是否存在键
3).delete(键)
:删除匹配的键
4).clear()
:清空map集合
5).size
:获取map集合元素的数量,只读
和数组进行相互转换
使用const mp = new Map([['a', 1], ['b', 2], ['c', 3]]) const arr = [...mp]
for-of
遍历,每次得到的是长度为2的数组
使用for (const item of mp) { console.log(item) }
forEach
遍历,参数分别为值、键、本身
mp.forEach((value, key, mp)=>{ console.log(value, key, mp) })
十、反射Reflect
与代理Proxy
Reflect的一些API
Reflect.set(target, propertyKey, value)
: 设置对象target的属性propertyKey的值为value,等同于给对象的属性赋值
Reflect.get(target, propertyKey)
: 读取对象target的属性propertyKey,等同于读取对象的属性值
Reflect.apply(target, thisArgument, argumentsList)
:调用一个指定的函数,并绑定this和参数列表。等同于函数调用
Reflect.deleteProperty(target, propertyKey)
:删除一个对象的属性
Reflect.defineProperty(target, propertyKey, attributes)
:类似于Object.defineProperty,不同的是如果配置出现问题,返回false而不是报错
Reflect.construct(target, argumentsList)
:用构造函数的方式创建一个对象
Reflect.has(target, propertyKey)
: 判断一个对象是否拥有一个属性
…
使用new Proxy()
创建代理对象,与Reflect搭配使用
const proxy = new Proxy(target, {
set(target, prop, value) {
Reflect.set(target, prop, value);
render();
},
get(target, prop){
return Reflect.get(target, prop);
}
})
function ConstructorProxy(Class, ...propNames) {
return new Proxy(Class, {
construct(target, argumentsList) {
const obj = Reflect.construct(target, argumentsList)
propNames.forEach((name, i) => {
obj[name] = argumentsList[i];
})
return obj;
}
})
}