学习视频
1. let和const
1.1 let
- 变量必须先声明再使用
- 同一变量不能重复声明
- 变量有块级作用域
1.2 const
- 声明常量,常量不能改变
- 常量必须有初始值,不能先声明再赋值
2. 解构
1 数组解构
保持左右的结构一样,安装顺序一一对应
- 完全解构
let [a,b] = [1,2]
console.log(a,b) // 1 2
- 部分解构
let [a] = [1,2]
console.log(a) // 1
- 忽略方式解构
let [ ,b] = [1,2]
console.log(b) // 2
- 嵌套结构
let [,,[a]] = [1,2,[3]]
console.log(a) // 3
- 剩余运算符解构
let [a,...b] = [1,2,3]
console.log(a,b) // 1 [2,3]
- 解构默认值
let [a,b=2] = [1]
console.log(a,b) // 1 2
- 应用:两数交换
let a = 10
let b = 20
[b, a] = [a, b]
console.log(a, b) // 20, 10
2. 对象解构
按属性名对应
- 完全解构
let user = {name:"zhangsan",age:18}
let {age, name} = user
console.log(name, age) // zhangsan 18
- 部分解构
let user = {name:"zhangsan",age:18}
let {name} = user
console.log(name) // zhangsan
- 解构后重命名
let user = {name:"zhangsan",age:18}
let {name:userName,age:userAge} = user
console.log(userName, userAge) // zhangsan 18
- 剩余运算符解构
let user = {name:"zhangsan",age:18,address:'银河系'}
let {name,...rest} = user
console.log(name, rest) // zhangsan {age: 18, address: '银河系'}
- 默认值
let user = {name:"zhangsan",age:18}
let {name, age, address='银河系'} = user
console.log(name, age, address) // zhangsan 18 银河系
3. 字符串解构
- 数组解构字符串
let str = 'qwert'
let [a,b,c,d] = str
console.log(a,b,c,d) // q w e r
- 字符串属性解构
let str = 'qwert'
let {length} = str
console.log(length) // 5
3. 对字符串扩展
1. 模板字符串
- 解决了字符串换行
console.log("字符串
随意换行") // 报错
console.log(`字符串\
可以\
随意换行`) // 字符串可以随意换行
- 更容易的插入变量
let user = {name:"zhangsan",age:18}
console.log(`我叫${user.name},今年${user.age}岁`) //我叫zhangsan,今年18岁
2. 字符串新增的方法
- 是否包含字符串,
includes()
返回值:boolean
// 是否包含字符串 wo
console.log(str.includes('wo')) // true
console.log(str.includes(`oo`)) // false
// 索引0位置开始是否有hel字符串
console.log(str.includes('hel', 0)) // true
- 是否从某个字符串开始,
startsWith()
,返回值:boolean
// he 是否在字符串的开头,也就是索引0开始
console.log(str.startsWith(`he`)); // true
// el 是否从索引1开始
console.log(str.startsWith(`el`,1)) // true
- 是否以某个字符串结尾
endsWith()
,返回值:boolean
// 字符串是否以 ld 结尾
console.log(str.endsWith(`ld`)); // true
// 截取索引从0到4的字符串,是否以 o 结尾
console.log(str.endsWith(`o`,5)); // true
- 返回重复几次字符串,
repeat()
,返回值:string
console.log(str.repeat(3)); // hello worldhello worldhello world
4. 对象的扩展
1. 简化对象中属性名和方法名的写法
// 简化对象中属性名和函数名的写法
let str = `一个字符串`
// 未简写的形式
let obj = {
str: str,
fun: function(){
return '一个函数'
}
}
console.log(obj.str,obj.fun()) //一个字符串 一个函数
// 简写的形式
let obj2 = {
str, // 属性名与引入的对象的名字相同,可以使用简写形式
fun(){
return '又一个函数'
}
}
console.log(obj2.str,obj2.fun()) // 一个字符串 又一个函数
- 对象中的属性名使用
[]
表达式
- 属性名使用
[]
拼接字符串
let lastName = 'last';
let firstName = 'first';
let obj = {
['my' + 'name']:'zhangsan',
[lastName + 'name']:'lisi',
[`${firstName}name`]:'wangwu'
}
console.log(obj); //{myname: 'zhangsan', lastname: 'lisi', firstname: 'wangwu'}
- 对象中的属性名可以是动态的
let arrName = ['zhangsan','lisi','wangwu']
let obj = {}
for(let item of arrName){
obj[item+"Name"]=item
}
console.log(obj) //{zhangsanName: 'zhangsan', lisiName: 'lisi', wangwuName: 'wangwu'}
2. 对象扩展的方法
- Object.assign对象合并
Object.assign(target: {}, source: any)
返回值是合并后的对象
- 第一种情形
let user = {}
let user1 = {name:'zhangsan'}
let user2 = {age:10}
console.log(user === user1) // false
user = Object.assign(user1,user2)
console.log(user1 === user) // true
console.log(user); // {name: 'zhangsan', age: 10}
console.log(user1) // {name: 'zhangsan', age: 10}
console.log(user2) // {age: 10}
- 第二种情形
let user = {}
let user1 = {name:'zhangsan'}
let user2 = {age:10}
Object.assign(user,user1,user2)
console.log(user) // {name: 'zhangsan', age: 10}
console.log(user1) // {name: 'zhangsan'}
console.log(user2) // {age: 10}
- 第三种情形:如有相同的属性,则覆盖属性值
let user1 = {name:'zhangsan',age:33}
let user2 = {age:10}
Object.assign(user1,user2)
console.log(user1) // {name: 'zhangsan', age: 10}
console.log(user2) // {age: 10}
- 应用:初始化对象
let user1 = {name:'',age:0}
let user2 = {...user1}
user1.name = 'zhangsan'
user1.age = 10
console.log(user1) // {name: 'zhangsan', age: 10}
Object.assign(user1,user2)
console.log(user1) // {name: '', age: 0}
- 对象是否相等Object.is
和
===
作用相同
相比较的是两个对象,地址相同返回true,不同返回false
let user1 = {name:'',age:0}
let user2 = {name:'',age:0}
console.log(Object.is(user1,user2)); // false
user1 = user2;
console.log(Object.is(user1,user2)); // true
5. 数组的扩展
1. 扩展运算符...
let arr1 = ['a','b','c']
let arr2 = ['1','2','3']
let arr = ['A',...arr1,...arr2]
console.log(arr) // ['A', 'a', 'b', 'c', '1', '2', '3']
2. 查找 find()
let arr = ['A', 'a', 'b', 'c', '1', '2', '3']
// 返回符合条件的第一个元素
let findResult = arr.find(function(item){
return item > 'b'
})
console.log(findResult); // c
3. 查找 findIndex()
let arr = ['A', 'a', 'b', 'c', '1', '2', '3']
// 返回符合条件的第一个元素下标
let findResult = arr.findIndex(function(item){
return item > 'b'
})
console.log(findResult); // 3
4. 将一组值转换为数组
let arr = Array.of(1,2,3)
console.log(arr); // [1,2,3]
5. 将对象内的值转化为数组
通常使用的对象是无法通过Array.form转换为数组的
- 应用场景:查找class下的所有dom对象,将其转化为数组
var parent = document.querySelectorAll('#myClass');
let children = parent[0].children;
console.log(children);
// 将children转换为真正的数组
let arr = Array.from(children)
console.log(arr);
6. include 方法
ES7 – 2016 新增
- 数组中是否包含某个元素,返回值为
boolean
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr.includes(5); // true
6. 函数的扩展
1. 不同函数中的this
{
// 普通函数
function fn() {
console.log(this) // windows
}
fn()
}
{
// 构造函数
function Person(name) {
this.name = name;
console.log(this) // Person {name: 'zs'}
}
let zs = new Person('zs')
console.log(zs) // Person {name: 'zs'}
}
{
// 函数作为属性值
let obj = {
name: 'obj',
fn() {
console.log(this)
}
}
obj.fn() // {name: 'obj', fn: ƒ}
}
2. 更改this的指向
call(this: Function, thisArg: any, ...argArray: any[])
只在执行call方法这一句代码时改变this的指向(并不是彻底改变函数中this的指向)
// 函数作为属性值
let obj = {
name: 'obj',
fn() {
console.log(`name:${this.name},age:${this.age}`)
}
}
// fn函数的this指向obj,所以没有age的属性值
obj.fn() // name:obj,age:undefined
let obj1 = { age: 18 }
// 将fn函数的this指向obj1,所以没有name的属性值
obj.fn.call(obj1) //name:undefined,age:18
- call携带参数
// 函数作为属性值
let obj = {
name: 'obj',
fn(param) {
console.log(param)
}
}
// fn函数的this指向obj
obj.fn("this指向obj") // this指向obj
let obj1 = { age: 18 }
// 将fn函数的this指向obj1
obj.fn.call(obj1,'this指向obj1') // this指向obj1
apply(this: Function, thisArg: any, argArray?: any)
- 与call方法唯一不同的是传递参数时使用
[]
// 构造函数
function Person() {
console.log(this)
}
let obj = { name: 'obj'}
Person.apply(obj) // {name: 'obj'}
let zs1 = new Person() // Person {}
// 构造函数
function Person(...argArray) {
this.age= 10
console.log(`参数:`,argArray)
console.log('this指向====>',this)
}
let obj = { name: 'obj' }
Person.apply(obj,['arg1','arg2'])
/*
结果:
参数:['arg1', 'arg2']
this指向====> {name: 'obj', age: 10}
*/
let zs1 = new Person('XXX') // Person {}
/*
结果:
参数: ['XXX']
this指向====> Person {age: 10}
*/
- bind
bind
方法返回fn函数
更换this
后的fn函数
- 对上面这句话的解释:
fn函数
还是fn函数
,只不过fn函数
中的this
指向了obj对象
// 普通函数
function fn() {
console.log(this) // {name: 'obj'}
}
let obj = { name: 'obj' }
let newFn = fn.bind(obj)
newFn()
3. 函数中参数设置默认值
- 如果有多个参数,使用默认值的参数要放在参数的最后面
// 默认值参数
function fun (a, b=1000) {
console.log(a, b)
}
7. 箭头函数
1. 箭头函数中的this,指向window
let fun = ()=>{
console.log(this) // window
}
fun()
2. 返回值是对象,使用({......})
let fun = ()=>({name:'zhangsan'})
console.log(fun())
8. 二进制和八进制
let num1 = 0b101; // 0b或者0B 二进制
let num2 = 0o123; // 0o或者0O 八进制
let num3 = 0xff; // 0x或者0X 十六进制
console.log(num1, num2, num3); // 5 83 255
9. symbol
10. Class
1. 基本结构
class Person {
// 构造器(类似构造函数)
constructor(name, age) {
this.name = name;
this.age = age;
}
// 方法
sayHi(){
console.log(`Hi, I am ${this.name}`);
}
}
2. 继承
// 继承
class Student extends Person {
constructor(name, age, grade) {
// 调用父类的构造函数
super(name, age); // 调用父类的构造函数,不许写在第一行
this.grade = grade;
}
study() {
console.log(`${this.name} is studying`);
}
}
3. get和set属性
class Person {
pname // 定义属性,可以不通过构造器定义属性
// 对外使用 name 属性,类中的属性实际是pname
set name(value) {
console.log('set name 对name的属性值进行校验等操作')
this.pname = value;
}
get name() {
console.log('get name 对name的属性值进行操作')
return this.pname;
}
}
const person = new Person();
person.name = 'John' // set name 对name的属性值进行校验等操作
console.log(person.name); // get name 对name的属性值进行操作 John
4. 类的静态属性和方法
class Person {
// static: 定义静态属性和方法的关键字
static type
static sayHello() {
console.log(this); // 指向Person类
}
walk() {
console.log(this); // 指向实例化对象
}
}
// 静态属性和方法的使用
Person.type = 'person';
console.log(Person.type); // person
Person.sayHello(); // 静态方法中的 this 指向类本身
/*结果:
class Person {
static type
static sayHello() {
console.log(this);
}
walk() {
console.log(this);
}
}
*/
const person = new Person()
person.walk(); // walk中的this指向的是person实例
11. Set
1. Set集合的增删改查
- Set,是一种数据结构,和数组类似,但是Set集合里面的元素不能重复
- 创建Set集合
// new关键字,创建Set集合
const set1 = new Set()
// 把数组转化为Set
const set2 = new Set([1, 2, 3])
- 将数组转换为Set集合
// 把数组转化为Set
const set2 = new Set([1, 2, 3])
const arr = [1, 2, 3, 4, 5, 1, 2]
const set3 = new Set(arr) // {1, 2, 3, 4, 5}
- 获取set集合中元素的数量
// 获取Set集合的长度 .size
let size = set3.size // size是Set集合的属性,不是方法
- 添加元素
// 添加元素 add()
const set4 = set3.add(4)
- 删除元素
// 删除元素 delete()
const set5 = set3.delete(2)
- 判断集合中是否有某个元素
// 判断元素是否存在 has()
const isExist = set3.has(2) // 返回值是布尔值
- 清空集合
// 清空集合 clear()
set3.clear()
2. 遍历Set
set
的数据结构和数组相似,但是它没有index
set
是以键值对的形式储存的,但是set的键和值是相等的
- 通过遍历数组和Set集合比较两个的数据结构
遍历数组
// 数组的遍历
const arr = ['a', 'b', 'c', 'd']
arr.forEach((value,index,array) => {
console.log(`value===>${value},index===>${index},array===>`,array);
})`在这里插入代码片`
// 结果
value===>a,index===>0,array===> (4) ['a', 'b', 'c', 'd']
value===>b,index===>1,array===> (4) ['a', 'b', 'c', 'd']
value===>c,index===>2,array===> (4) ['a', 'b', 'c', 'd']
value===>d,index===>3,array===> (4) ['a', 'b', 'c', 'd']
遍历Set集合
const list = new Set(['a', 'b', 'c', 'd'])
list.forEach((value,index,set) => {
console.log(`value===>${value},index===>${index},set===>`,set);
})
// 结果
value===>a,index===>a,set===> Set(4) {'a', 'b', 'c', 'd'}
value===>b,index===>b,set===> Set(4) {'a', 'b', 'c', 'd'}
value===>c,index===>c,set===> Set(4) {'a', 'b', 'c', 'd'}
value===>d,index===>d,set===> Set(4) {'a', 'b', 'c', 'd'}
结论: set集合
中没有索引,是以键值对
的结构存储元素,并且键与值是一样的
for... of
const list = new Set(['a', 'b', 'c', 'd'])
for (let item of list) {
console.log(item); // a b c d
}
- 将set结构转换为数组结构后遍历
- Array.from
const list = new Set(['a', 'b', 'c', 'd'])
Array.from(list).forEach((value,index,set) => {
console.log(`value===>${value},index===>${index},set===>`,set);
})
// 结果
value===>a,index===>0,array===> (4) ['a', 'b', 'c', 'd']
value===>b,index===>1,array===> (4) ['a', 'b', 'c', 'd']
value===>c,index===>2,array===> (4) ['a', 'b', 'c', 'd']
value===>d,index===>3,array===> (4) ['a', 'b', 'c', 'd']
- […set]
let list = new Set(['a', 'b', 'c', 'd']);
[...list].forEach((value,index,array) => {
console.log(`value===>${value},index===>${index},array===>`,array);
})
12 Map
Map:
数据结构,以键值对的形式储存,但是键在集合中唯一
1. Map集合的增删改查
- 创建Map
const map = new Map();
map.set("IN", "India");
map.set("FR", "France");
console.log(map)
// {'IN' => 'India', 'FR' => 'France'}
const map1 = new Map([["IN","India"],["FR","France"]])
- 获取集合中某个键的值
let v = map.get("IN")
console.log(v) // India
- 删除元素
map.delete("IN") // 删除键值为'IN'的元素
console.log(map)
- 清空集合
map.clear()
console.log(map) //Map(0) {size: 0}
- 集合中元素的数量
let size = map.size
- 修改键的值
const map = new Map();
map.set("IN", "India");
map.set("IN","XXXXX")
console.log(map) // {'IN' => 'XXXXX'}
2. 遍历Map
- 获取Map所有的键
const map = new Map();
map.set("IN", "India");
map.set("FR", "France");
map.set("USA", "United States")
const keys = map.keys();
console.log(keys); // {'IN', 'FR', 'USA'}
- 获取Map所有的值
const values = map.values();
console.log(values); // {'India', 'France', 'United States'}
for...of
for(let [key,value] of map){
console.log("key==> ",key,"value===> ",value);
}
/*
key==> IN value===> India
key==> FR value===> France
key==> USA value===> United States
*/
for(let item of map){
console.log(item);
}
/*
['IN', 'India']
['FR', 'France']
['USA', 'United States']
*/
forEach
map.forEach((value,key)=>{
console.log("key==>",key,"value===>",value);
})
/*
key==> IN value===> India
key==> FR value===> France
key==> USA value===> United States
*/
13. Iterator 迭代器
迭代器:
- 实现Symbol.iterator方法的数据解构都可以通过for…of遍历数据
- 迭代器必须实现next(),它返回一个对象,该对象有两个属性:value 和 done。value 是当前元素的值,done 是布尔值,表示是否已经到达了序列的末尾。
-
原生实现迭代器的数据类型
- Array(数组)
- String(字符串)
- Map(映射表)
- Set(集合)
- NodeList 和 HTMLCollection: 查询器返回的结果
- Generator 函数: Generator 函数本身就是一个迭代器工厂
- TypedArray(类型化数组)
- Arguments 对象(传递给函数的参数)
-
在对象中使用迭代器
let obj = {
arr:["苹果","香蕉","梨"],
// 创建迭代器
[Symbol.iterator](){
let index = 0;
return {
next(){
if(index < obj.arr.length){
return {value:obj.arr[index++],done:false}
}else{
return {value:undefined,done:true}
}
}
}
},
}
// 对象中实现迭代器后可以使用for..of
for(let item of obj){
console.log(item)
}
// 迭代器中的next()方法
let it = obj[Symbol.iterator]();
console.log(it.next()); // {value: '苹果', done: false}
console.log(it.next()); // {value: '香蕉', done: false}
console.log(it.next()); // {value: '梨', done: false}
console.log(it.next()); // {value: undefined, done: true}
14. Promise
1. 基本使用
let promise = new Promise((resolve, reject) => {
// resolve("成功")
reject("失败")
});
promise.then(value => {
console.log(value) // 成功
},err => {
console.log(err) // 失败
});
- new Promise中参数是一个函数,函数中有两个参数,第一个函数执行,对应then方法的第一个函数执行;第二个函数执行,则then方法的第二个函数执行
- then里面有两个参数,参数数据类型是函数
function resolve(value){}
function reject(reason){}
function executor(resolve, reject){
// 在resolve和reject执行前,promise为待定状态(pending): 初始状态,既没有被兑现,也没有被拒绝。
resolve("成功") // 如果执行resolve函数,promise为成功状态(fulfilled): 意味着操作成功完成。
// reject("失败") // 如果执行reject函数,promise为失败状态(rejected): 意味着操作失败
}
let promise = new Promise(executor)
function thenResolve(value){ // promise状态变为成功状态执行该函数
// value 是 resolve函数的参数
console.log(value)
}
function thenReject(reason){ // promise状态变为失败状态执行该函数
// reason 是 reject函数的参数
console.log(reason)
}
promise.then(thenResolve, thenResolve)
2. Promise的链式调用
// 链式调用
let ajax = (url) => {
return new Promise((resolve) => {
console.log('请求地址:' + url)
setTimeout(resolve,2000)
})
}
ajax('A_url').then(res=>{
console.log('A请求返回的结果')
return ajax("B_url")
}).then(res=>{
console.log('B请求返回的结果')
return ajax('C_url')
}).then(res=>{
console.log('C地址返回的结果')
})
/*
请求地址:A_url
A请求返回的结果
请求地址:B_url
B请求返回的结果
请求地址:C_url
C地址返回的结果
*/
3. Promise.all
Promise.all( [ promise1, promise2, promise3 ] )
- 将多个
promise
绑定到一起,直到所有的promise
都变为fulfilled
(成功)状态时,一起返回结果
let p1 = new Promise((resolve, reject)=>{
resolve("P1")
})
let p2 = new Promise((resolve, reject)=>{
resolve("P2")
// reject("P2")
})
let p3 = new Promise((resolve, reject)=>{
resolve("P3")
// reject("P3")
})
Promise.all([p1,p2,p3]).then(res=>{
console.log(res) // ['P1', 'P2', 'P3']
},value=>{
console.log(value)
})
- 如果有多个promise返回失败状态,则Promise.all中只会接收最先变为失败状态的promise
4. Promise.race
- 数组中promise,谁的状态(成功或失败)先改变,返回谁的结果
let p1 = new Promise((resolve, reject)=>{
setTimeout(()=>{
reject("P1")
},2000)
})
let p2 = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve("P2")
// reject("P2")
},1000)
})
let p3 = new Promise((resolve, reject)=>{
setTimeout(resolve,3000,"P3")
})
Promise.race([p1,p2,p3]).then(res=>{
console.log(res) // P2
},value=>{
console.log(value)
})
5. catch
作用:当
promise
状态变为fulfilled
,then
执行成功的回调,但是在回调中产生的异常没有处理方式
- catch可以捕获所有的异常,无论是
promise
还是then
里面产生的 - 如果没有错误的回调,
catch
也能接收rejected
状态
let promise = new Promise((resolve, reject) => {
// throw new Error("错误")
// resolve("成功")
reject("失败")
});
promise.then(value => {
throw new Error("错误")
console.log(value) // 成功
})
.catch(err => {
console.log("catch:",err) // 失败
})
6. finally
15. Module 模块的导出和导入
1. 基本使用
- 导入和导出
- 导出的变量不能重新赋值
export let var1 = 1;
export let obj1 = {
a: 1,
}
export let fun1 = ()=>{};
import {var1, obj1, fun1} from './module.js'
let var2 = 2;
let obj2 = {
b: 2,
}
let fun2 = ()=>{};
export {var2, obj2, fun2};
import {var2, obj2, fun2} from './module.js';
- 使用别名
as
- 在export中使用别名
let var2 = 2;
let obj2 = {
b: 2,
}
let fun2 = ()=>{};
export {
var2 as var3,
obj2 as obj3,
fun2 as fun3,
}
import {var3, obj3, fun3} from './module.js'
- 在import中使用别名
let var2 = 2;
let obj2 = {
b: 2,
};
let fun2 = () => {};
export { var2, obj2, fun2 };
import {var2 as var3, obj2 as obj3, fun2 as fun3} from './module.js'
2. 整体导入 * as
export let var1 = 1;
export let obj1 = {
a: 1,
};
export let fun1 = () => {};
import * as myName from './module.js'
// 使用
console.log(myName.var1) // 1
console.log(myName.obj1) // {a: 1}
console.log(myName.fun1) // () => {}
3. 默认导出 default
,匿名导入
- 在一个文件中只能有一个default,但是不影响普通的导出方式
- 导入时名字不需要加
{}
let var2 = 2;
let obj2 = {
b: 2,
};
let fun2 = () => {};
export default {
var2,
obj2,
fun2,
};
import myName from './module.js'
console.log(myName.var2) // 2
console.log(myName.obj2) // {a: 2}
console.log(myName.fun2) // () => {}
- 默认导出匿名函数
export default function () {
console.log("hello world");
};
import myName from './module.js'
myName() // hello world
- 默认导出匿名对象
export default {
name: "zhangsan",
age: 18,
talk(){
console.log("hello world");
}
};
import myName from './module.js'
myName.age = 20
myName.talk() // hello world
console.log(myName) // {name: 'zhangsan', age: 20, talk: ƒ}
4. 在html中使用Module
type="module"
<script type="module">
import {var1} from './module.js'
console.log(var1)
</script>