ES全称ECMAScript,是脚本语言的规范。为什么要学习ES6?
1、语法简洁,功能方法
2、框架开发与应用
3、前端求职的必备技能
1、let、const
let 定义变量
- 变量不能重复声明
- 块级作用域
- 不存在变量提升
- 不影响作用域链
const 定义常量
- 一定要赋初始值 (不然会报错:SyntaxError: Missing initializer in const declaration)
- 一般常量使用大写(语法规则)
- 常量的值不能修改(不然会报错:TypeError: Assignment to constant variable.)
- 块级作用域
- 对于数组和对象的元素修改,不算对常量的修改,所以不会报错
2、解构赋值
es6允许按照一定模式从数组和对象中提取值,对变量进行赋值。简便操作,提高效率。
- 数组的解构赋值 (命名取值只与数组顺序有关)
let arr = ['apink', 'rose', 'jennie']
,使用:let [a, r, j] = arr
- 对象的解构赋值 (命名要与对象中的key一致)
let obj = {name: 'rita', age: '18', color: 'pink'}
, 使用let {name,color,age} = obj
3、模板字符串
es6引入新的声明字符串的方式,字符串和变量拼接,以及直接出现换行符
4、es6简化对象写法
es6允许在大括号里直接写变量和函数,作为对象的属性和方法,这样书写更加简洁。
简略了写法:name, // name => name:name
,以及change:function(){} => change(){}
5、箭头函数
let fn = function(){
}
let fn = () => {
}
特性:
- this是静态的。this始终指向函数声明时所在的作用域下的this的值
let getname1 = function(){
console.log(this.name);
}
let getname2 = () => {
console.log(this.name);
}
window.name = 'lorretta'
const person = {
name : 'rita'
}
getname1().call(person) // rita
getname2().call(person) // lorretta
- 不能做为构造函数去实例化对象
let Person = (nam, age) => {
this.nam = nam
this.age = age
}
let me = new Person('rita', 18)
// TypeError: Person is not a constructor
- 不能使用arguments对象
let fn = ()=>{
console.log(arguments)
}
fn(1,2,3)
// Uncaught ReferenceError: arguments is not defined
- 箭头函数的简写
1)当形参有且只有一个的时候,可以省略小括号
2)当代码体只有一句时,可以省略花括号,此时return必须省略 - 适用场景
1)适合与this无关的回调,如定时器、数组的返回等
2)不适合与this有关的回调,如dom里的事件回调,对象里的方法等
6、函数参数的默认值
let fn = function(a,b,c=10){
return a + b + c
}
fn(1,2,) //13
----------
function connect({host="127.0.0.1",username,password, port}){
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
connect({
host: 'atguigu.com', username: 'root', password: 'root', port: 3306
})
- 形参初始值,具有默认的参数,一般位置靠最后(潜规则)
- 与解构赋值结合,可以设置默认值
7、rest
es6引入rest参数,用于获取参数的实参,用来代替arguments
function date_es5(){
console.log(arguments);
// ['hello', 'world', 'hi', callee: ƒ, Symbol(Symbol.iterator): ƒ] 是对象
}
date_es5('hello', 'world', 'hi')
function date_es6(...args){
console.log(args); // ['hello1', 'world2', 'hi3'] 是一个数组
}
date_es6('hello1', 'world2', 'hi3')
//rest 参数必须要放到参数最后
function fn(a,b,...args){
console.log(a);
console.log(b);
console.log(args);
}
fn(1,2,3,4,5,6); // 1、 2、 [3, 4, 5, 6]
8、扩展运算符
...扩展运算符能将数组转化为逗号分隔的参数序列,可以做什么:
- 数组的合并
let newArr = [...arr1, ...arr2]
- 数组的克隆(引用数据类型,是浅拷贝)
浅拷贝:就是拷贝变量所存的值,如果是引用变量,那拷贝的就是它里面的地址 - 将伪数组转成真正的数组
[...divArr]
,这样就可以使用数组的map、filter等方法
9、symbol
- 是原始数据类型,值是唯一的,symbol就是用来创建全局唯一的值
- 作用:为对象快速且安全的添加,独一无二的自定义的属性和方法(symbol值是唯一的,这么做应该是为了防止命名冲突)
- 不能进行运算
- symbol定义的对象属性不能用for...in进行循环遍历
- 数据类型
【usonb】:undefined、string、symbol、object、null、number、boolean
// 1、Symbol创建
let s1 = Symbol('rita')
let s2 = Symbol('rita')
// 虽然有两个rita, 但是编号是不一致的,所以不会相等
console.log(s1 == s2); // false
// 2、Symbol.for创建,这时可以得到唯一的symbol值
let s3 = Symbol.for('meiyun')
let s4 = Symbol.for('meiyun')
console.log(s3 == s4); // true
// 3、不能运算,不能进行加减乘除
false? s1 + 100 : ''
// 报错:Uncaught TypeError: Cannot convert a Symbol value to a number
// 4、作用:为对象快速且安全的添加,独一无二的自定义的属性和方法
// 5、实例:为game添加同名的up方法,且不会覆盖原有的方法
let game = {
// 内置的重名方法
up(){
console.log('这是内置的up方法');
},
// 添加方式1
[up=Symbol.for('up')]:function(){
console.log('1、Symbol里的say方法, 写在对象上');
}
}
// 添加方式2
let method = {
up: Symbol(),
}
game[method.up] = function() {
console.log('2、Symbol里的up方法, 写在自定义的对象method里');
}
// 进行调用
console.log(game.up()); // 这是内置的up方法
console.log(game[up]()); // 1、Symbol方法, 写在对象上
console.log(game[method.up]()); // 2、Symbol方法, 写在自定义的对象method里
10、迭代器iterator
- 迭代器是一种接口,任何数据结构只要部署了iterator接口,就可进行遍历。
- 有next执行方法,返回对象里包含{value, done}
// 自定义一个迭代器方法,遍历数组对象,返回page里的值
let obj = {
name: 'home',
page: [
'search',
'card',
'list',
'detail',
],
// 自定义iterator接口方法 包含{value, done}
[Symbol.iterator](){
let arr = this.page
let idx = 0
return {
next:()=>{
if (idx<arr.length) {
let result = {value:arr[idx], done: false}
idx++
return result
} else {
return {value:undefined, done: true}
}
}
}
}
}
// for of 进行对象遍历
for (const v of obj) {
console.log(v); // search、card...
}
for...of...遍历对象,返回键值value
for...in...遍历对象,返回键名key
forEach()
map()
filter()
11、生成器generator
- 生成器是特殊的函数,由于异步编程,yield函数代码的分隔符,可以与for...of循环相结合
- 生成器函数可以让几个方法顺序执行,异步编程的解决方法,next()方法
function getUser(){
setTimeout(() => {
console.log('用户数据')
iterator.next()
}, 1000);
}
function getShop(){
setTimeout(() => {
console.log('订单数据')
iterator.next()
}, 1000);
}
function getGoods(){
setTimeout(() => {
console.log('商品数据')
}, 1000);
}
function * gen(){
let user = yield getUser()
let order = yield getShop()
let goods = yield getGoods()
}
let iterator = gen()
iterator.next()
// 一秒后:用户数据 =>二秒后:订单数据 =>三秒后:商品数据
12、promise
- 异步编程的解决方法,可与ajax进行接口请求数据的封装
- 具体可见笔记:跟着B站学前端之promise源码解析与封装 - 简书 (jianshu.com)
13、Set()
es6提供了新的数据结果Set,它类似于数组,但成员的值都是唯一的,可以使用【...】扩展运算符与for...of进行遍历
- 基本使用:
// 1、 声明一个set: new Set()
let s = new Set(['lv','lv','gucci', 'dior', 'chanel', 'prada'])
// 2、检测长度size
console.log(s.size);
// 3、添加add
console.log(s.add('celine'));
// 4、删除delete
s.delete('lv')
// 5、检测has
console.log(s.has('lv'));
// 6、清空clear
s.clear()
// 7、此数据结构能进行for...of遍历
for (const v of s) {
console.log(v);
}
- 实际运用
// 实战1:实现数组去重
let arr1 = [1, 1, 3, 2, 3, 4, 5]
let result = [...new Set(arr1)]
console.log(result); //[1, 3, 2, 4, 5]
// 实战2:求交集
let arr2 = [1, 2, 3, 666, 999]
let contract = [...new Set(arr2)].filter(item => new Set(arr1).has(item))
console.log(contract); //[666, 999]
// 实战3:求并集
let union = [...new Set([...arr1, ...arr2])]
console.log(union); //[1, 3, 2, 4, 5, 666, 999]
// 实战4:求差集
let diff = [...new Set(arr2)].filter(item => !(new Set(arr1).has(item)))
console.log(diff); // [666, 999]
14、Map()
map是升级版的对象,也是键值对集合。原来的key只能是字符串,现在不限制类型。可以使用【...】扩展运算符与for...of进行遍历
// 设置一个map
let m = new Map()
m.set('bag', 'celine')
m.set('buy', function () {
console.log('我想买个celine ava');
})
// 读取 get
m.get('buy')()
// 长度 size
console.log(m.size);
// 删除 delete
m.delete('bag')
// 查询 has
console.log(m.has('buy'));
// 清空 clear
m.clear()
// 遍历 for...of
for (const v of m) {
console.log(v);
}
15、class类
- es6的创建类
关键字是class,使用constructor对象 - static
实例对象与函数对象上的属性与方法是不相通的,所以叫静态成员static。static 标注的属性、方法,只属于类本身,实例对象无法调用。 - es5 与 es6创建类
// es5 创建类
function Bag(brand, price) {
this.brand = brand
this.price = price
}
Bag.color = 'pink'
Bag.prototype.slogan = function () {
console.log('es5 包治百病~');
}
let celine1 = new Bag('celine', '12500')
celine1.slogan()
// es6 class创建类
class Gift {
constructor(brand, price) {
this.brand = brand
this.price = price
}
static color = 'black pink'
// 这里不能使用 slogan:function(){}
slogan() {
console.log('es6 包治百病~');
}
}
let celine2 = new Gift('lv', '14400')
celine2.slogan()
console.log(celine2);
- 【继承】es5是构造函数与call方法结合绑定父级原型链实现继承
// es5 构造函数实现继承
function Animal(name, age) {
this.name = name,
this.age = age
}
Animal.prototype.say = function () {
console.log('hello rita');
}
function Person(name, age, sexial, color) {
// 继承animal
Animal.call(this, name, age)
this.sexial = sexial
this.color = color
}
// 子级的原型绑定到父级
Person.prototype = new Animal()
Person.prototype.constructor = Person
// 给子级添加原型方法
Person.prototype.sing = function () {
console.log('i can sing');
}
// 创建子级的实例
let rita = new Person('rita', '18', '女', 'pink')
// 调用父类的方法 console.log(rita.__proto__.say);
// 调用自身的方法
console.log(rita.sing);
- 【继承】es6是通过extends关键字与super函数实现继承
// es6 class如何实现继承
class Animal {
constructor(name, age) {
this.name = name
this.age = age
}
sayHi() {
console.log('hello class');
}
}
class Person extends Animal {
constructor(name, age, sexial, color) {
super(name, age)
this.sexial = sexial
this.color = color
}
sing() {
console.log(this.name + ' can sing~');
}
// 改写父级的同名方法
sayHi() {
console.log(this.name + ' say hello~');
}
}
// 创建实例
const xiaomi = new Person('小米', 20, '男', 'blue')
xiaomi.sayHi()
console.log(xiaomi);
- get 与 set
class Person {
// get 与 set方法
get hobby() {
console.log('hobby属性正在被读取');
return '爱好是唱歌'
}
set hobby(newVal) {
console.log('hobby属性正在被修改');
}
}
// 创建实例
const xiaomi = new Person('小米')
xiaomi.hobby = '跑步'
console.log(xiaomi.hobby) //爱好是唱歌
16、数值的扩展
- Number.EPSILON是一个非常小的数(2.220446049250313e-16),可以用来计算0.1+0.2 !== 0.3的问题
- Number.isFinite(10/0) 返回传入的数字是否为有限数的判断true/false
- Number.isNaN(NaN)判断一个数是否是NaN
- Number.parseInt向下取整、Number.parseFloat 转为整数
- Number.isInteger(1.23)判断一个数是否为整数
- Math.trunc()将数字的小数部分抹掉
- Math.sign() 判断一个数是正数1、负数-1、还是0
16、对象方法的拓展
- Object.is(a,b) // 判断两个值是否相等 类似于===
- Object.assign(obj1,obj2) // 用做配置合并,对象的克隆等, obj2会覆盖掉obj1
- Object.setPrototypeOf(对象,变量) 设置原型对象、Object.getPrototypeOf(变量) 读取原型对象
17、模块化
- 优点:防止命名冲突、代码复用、高维护性
- ES6之前的规范:CommonJS、AMD、CMD
导入import
- 通用导入
import * as m1 from './module/m1.js'
- 解构赋值
// name as myname 模块重名可用as起别名
import {name as myname,fn} from './module/m1.js'
- 简便形式,针对默认暴露
import m1 from './module/m1.js'
导出export
- 分别暴露
export let name = 'rita' export function fn(){}
- 统一暴露
export {name, fn}
- 默认暴露
export default {
name:'rita',
fn(){}
}
18、es7 数组方法的拓展
const bags = ['lv', 'gucci', 'dior', 'chanel']
// includes 类似于indexOf
console.log( bags.includes('coach'));// false
console.log( bags.includes('lv')); // true
// ** 类似于Math.pow()
console.log(2 ** 10);
console.log(Math.pow(2,10));
19、es8:async / await
参考笔记链接:抱歉了... - 简书 (jianshu.com)
20、es8:对象方法的拓展
1) Object.entries
const obj = {
brand: ['lv', 'gucci', 'dior', 'chanel'],
current: 'speednano',
cost: 16500,
}
// 获取键名
console.log(Object.keys(obj)); //['brand', 'current', 'cost']
// 获取键值
console.log(Object.values(obj)); // [Array(4), 'speednano', 16500]
// 获取entries
console.log(Object.entries(obj)); // [['brand', Array(4)] ...]
// 结合map
const m = new Map(Object.entries(obj)) // [0: {"brand" => Array(4)} ... ]
console.log(m.get('current')); //speednano
2) Object.getOwnPropertyDescriptor
console.log(Object.getOwnPropertyDescriptors(obj));
{
brand = {
configurable:true,
enumerable:true,
value:(4)['lv', 'gucci', 'dior', 'chanel'],
writable:true,
[[Prototype]]:Object,
} ...
}
21、es9
rest拓展运算符,新增对象的展开
参数对象的展开
function fn({name,age,...params}) {}
对象的合并,浅拷贝
const mergeObj = {...one, ...two, ...three}
正则扩展
- 命名捕获分租
- 反向断言
- dotAll模式
22、es10
- 1)fromEntries
es10 fromEntries 创建一个对象 接受一个map 或二维数组
es08 entries 是fromEntries的逆运算,把传入的对象转成为二维数组,一个是将对象转换成二维数组,另一个是将二维数组转成对象
// 二维数组
const result1 = Object.fromEntries([
['name', 'rita'],
['age', '18']
])
console.log(result1); // {name: 'rita', age: '18'}
// Map
const m = new Map()
m.set('name', 'RITA')
const result2 = Object.fromEntries(m)
console.log(result2); // {name: 'RITA'}
- 2)字符串的扩展方法 清除空白
trimStart()、trimEnd()、trim() - 3)数组的两个方法:flat()、flatMap()
fla将多维数组转成一维数组[1,[2,[3]]].flat(3)
flatMap将map结果做了一个维度降低let arr = [1,2,3].flatMap(item=>[item*10])
- 4)Symbol.prototype.description
description获取symbol字符串的描述
23、es11
1)对象的私有属性
对象的私有属性,属性名前加#号,无法被外部读取和修改 (面向对象中的特性,对属性的封装)
class Person{
name;
#age; // #是私有属性的标识符
constructor(name, age){ this.name = name;this.#age = age}
intro(){console.log(this.name+'的年龄是'+ this.#age); }
}
// 实例化
const boy = new Person('eric', 22)
// 可以调用内部属性
boy.intro() // eric的年龄是22
// 直接调用会报错
console.log(boy.#age ); //Private field '#age' must be declared in an enclosing class
2)promise的allSettle()
用于批量操作异步进程的场景。
- 都需要成功才能操作,就用
all(p1,p2)
。 - 需要知道每个进程返回的结果,就用
allSettle(p1,p2)
3)字符串扩展的方法
String.prototype.matchAll() 返回的结果是可迭代对象,可用for循环或map进行查询和数据提取
4)可选链操作符 ?.
以前:user = config && config.admin && config.admin.user
现在:user = config?.admin?.user
5)动态import
与之相对应的是静态import,动态import可以实现按需加载
6)大整形 BigInt,可以用来做更大数值运算
let n = 520n //正常数字后加一个n
console.log(n, typeof(n)); // 520n 'bigint'
BigInt(1314) // 1314n
7)globalThis
始终指向全局对象的globalThis,如果想对全局对象进行一些读取和操作,直接使用globalThis
可忽略当前执行环境