1.let 关键字
let 关键字用来声明变量,使用 let 声明的变量有几个特点:
- 不允许重复声明
- 块级作用域
- 不存在变量提升
- 不影响作用域链
应用场景:以后声明变量使用 let 就对了
e.g:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>let 关键字</title>
<style type="text/css">
.item {
width: 200px;
height: 200px;
border: 1px solid #000000;
}
</style>
</head>
<body>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<script type="text/javascript">
//1.不允许重复声明
// let a = 1
// let a = 2
// console.log(a)
//2.块级作用域
// {
// let a = 2
// }
// console.log(a)
//3.不存在变量提升
// console.log(a)
// let a = 3
//4.不影响作用域链
// {
// let a = 1
// function fn() {//此函数相当于var fn = function(){},因此存在变量提升,fn可在块级作用域外被调用
// console.log(a, 'ssss')
// }
// fn()
// }
//实例
let items = document.querySelectorAll(".item")
//这样就可以
// for (let i = 0; i < items.length; i++) {//利用了块级作用域
// items[i].onclick = function () {
// items[i].style.background = "red"
// }
// }
//第二种做法(利用闭包)
// for (var i = 0; i < items.length; i++) {
// (function(i){
// items[i].onclick = function(){
// items[i].style.background = "red"
// }
// })(i)
// }
//第三种做法
// for (var i = 0; i < items.length; i++) {
// items[i].index = i
// items[i].onclick = function(){
// items[this.index].style.background = "red"
// }
// }
</script>
</body>
</html>
2.const 关键字
const 关键字用来声明常量,const 声明有以下特点
- 声明必须赋初始值
- 标识符一般为大写
- 不允许重复声明
- 值不允许修改
- 块级作用域
- 不存在变量提升
- 不影响作用域链
- 但是可以修改const修饰的数组,对象变量中的元素
注意: 对象属性修改和数组元素变化不会触发 const 错误
应用场景:声明对象类型使用 const,非对象类型声明选择 let
e.g:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>const 关键字</title>
</head>
<body>
<script type="text/javascript">
// const 关键字用来声明常量,const 声明有以下特点
// 1) 声明必须赋初始值
// const a; 报错
// 2) 标识符一般为大写(行业中的常识)
// const CAR = "福特"
// 3) 不允许重复声明
// const a = 1
// const a = 2
// 4) 值不允许修改
// const CAR = "福特"
// CAR = "长安"
// 5) 块级作用域
// {
// const A = 200
// }
// console.log(A)
//6 不存在常量提升
// console.log(c)
// const c = 3
//7 但是可以修改const修饰的数组,对象变量中的元素
const a = ['uzi','ming']
a.push('letem')
</script>
</body>
</html>
3.变量的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称
为解构赋值。
注意:频繁使用对象方法(属性)、数组元素,就可以使用解构赋值形式
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
//1.将数组中的元素解构为变量,方便以后复用
// const name = ['孙悟空','猪八戒','沙和尚']
// let [sun,bajie] = name
// console.log(sun) //孙悟空
// console.log(bajie) //猪八戒
//2.将对象中的属性解构为变量,方便以后复用
// const wukong = {
// name: '大师兄',
// play: function(){
// console.log("大师兄打白骨精")
// }
// }
// let {name,play} = wukong
// console.log(name)
// console.log(play)
// play()
</script>
</body>
</html>
4.模板字符串
模板字符串是增强版的字符串,用反引号(` (Tab上面的按键))标识,
特点
- 字符串中可以出现换行符
- 可以使用 ${xxx} 形式输出变量
注意:当遇到字符串与变量拼接的情况使用模板字符串
5.对象简化写法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这
样的书写更加简洁
注意:对象简写形式简化了代码,所以以后用简写就对了
6.箭头函数
ES6 允许使用「箭头」(=>)定义函数。
箭头函数的注意点:
- 如果形参只有一个,则小括号可以省略
- 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的
执行结果- 箭头函数 this 指向声明时所在作用域下 的this值,this值是静态的
- 箭头函数不能作为构造函数实例化对象
- 不能使用 arguments
注意:箭头函数不会更改 this 指向,用来指定回调函数会非常合适
定时器中的回调函数,数组中的回调函数
7.rest参数
ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments
/**
* 作用与 arguments 类似
*/
function add(...args){
console.log(args); //结果是数组
}
add(1,2,3,4,5);
/**
* rest 参数必须是最后一个形参
*/
function minus(a,b,...args){
console.log(a,b,args);
}
minus(100,1,2,3,4,5,19);
注意:rest 参数非常适合在函数参数不定个数的场景下使用
函数形参默认值
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
//注意: 设置默认值的那个参数必须放在形参列表最后,否则没有意义
function add(a,b,c=6){
console.log(a+b+c) //9
}
add(1,2)
//函数参数默认值与解构赋值结合
function connect({host,port,username,password='home'}){
console.log(host)
console.log(port)
console.log(username)
console.log(password)
}
connect({
host: 'www.baidu.com',
port: 80,
username: 'admin'
// password: 'admin'
})
</script>
</body>
</html>
8.spread 扩展运算符
扩展运算符(spread)也就是三个点(…),将一个数组(对象)转为用逗号分隔的参数序列,对数组(对象)进行解包.
let tfboys = ['德玛西亚之力','德玛西亚之翼','德玛西亚皇子'];
function fn(){
console.log(arguments); //'德玛西亚之力','德玛西亚之翼','德玛西亚皇子'
}
fn(...tfboys)
/**
* 展开对象
*/
let skillOne = {
q: '致命打击',
};
let skillTwo = {
w: '勇气'
};
let skillThree = {
e: '审判'
};
let skillFour = {
r: '德玛西亚正义'
};
let gailun = {...skillOne, ...skillTwo,...skillThree,...skillFour};
//{q: '致命打击',w: '勇气',e: '审判',r: '德玛西亚正义'}
9.Symbol
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是
JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol 特点
- Symbol 的值是唯一的,用来解决命名冲突的问题
- Symbol 值不能与其他数据进行运算
- Symbol 定 义 的 对 象 属 性 不 能 使 用 for…in 循 环 遍 历 , 但 是 可 以 使 用
Reflect.ownKeys 来获取对象的所有键名
注: 遇到唯一性的场景时要想到 Symbol
e.g:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Symbol 应用</title>
</head>
<body>
<script type="text/javascript">
//创建 Symbol
let s1 = Symbol();
// console.log(s1, typeof s1);
//添加标识的 Symbol
let s2 = Symbol('尚硅谷');
let s2_2 = Symbol('尚硅谷');
// console.log(s2 === s2_2,s2); //false
//使用 Symbol for 定义
let s3 = Symbol.for('尚硅谷');
let s3_2 = Symbol.for('尚硅谷');//会从全局中找是否有Symbol('尚硅谷'),有就返回之前的,没有就新创建一个
// console.log(s3 === s3_2,s3); //true
//1.用于向arr对象中添加属性或者方法时不确定之前有没有和我一样的属性名
// let arr = {
// up: function(){
// console.log('我是up方法')
// }
// }
// let tem = {
// up: Symbol()
// }
// arr[tem.up] = function(){
// console.log("我是symbol的up")
// }
// let s = Symbol()
// arr[s] = function(){
// console.log("我是symbol的up222")
// }
// arr[tem.up]()
// arr[s]()
// console.log(arr)
//2.第二种添加方式
// let xiyouji = {
// name: "孙悟空",
// [Symbol('say')]: function(){
// console.log('say method')
// }
// }
// console.log(Reflect.ownKeys(xiyouji)[1])
// xiyouji[Reflect.ownKeys(xiyouji)[1]]()
/**
* Symbol内置对象属性的用法示例
*/
// let obj = {name: '王二麻子'}
// class Person{
// static [Symbol.hasInstance] = function(param){
// console.log(param)//{name: '王二麻子'}
// console.log(param === obj);//true
// }
// }
// console.log(obj instanceof Person)//false
//第二个示例
// let a = [1,2,3]
// let b = [4,5,6]
// b[Symbol.isConcatSpreadable] = false
// let arr = a.concat(b)
// console.log(arr)
//(4) [1, 2, 3, Array(3)]
</script>
</body>
</html>
Symbol 内置值
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值.指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行
Symbol内置对象 | 自动执行的场景 |
---|---|
Symbol.hasInstance | 当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法 |
Symbol.isConcatSpreadable | 对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat()时,是否可以展开 |
… | … |
10.迭代器
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提
供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
- ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 使用
- 原生具备 iterator 接口的数据(可用 for of 遍历)
a) Array
b) Arguments
c) Set
d) Map
e) String
f) TypedArray
g) NodeList- 工作原理
a) 创建一个指针对象,指向当前数据结构的起始位置
b) 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
c) 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
d) 每调用 next 方法返回一个包含 value 和 done 属性的对象
注: 需要自定义遍历数据的时候,要想到迭代器。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
const team = {
name: 'EDG',
per: [
'deft',
'meiko',
'panw',
'clearlove',
'korol'
],
[Symbol.iterator](){
//索引
let i = 0
return {
next: ()=>{
//简化成一行代码
return i < this.per.length?{value: this.per[i++],done: false}:{done: true}
//繁琐的写法
// if(i < this.per.length){
// return {value: this.per[i++],done: false}
// }else{
// return {value: undefined,done: true}
// }
}
}
}
}
for (let v of team) {
console.log(v)
}
</script>
</body>
</html>
11.生成器
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
特点
- * 的位置没有限制
- 生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到
yield 语句后的值- yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next
方法,执行一段代码- next 方法可以传递实参,作为 yield 语句的返回值
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
//1s后输出111-->2s之后输出222-->3s之后输出333
function one(){
setTimeout(()=>{
console.log(111)
iterator.next()
}, 1000);
}
function two(){
setTimeout(()=>{
console.log(222)
iterator.next()
}, 2000);
}
function three(){
setTimeout(()=>{
console.log(333)
iterator.next()
}, 3000);
}
/**
* 声明生成器函数
* yield作用就是将函数代码块分隔开,只有调用一次iterator.next()才执行一个代码块,如下:3个yield分隔了4个代码块
*/
function* gen(){
yield one()
yield two()
yield three()
}
let iterator = gen()
iterator.next()
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
//模拟流程: 先获取用户数据--->根据用户数据获取订单数据--->根据订单数据获取商品数据
function getUsers(){
setTimeout(()=>{
let data = '用户数据'
iterator.next(data)
}, 1000);
}
function getOrders(){
setTimeout(()=>{
let data = '订单数据'
iterator.next(data)
}, 1000);
}
function getGoods(){
setTimeout(()=>{
let data = '商品数据'
iterator.next(data)
}, 1000);
}
/**
* 声明生成器函数
* yield作用就是将函数代码块分隔开,只有调用一次iterator.next()才执行一个代码块,如下:3个yield分隔了4个代码块
*/
function* gen(){
let users = yield getUsers()
console.log(users)
let orders = yield getOrders()
console.log(orders)
let goods = yield getGoods()
console.log(goods)
}
let iterator = gen()
iterator.next()
</script>
</body>
</html>
12.Promise
Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,
用来封装异步操作并可以获取其成功或失败的结果。
详细资料及面试题请参考JavaScript专栏下的Promise
13.Set
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯
一的,集合实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of…』进
行遍历,集合的属性和方法:
- size 返回集合的元素个数
- add 增加一个新元素,返回当前集合
- delete 删除元素,返回 boolean 值
- has 检测集合中是否包含某个元素,返回 boolean 值
- clear 清空集合,返回 undefined
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
let arr = [1,2,3,4,5,4,3,2,1]
//1.数组去重
// let result = [...new Set(arr)]
// console.log(result)
//2.交集
let arr2 = [4,5,6,4,5]
// let result = [...new Set(arr)].filter((item)=> new Set(arr2).has(item))
// console.log(result)
//3.并集
// let result = [...new Set([...arr,...arr2])]
// console.log(result)
//4.差集
let result = [...new Set(arr)].filter((item)=> !(new Set(arr2).has(item)))
console.log(result)
</script>
</body>
</html>
14.Map
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”
的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了
iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。Map 的属
性和方法:
- size 返回 Map 的元素个数
- set 增加一个新元素,返回当前 Map
- get 返回键名对象的键值
- has 检测 Map 中是否包含某个元素,返回 boolean 值
- clear 清空集合,返回 undefined
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//创建一个空 map
let m = new Map();
//创建一个非空 map
let m2 = new Map([
['name', 'dsfaf'],
['slogon', 'dsffgdg']
]);
//获取映射元素的个数
// console.log(m2.size);//2
//添加映射值
// console.log(m2.set('age', 6));
// console.log(m2);
//获取映射值
// console.log(m2.get('age'));
//检测是否有该映射
// console.log(m2.has('age'));
//清除
// console.log(m2.clear());
</script>
</body>
</html>
15.class
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对
象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是
一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象
原型的写法更加清晰、更像面向对象编程的语法而已。
知识点:
- class 声明类
- constructor 定义构造函数初始化
- extends 继承父类
- super 调用父级构造方法
- static 定义静态方法和属性 (是在class的对象属性上)
- 父类方法可以重写
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
class Person {
//静态属性是Person的属性,不是在Person的prototype上
static header = '头'
constructor(name, age) {
this.name = name
this.age = age
}
play() {
console.log('人生如戏')
}
//get set方法 作用:可以根据具体的需求动态的拿到想要的数据
get white(){
return 120
}
set white(newname){
this.name = newname
}
static say(){//静态方法是Person的属性,不是在Person的prototype上
console.log('hello');
}
}
let p = new Person('张三',10)
console.log(p,Person.header)
Person.say()
class Student extends Person{
constructor(name,age,school){
super(name,age)
this.school = school
}
study(){
console.log('好好学习')
}
}
let stu = new Student('王二麻子',16,'南大')
// console.log(stu)
</script>
</body>
</html>
数值扩展
二进制,八进制,十六进制
ES6 提供了二进制,八进制,十六进制数值新的写法,分别用前缀 0b ,0o ,0x 表示,后面直接跟对应的进制数字就可以了
Number.isFinite() 与 Number.isNaN()
Number.isFinite() 用来检查一个数值是否为有限的
Number.isNaN() 用来检查一个值是否为 NaN
Number.parseInt() 与 Number.parseFloat()
ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变。
Math.trunc
用于去除一个数的小数部分,返回整数部分。
Number.isInteger
Number.isInteger() 用来判断一个数值是否为整数
对象扩展
ES6 新增了一些 Object 对象的方法
- Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN)
- Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象
- proto、setPrototypeOf、 setPrototypeOf 可以直接设置对象的原型
ES7新特性
1.Array.prototype.includes
Includes 方法用来检测数组中是否包含某个元素,返回布尔类型值
2.指数操作符
在 ES7 中引入指数运算符「**」,用来实现幂运算,功能与 Math.pow 结果相同
console.log(3 ** 4);
ES8新特性
1.async 和 await
async 和 await 两种语法结合可以让异步代码像同步代码一样
async 函数
- async 函数的返回值为 promise 对象,
- promise 对象的结果由 async 函数执行的返回值决定
1)如果async函数返回的不是promise对象,则此函数的返回值是成功的promise对象
2)如果async函数返回的是promise对象,则取决于promise对象是否成功
3)抛出错误则是失败的promise对象
await 表达式
- await 必须写在 async 函数中
- await 右侧的表达式一般为 promise 对象
- await 返回的是 promise 成功的值
- await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
2.Object.values 和 Object.entries
- Object.values()方法返回一个给定对象的所有可枚举属性值的数组
- Object.entries()方法返回一个给定对象自身可遍历属性 [key,value] 的数组
ES9新特性
1.正则表达式命名捕获组
ES9 允许命名捕获组使用符号 ?<name>,这样获取捕获结果可读性更强
let str = '<a href="https://www.baidu.com">百度</a>';
const reg = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
const result = reg.exec(str);
console.log(result.groups.url);
console.log(result.groups.text);
2.正则表达式反向断言
ES9 支持反向断言,通过对匹配结果前面的内容进行判断,对匹配进行筛选
//声明字符串
let str = 'JS5211314你知道么 555啦啦啦';
//正向断言
const reg = /\d+(?=啦)/;
const result = reg.exec(str); //555
//反向断言
const reg = /(?<=么)\d+/;
const result = reg.exec(str); //555
3.正则表达式dotAll模式(/s)
正则表达式中点.匹配除回车外的任何单字符,标记 /s 改变这种行为,允许行
终止符出现
let str = `
<ul>
<li>
<a>肖生克的救赎</a>
<p>上映日期: 1994-09-10</p>
</li>
<li>
<a>阿甘正传</a>
<p>上映日期: 1994-07-06</p>
</li>
</ul>`;
//声明正则
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
//执行匹配
// const result = reg.exec(str);
let result;
let data = [];
while (result = reg.exec(str)) {
data.push({ title: result[1], time: result[2] });
}
//输出结果
console.log(data);
ES10新特性
1.Object.fromEntries
将二维数组转换为对象
2.trimStart 和 trimEnd
trimStart清除字符串左侧的空格
trimEnd清除字符串右侧的空格
3.Array.prototype.flat
flat可以将多维数组降为一维数组
ES11新特性
1.class的私有属性
在属性前加#字符即可,私有属性只能在类的内部访问,不能在类的外部访问(使用实例化对象访问私有属性也不行)
2.Promise.allSettled
批量执行互不依赖的异步任务
3.可选链操作符
字符是’ ?. ’
可选链操作符( ?. )允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为空(nullish ) (null 或者 undefined) 的情况下不会引起错误,该表达式短路返回值是 undefined。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined。
4.globalThis 对象
无论任何环境都是指向全局对象的