前言
ES6全称ECMAScript是2015年发布的第六版本,因为版本更新太大所以被熟知(目前已经更新到第八个版本)
一、声明变量
1. let关键字
概括:声明变量关键字,解决var关键字存在的问题
优点:
-
存在块级作用域
{ let str = 'kuaijizuoyongyu' } console.log(str) // 无法访问作用域里面的变量 str is not defined
-
不存在变量提升
console.log(str) let str = 'bianliangtisheng' // 无法访问未声明的let变量 str is not defined
-
不可以重复声明
let str = 'chongfushengming' let str = 'chongfushengming1' // 无法重复声明 Identifier 'str' has already been declared
var关键字缺点:
-
没有块级作用域
{ var str = 'kuaijizuoyongyu'; } console.log(str); // 不存在块级作用域 'bianliangtisheng'
-
不可以限制修改
var str = 'xianzhixiugai' str = 'xiugaiguohou' console.log(str) // 可以修改 xiugaiguohou
-
可以重复声明
var str = 'chongfushengming' var str = 'chongfushengming1' console.log(str) // 可以重复声明,重复声明做赋值操作 chongfushengming1
-
存在变量提升
console.log(str) // 变量提升但是赋值不提升 undefined var str = 'bianliangtisheng'
2. const关键字
概括:声明常量关键字
优点:
-
一旦声明不可改变,避免var关键存在的变量污染问题
const str = 'changliang' str = 'xiugai' console.log(str) // 无法修改 Assignment to constant variable.
-
和let关键字一样存在块级作用域
{ const str = 'changliang' } console.log(str); // 无法访问作用域里面的常量 str is not defined
-
不存在变量提升
console.log(str) // 无法访问未声明的常量 str is not defined const str = 'bianliangtisheng'
-
无法重复声明
const str = 'shengmingchangliang' const str = 'shengmingchangliang1' console.log(str) // 无法重复声明 Identifier 'str' has already been declared
二、箭头函数
概括:将原生函数的function改为 => 箭头方式进行声明
优点:减少代码量,提高代码执行效率
缺点:
- 会出现this指向问题(由于箭头函数本身没有this指向,它指向的是宿主this,一旦没有this,将会指向window对象)
- 语法过于激进,初学者不易懂
使用方法:
-
如果只有一个参数,可以去掉括号(注意没有参数时也要加上()占位)
const fun = x =>{return x * x} console.log(fun(3)) // 输出9
-
如果只有一条返回语句,可以再去掉return和{ }
const fun = x => x * x console.log(fun(3)) // 输出9
-
箭头函数在返回对象时必须在对象外层多加一个()
const fun = id=>{({id:id, name:'张三'})} console.log(fun(10).name) // 相当于: //const fun = id=>{ // return ({id:id, name:'张三'}) //} // 因为对象有{},如果不括起来无法识别这是一个对象(变量)还是函数体内容
三、新增数组方法
1. filter 方法
概括:过滤数组(过滤出返回为true的数据)
参数(入参函数参数):
- 参数1:数组单元数据
- 参数2:每个单元索引
- 参数3:数组本身
返回值:返回过滤后的新数组
let arr = [1,2,3,4]
arr.filter((data,index,array) => {
console.log(data) // 数组每个单元数据
console.log(index) // 数组下标
console.log(array) // 原数组本身
return data == 1 // 过滤返回为true的数据
})
2. reduce 方法
概括:迭代数组所有项(累加器)
参数:两个参数
- 参数1(入参函数参数):回调函数(必选)
- 回调参数1:上一次回调返回值,或者初始值(必选)
- 回调参数2:数组中被处理的数据项(必选)
- 回调参数3:数据项在数组中的索引(可选)
- 回调参数4:原数组(可选)
- 参数2:初始值(可选)
返回值:返回数组计算后的结果
let arr = [1,2,3,4]
arr.reduce((pre,data,index,array) => {
console.log(pre) // 数组上一次计算结果,如果未计算则是初始值
console.log(data) // 数组中被处理的数据项
console.log(index) // 数据项在数组中的索引
console.log(array) // 原数组
return pre + data // 将每次累加结果进行累加下一项
}, 0) // 设置遍历初始值
扩展用法:
- 计算数组中每个元素出现的次数
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
let nameNum = names.reduce((pre,cur)=>{
if(cur in pre){
pre[cur]++
}else{
pre[cur] = 1
}
return pre
},{})
console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
- 数组去重
// 单数组去重
let arr = [1,2,3,4,4,1]
let newArr = arr.reduce((pre,cur)=>{
if(!pre.includes(cur)){
return pre.concat(cur)
}else{
return pre
}
},[])
console.log(newArr);// [1, 2, 3, 4]
// 数组对象去重
let arr = [{a: 0, name: 'zhangsan'}, {b: 0, name: 'lisi'}]
let Obj = {}
person = person.reduce((cur,next) => {
obj[next.id] ? "" : obj[next.id] = true && cur.push(next);
return cur;
},[])
- 将二维数组转化为一维数组
let arr = [[0, 1], [2, 3], [4, 5]]
let newArr = arr.reduce((pre,cur)=>{
return pre.concat(cur)
},[])
console.log(newArr); // [0, 1, 2, 3, 4, 5]
- 将多维数组转化为一维数组
let arr = [[0, 1], [2, 3], [4,[5,6,7]]]
const newArr = function(arr){
return arr.reduce((pre,cur)=>{
pre.concat(Array.isArray(cur) ? newArr(cur) : cur
}),[])
}
console.log(newArr(arr)); // [0, 1, 2, 3, 4, 5, 6, 7]
- 对象里面属性求和
var result = [
{
subject: 'math',
score: 10
},
{
subject: 'chinese',
score: 20
},
{
subject: 'english',
score: 30
}
];
var sum = result.reduce(function(prev, cur) {
return cur.score + prev;
}, 0);
console.log(sum) //60
3. reduceRight 方法
概括:迭代数组所有项(从右至左进行计算,同数组reduce方法)
参数:同数组的reduce方法参数
返回值:数组计算结果
let arr = [1,2,3,4]
arr.reduceRight((pre,data,index,array) => {
console.log(pre) // 数组上一次计算结果,如果未计算则是初始值
console.log(data) // 数组中被处理的数据项
console.log(index) // 数据项在数组中的索引
console.log(array) // 原数组
return pre + data // 将每次累加结果进行累加下一项
}, 0) // 设置遍历初始值
4. Array.from 方法
概括:将伪数组转化成数组,只要含length属性的都可转化成数组(ES6)
参数:需要转化的伪数组
返回值:转化后的数组
let str = 'asdf'
console.log(Array.from(str)) // 将字符串转化成数组 [a,s,d,f]
let obj = {0:'a',1:'b',length:2}
console.log(Array.from(obj)) // 含索引并length属性的对象也可以转化成数组 ['a', 'b']
5. Array.of 方法
概括:将一组值转化成数组,类似于生明数组(ES6)
参数:需要转化的值
返回值:转化后的数组
console.log(Array.of('11')) // 将字符串转化成数组 ['11']
console.log(Array.of({a:1,b:2})) // 将对象转化成数组 [{a:1,b:2}]
console.log(new Array('11')) // 类似于构造函数声明数组
console.log(new Array(2)) // 构造函数生明因为入参问题容易容易引起重载 [empty × 2] 空数组
6. copyWithin 方法
概括:在数组内部将指定位置的数组赋值到其他位置,会覆盖原数组项,返回当前数组
参数:三个参数
- 参数1:开始位置,从该位置开始替换数组项(必传)
- 参数2:从指定索引开始读取数组项,默认为0,如果为负值,则从右往左读(可选)
- 参数3:从指定索引结束读取数组项,默认为数组长度,如果是负值表示倒数(可选)
返回值:处理好的数组
let arr = [1,2,3,4,5]
arr.copyWithin(3) // 从下标3的位置上开始,默认将整个数组作为数据项进行替换,长度不够默认截取 [1, 2, 3, 1, 2]
arr.copyWithin(0, 2) // 从下标为0位置开始,默认将从下标2位置截取到末尾作为数据项进行替换,长度不够默认截取 [3, 4, 5, 4, 5]
arr.copyWithin(0, 2, 3) // 从下标0位置开始,默认将从下标2位置截取到下标3位置之前作为数据项进行替换,长度不够默认截取 [3, 2, 3, 4, 5]
arr.copyWithin(-1) // 从倒数倒数第一位开始,默认将整个数组作为数据项进行替换,长度不够默认截取 [1, 2, 3, 4, 1]
arr.copyWithin(-1, -2) // 从倒数第一位置开始,默认将从倒数第二位置默认截取到末尾作为数据项进项替换,长度不够默认截取 [1, 2, 3, 4, 4]
arr.copyWithin(-1, -4, -2) // 从倒数第一位置开始,默认将从倒数第四的位置开始截取到倒数第二的位置作为数据项项进项替换,长度不够默认截取 [1, 2, 3, 4, 2]
7. find 方法
概括:找到第一个符合条件的数组数据项
参数(入参函数参数):
- 参数1:数组数据项
- 参数2:数据项下标
- 参数3:原数组
返回值:符合条件的数组数据项
let arr = [1,2,3,4,5]
arr.find((item, index, array) => {
console.log(item) // 数组数据项
console.log(index) // 数据项下标
console.log(array) // 原数组
return item > 1 // 此条件不会校验数组所有数据项,只会校验第一条符合条件的数据
})
8. findIndex 方法
概括:找到第一个符合条件的数组数据项下标
参数(入参函数参数):同数组find方法
返回值:符合条件数据项下标
let arr = [1,2,3,4,5]
arr.findIndex((item, index, array) => {
console.log(item) // 数组数据项
console.log(index) // 数据项下标
console.log(array) // 原数组
return item > 1 // 此条件不会校验数组所有数据项,只会校验第一条符合条件的数据
})
9. fill 方法
概括:使用指定值填充整个数组
参数:
- 参数1:待填充的数据
- 参数2:开始填充的位置
- 参数3:结束填充的位置(该位置前一位)
返回值:填充后的数组
let arr = [1,2,3,4]
arr.fill(1) // 默认将数组所有项填充成该数据 [1,1,1,1]
arr.fill(1,2) // 以参数1为填充项,将数据从坐标为2位置开始填充至数组末尾 [1,2,1,1]
arr.fill(1,2,4) // 以参数1为填充项,将是数据从坐标2位置开始填充至下标为4位置 [1,2,1,4]
10. keys 方法
概括:遍历数组的键名(一般针对于Set、Map数据集合使用)
参数:无
返回值:在日志层面显示Array Iterator {}(数组迭代器),在数据层面显示数组下标
let arr = [1,2,3,4]
let arr2 = arr.keys()
console.log(arr2) // Array Iterator {}
for (let key of arr2) {
console.log(key); // 0,1,2,3
}
11. value 方法
概括:遍历数组键名(一般针对于Set、Map数据集合使用)
参数:无
返回值:在日志层面显示Array Iterator {}(数组迭代器),在数据层面显示数组每个数据项
let arr = [1,2,3,4]
let arr2 = arr.value()
console.log(arr2) // Array Iterator {}
for (let val of arr2) {
console.log(val); // 1,2,3,4
}
12. entries 方法
概括:遍历数组的键值和键名(迭代数组,一般针对于Set、Map数据集合使用)
参数:无
返回值:在日志层面显示Array Iterator {}(数组迭代器),在数据层面显示数组每个单元的数据项和下标作为一个数组
let arr = [1,2,3,4]
let arr1 = arr.entries()
console.log(arr1) // Array Iterator {}
for (let e of arr1) {
console.log(e); // [0,1] [1,2] [2,3] [3,4]
}
13. map 方法
概括:遍历数据(映射数组)
参数(入参函数参数):
- 参数1:数组单元数据
- 参数2:每个单元索引
- 参数3:数组本身
返回值:返回映射后的新数组
let arr = [1,2,3,4]
arr.map((data,index,array) => {
console.log(data) // 数组每个单元数据
console.log(index) // 数组下标
console.log(array) // 原数组本身
})
14. for...of
概括:遍历数据
参数:无
与for...in的区别:
- for...of 只能遍历数组,而for...in能遍历对象和数组
- for...in 遍历的是对象key(数组也是对象,下标是键,数据项是值),for...of遍历的是数组的每一项
- 如果动态给数组添加一个键值对,for...in会将数组的键包括添加的属性名一起遍历,而for...of只会遍历原数组数据项
let arr = [1,2,3,4]
let obj = {name: '张三', age: 50}
arr.name = '张三'
for(let item of arr) {
console.log(item) // 返回的数组的每一个单元 1,2,3,4
}
for(let item of obj) {} // 不是可迭代对象 obj is not iterable
for(let item in arr) {
console.log(item) // 返回的是数组的key 0,1,2,3,name
}
for(let item in obj) {
console.log(item) // 返回的是对象的每一个key name,age
}
返回值:返回数组 length 长度
let arr = [1,2,3,4]
for(let i of arr) {
console.log(i) // 1,2,3,4
}
四、Map和Set数据结构
1. Set 数据结构
概括:Set数据结构,是由一些不重复的元素组成的内存结构(类似于数组),统称为集合
参数:接收一个数组
属性:size(集合中包含元素的数量)
操作方法:
- add(value):向集合中添加一个新的项
- delete(value):从集合中删除一个值
- has(value):校验集合中是否包含该元素
- clear():移出集合中所有项
let set = new Set([1,2])
set.add(3) // Set {1,2,3}
set.has(2) // true
set.delete(2) // Set {1,3}
set.clear() // Set {}
遍历方法:
- keys(): 返回键名的遍历器
- values(): 返回键值的遍历器
- entries(): 返回键值对的遍历器
- forEach(): 使用回调函数遍历每个成员
let set = new Set([1,2,3,4])
// 由于set只有键值,没有键名,所以keys() values()行为完全一致
console.log(Array.from(set.keys())) // [1,2,3,4]
console.log(Array.from(set.values())) // [1,2,3,4]
console.log(Array.from(set.entries())) // [[1,1],[2,2],[3,3],[4,4]]
set.forEach((item) => { console.log(item)}) // 1,2,3,4
返回值:Set数据集合(可以去除重复数据)
let set = new Set([1,2,1,2])
console.log(Set) // Set数据集合 {1, 2}
2. Map 数据结构
概括:Map数据结构,是有一些不重复的键和值组成的内存结构(类似于对象),键只能是字符串类型,统称为字典
参数:二维数组 [[ 键: 值 ], [ 键: 值 ]]
属性:size(Map对象中所有键值对的数量)
操作方法:
- set( key: value ):向Map对象中加入或更新键值对
- get( key ):读取Map对象中对应key的值,如果没有返回 undefined
- has( key ):校验某个key是否在Map对象中,再返回true 否则返回 false
- delete( key ):删除Map对象中的某个key,返回 true,如果删除失败返回 false
- clear():清除Map对象中的所有值
let map = new Map([['name','vue3js.cn']])
map.set('age','18') // Map {"name" => "vuejs.cn", "age" => "18"}
map.get('name') // vue3js.cn
map.has('name') // true
map.delete('name') // Map {"age" => "18"}
map.clear() // Map {}
遍历方法:同Set数据对象
返回值:Map数据字典(可以去除重复数据)
let map new Map([[1,2],[1,2]])
console.log(map) // Map {1 => 2}
五、字符串新增方法与模板字符串
1. includes()
概括:校验字符串中是否包含指定字符
参数:参数1(指定字符)、参数2(起始位置)
返回值:Boolean(布尔值)
let str = 'asdfghjkl'
str.includes('a') // 包含指定字符 " 返回 true
str.includes('x') // 不包含指定字符 返回 false
str.includes('a', 1) // 从字符串下标为1开始查找指定字符 返回 false
2. startsWith()
概括:校验字符串是否以特定字符开头
参数:参数1(指定字符)参数2(起始位置)
返回值:Boolean(布尔值)
let str = 'asdfghjkl'
str.startsWith('a') // 校验原字符串以a字符开头 true
str.startsWith('s') // 校验原字符串以s字符开头 false
str.startsWith('a', 1) // 从下标为1的位置校验字符串是否以a字符开头 false
3. endsWith()
概括:校验字符串是否以特定字符结尾
参数: 要查询的字符
返回值:Boolean(布尔值)
let str = 'asdfghjkl'
str.startsWith('l') // 校验原字符串以 l字符结尾 true
str.startsWith('s') // 校验原字符串以s字符结尾 false
str.startsWith('l', 3) // 从下标为3的位置校验字符串是否以a字符结尾 false
4. repeat()
概括:重复当前字符串
参数:重复当前字符串的次数
返回值:重复后的字符串
let str = 'a'
str.repeat(2) // 将原字符串重复两次 aa
5. padStart()
概括:字符串首位补全
参数:参数1(字符串长度)、参数2(要添加的字符)
返回值:返回补全后的字符串
let str = 'asdfghjkl'
str.padStart(12, '123') // 补全字符串首位 123asdfghjkl
str.padStart(12) // 如参数二不传,默认补充空格 " asdfghjkl"
str.padStart(10, '123') // 如补充字符串长度超过原字符串补充位数自动截取 1asdfghjkl
6. padEnd()
概括:字符串末位补全
参数:参数1(字符串长度)、参数2(要添加的字符)
返回值:返回补全后的字符串
let str = 'asdfghjkl'
str.padEnd(10, '123') // 如补充字符串长度超过原字符串补充位数自动截取 asdfghjkl1
str.padEnd(12, '123') // 补全字符串末位 asdfghjkl123
7. trimStart()
概括:过滤字符串中首位空格部分
参数:无
返回值:过滤后的字符串
let str = ' aaa '
str.trimStart(2) // 过滤字符串中首位的空格部分 "aaa '
8. trimEnd()
概括:过滤字符串中末位空格部分
参数:无
返回值:过滤后的字符串
let str = ' aaa '
str.trimEnd(2) // 过滤字符串中末位的空格部分 " aaa'
9. replaceAll()
概括:替换字符传中所有指定字符
参数:参数1(原始字符)、参数2(替换字符)
返回值:返回替换后的字符串
let str = 'asdfghjklas'
str.replace('as', 'yz') // 返回替换字符后的字符串 yzdfghjklyz
str.replace('ad', 'yz') // 如未找到指定字符,则返回原字符串 asdfghjkl
10. 模板字符串
概括:将传统字符串(单引号或者双引号)改为反引号 ``
特点:
- 增加了解析变量功能,通过 ${} 解析模板字符串中的变量
- 增加解析换行操作
let str = '
换行操作
' // 语法错误 Invalid or unexpected token
let str = `
支持换行操作
`
console.log(str) // 在浏览器控制台上会将换行操作转换成换行符 "\n\t支持换行\n"
let str = '模板变量'
console.log(`可以解析${str}`) // 可以解析模板变量
六、解构赋值
1. 概括
解构赋值是对赋值运算符的扩展。 他是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值
2. 对于普通数组
let arr = [1,2,3,4]
let [a,b,c,d] = arr
console.log(a,b,c,d) // 1,2,3,4
3. 对于对象
let obj = {
name: '张三',
age: '10',
}
let { name, age } = obj // 解构对象时,左侧的变量必须和对象里面键值对key一样,否则返回undefined
console.log(name, age) // 张三,10
4. 解构变量少于解构对象数量时
let arr = [1,2,3,4]
let [a,b,c] = arr // 变量少于数组长度时,会按照顺序赋值
console.log(a,b,c) // 1,2,3
let obj = {
name: '张三',
age: '10',
sex: '男'
}
let { name, age } = obj // 变量少于对象key时,会按照顺序进行赋值
console.log(name, age) // 张三,10
5. 复合赋值
let arr = [{name:'张三', age:10}, [1,2,3], 'hello', 9 ];
let [a,b,c,d] = arr; // 解构数组中包含多种类型的数据
console.log(a); // {name:'张三', age:10}
console.log(b); // [1,2,3]
console.log(c); // hello
console.log(d); // 9
6. 分解赋值
let arr = [{name:'张三', age:10}, [1,2,3], 'helloWord', 100 ];
let[{name,age},[a,b,c],d,e] = arr; // 解构数组中包含多种类型的数据
console.log(name,age); // 张三 10
console.log(a,b,c); // 1 2 3
console.log(d,e); // helloWord 100
7. 声明和赋值不可分开
let [name, age]; // 报错 Missing initializer in destructuring declaration
七、扩展运算符和rest运算符
概括:将数组、对象或字符串里面数据进行扩展平铺,与其相反的是rest运算符
使用场景:
- 合并数组
let arr1 = [1,2]
let arr2 = [3,4]
console.log([...arr1, ...arr2]) // [1, 2, 3, 4]
- 合并对象
let obj1 = {name: '张三'}
let obj2 = {age: 10}
console.log({...obj1, ...obj2}) // {name: "张三", age: 10}
console.log(Object.assign(obj1,obj2)) // 等同于此项操作 {name: "张三", age: 10}
- 剩余(rest)运算符
function rest (...m) {
console.log(m) // 将多个实参通过rest运算符进行合并成一个形参
let num = 0;
for(let i of m){
num += i;
}
return num;
}
console.log(sumRest(1,2,3)); // 6
- rest运算符于解构赋值一起使用
let arr = [1,2,3,4];
let [a,b,...c] = array; // 将数组前两项进行解构,后两项机构后在合并成单独数组
console.log(a); // 1
console.log(b); // 2
console.log(c); // [3, 4]
区别:其实两者属于一种运算符方法。唯一的区别就是使用场景不一样,扩展运算主要做平铺操作,rest运算符主要做合并操作
八、对象新语法
1. 面向对象
概括:面向对象是一种编程思想。其中提出了类的概念,通过class类语法的使用提高代码的执行效率
特点:
- 封装:将方法中的相同的一类进行整合
- 继承:一个类继承另一个类的特性称为继承,提高复用性
- 多态:通过不同的入参展示不同的行为
- 抽象:将一类的实体的共同特性抽象出来封装在一个抽象类中
2. class类概念
概括:在ES6中,class作为声明类的关键字,相当于function的语法糖。使得对象原型的写法更加清晰、更像面向对象编程的语法
定义:
- 类定义
// 匿名类
let Example = class {
constructor(a) {
this.a = a;
}
}
// 命名类
let Example = class Example {
constructor(a) {
this.a = a;
}
}
- 类声明
class Example {
constructor(a) {
this.a = a;
}
}
语法:
- 使用class声明类,使用constructor创建构造函数
// 创建类
class Person {
// 创建构造函数
constructor(name, age, sex){
this.name = name;
this.age = age;
this.sex = sex;
}
}
- class类中的方法不需要使用function关键字
// 创建类
class Person {
// 创建构造函数
constructor(name, age, sex){
this.name = name;
this.age = age;
this.sex = sex;
}
handleEdit() { // ES6 语法直接可以声明
console.log(this.name)
}
}
- 通过new关键字,来创建class类的实例(可以传入参数)
// 创建类
class Person {
// 创建构造函数
constructor(name, age, sex){
this.name = name;
this.age = age;
this.sex = sex;
}
handleEdit() { // ES6 语法直接可以声明
console.log(this.name)
}
}
let person1 = new Person('张三','18','男')
- class类中方法通过对象的 . 语法来使用
// 创建类
class Person {
// 创建构造函数
constructor(name, age, sex){
this.name = name;
this.age = age;
this.sex = sex;
}
handleEdit() { // ES6 语法直接可以声明
console.log(this.name)
}
}
let person1 = new Person('张三','18','男')
person1.handleEdit()
- 子类通过extends继承父类中的属性和方法
// 父类
class Person {
// 创建构造函数
constructor(name, age, sex, id){
this.name = name;
this.age = age;
this.sex = sex;
this.id = id // 在子类实例对象中创建的属性在父类中也可以获取到
}
handleEdit() { // ES6 语法直接可以声明
console.log(this.Id)
}
}
// 子类
class Students extends Person {
}
let student1 = new Students('张三','18','男', '12138')
student1.handleEdit() // 可以调用父类中的方法
console.log(student1.name) // 可以获取父类中的属性
- 子类通过super()可以使用父类中的构造方法,默认使用父类中的构造方法,如果子类中使用constructor则会覆盖继承父类中构造方法
// 父类
class Person {
// 创建构造函数
constructor(name, age, sex, id){
this.name = name;
this.age = age;
this.sex = sex;
this.id = id // 在子类实例对象中创建的属性在父类中也可以获取到
}
handleEdit() { // ES6 语法直接可以声明
console.log(this.Id)
}
}
// 子类
class Students extends Person {
construtor(){
// 子类创建构造方法里面没有任何属性和方法,仍会覆盖父类的构造方法
}
}
- 使用super简化子类的构造函数
// 父类
class Person {
// 创建构造函数
constructor(name, age, sex, id){
this.name = name;
this.age = age;
this.sex = sex;
this.id = id // 在子类实例对象中创建的属性在父类中也可以获取到
}
handleEdit() { // ES6 语法直接可以声明
console.log(this.Id)
}
}
// 子类
class Students extends Person {
construtor(){
super(name, age, gender); // 使用父类的方法给name,age,gender赋值
// 这里相当于:
// this.name = name;
// this.age = age;
// this.gender = gender;
// 这种情况下直接使用super()可以达到简化的目的
// 再加上新入的id属性
this.id = id
}
}
- 重写父类中的方法
// 父类
class Person {
// 创建构造函数
constructor(name, age, sex, id){
this.name = name;
this.age = age;
this.sex = sex;
this.id = id // 在子类实例对象中创建的属性在父类中也可以获取到
}
handleEdit() { // ES6 语法直接可以声明
console.log(this.Id)
}
}
// 子类
class Students extends Person {
construtor(){
super(name, age, gender); // 使用父类的方法给name,age,gender赋值
// 这里相当于:
// this.name = name;
// this.age = age;
// this.gender = gender;
// 这种情况下直接使用super()可以达到简化的目的
// 再加上新入的id属性
this.id = id
}
// 子类方法中不写任何内容,仍会覆盖父类中的方法
handleEdit() {
}
}
3. JSON用法
概括:JSON 语法衍生于 JavaScript 对象标记法语法( JavaScript Object Notation)
语法:
- 简写变量,如果键名和变量名相同的话可以简写为一个
let name = '张三'
let age = 10
let sex = "男"
// 简写方式
let obj = {
name,
age,
sex
}
console.log(obj.name) // 张三
- 简写方法,可以省略function声明函数关键字
let obj = {
say() {
console.log('简写方法')
}
}
obj.say() // 简写方法
- 对象转 JSON 字符串(串行化)
let obj = {
name: '张三',
age: '李四'
}
console.log(JSON.stringify(obj)) // 串行化 {"name":"张三", "age":15}
- JSON字符串转对象(反串行化)
let str = JSON.parse('{"name":"李四","age":"19"}')
console.log(str.name) // 李四
九、模块化编程
1. 概括
将一个大的程序拆分成多个互相依赖的小模块,按需引入所需模块,从而提高代码的复用性
2. 原始方法
概括:通过script的src属性引入文件
缺点:
- 全局作用域下容易造成变量冲突
- 文件只能按照js的书写规范顺序进行加载
- 开发人员必须解决模块和代码库的依赖关系
- 大型项目中资源难以管理,代码可维护性较差
<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>
3. CommonJs规范
概括:CommonJs是服务器端模块的规范。由NodeJs推广使用
规范:
- 一个单独的文件就是一个模块。每个模块都是一个单独的作用域,在模块内部定义的变量无法其他模块读取,除非定义全局的global对象
- 暴露模块变量最好方法是使用module.exports对象
- 引入模块使用require方法,该方法读取一个文件并执行,返回文件内部的方法
缺点:需要依赖服务器端,只在浏览器端无法正常加载
语法:通过define方法封装一套标准的模块
/******************传统commonJs规范**********************/
// a.js文件
exports.add = function() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
// b.js文件
var add = require('math').add;
exports.increment = function(val) {
return add(val, 1);
};
// c.js文件
var increment = require('b').increment;
var a = increment(1); // 2
/***********************二次封装commonJs规范*************************/
// a.js文件
define(function(require, exports, module) {
exports.add = function() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
});
// b.js文件
define(function(require, exports, module) {
var add = require('a').add;
exports.increment = function(val) {
return add(val, 1);
};
});
// c.js文件
define(function(require, exports, module) {
var inc = require('b').increment;
inc(1); // 2
});
4. AMD规范
概括:AMD 异步模块定义 的意思。他是一个浏览器端模块化开发规范,主要使用的 RequireJs 语法库
参数:AMD也是采用 require() 语法加载模块的,和CommonJs不同的是需要两个参数
- 参数1:是一个模块加载的队列数组
- 参数2:加载成功之后的回调函数
// a.js文件
export.add = function(a, b) {
return a + b
}
// b.js文件
require(['a']), function(a) {
a.add(2, 3)
}
解决问题:
- 多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
- js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长
语法:
// 定义模块 b.js
define(['a.js'], function(){
var name = 'Byron';
function printName(){
console.log(name);
}
return {
printName: printName
};
});
// 加载模块
require(['b'], function (my){})
5. CMD规范
概括:CMD 通用模块定义。主要使用的是seaJs语法库,和AMD规范类似只是执行时机不同
规范:
- 一个模块一个文件,经常以文件名作为模块Id
- 推崇依赖就近原则,所以不在define的参数中写依赖
- factory函数作为define函数的入参函数
参数:
- 参数1:require 是一个方法,接受模块标识 作为唯一参数,用来获取其他模块提供的接口
- 参数2:exports是一个对象,用来向外提供模块接口
- 参数3:module是一个对象,上面储存着其他模块的属性和方法
// 定义模块 a.js
define(function(require, exports, module) {
var $ = require('jquery.js')
$('div').addClass('active');
});
// 加载模块
seajs.use(['a.js'], function(my){});
区别(和AMD的区别):
- AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
- CMD推崇就近依赖,只有在用到某个模块的时候再去require
6. ES6模块化
概括:模块功能主要是有两个命令构成export和import。export方法规定模块对外暴露,import方法规定指定模块导入
语法:
- 将script标签引入的js文件进行模块化
<!--可以将每个js文件的变量进行私有化-->
<script src="./a.js" type="module"></script>
<script src="./b.js" type="module"></script>
<script src="./c.js" type="module"></script>
- 访问不同模块下访问相同的变量
// a.js文件
let name = '张三'
let age = 10
export {name, age} // JSON的简写方法
// b.js文件
import { name, age } from 'a.js'
console.log(name, age) // '张三', 10
- 设置不同模块下相同变量的别名
// a.js文件
let name = '张三'
let sex = '男'
export {
name, sex
}
// b.js文件
let name = '花花'
let sex = '女'
export {
name, sex
}
// c.js文件
import sex as sex1 from 'a.js'
import sex as sex2 from 'b.js'
console.log(sex1) // 男
console.log(sex1) // 女
- 匿名直接暴露模块
// a.js文件
export default function(a) {
console.log(a)
}
// b.js文件
import aFun from 'a.js' // 只能引入一次,引入多次会报错
aFun(10) // 调用a.js 文件中的方法
- 暴露所有属性
// a.js文件
function add() {
console.log('add')
}
function del() {
console.log('del')
}
function edit() {
console.log('edit')
}
function query() {
console.log('del')
}
export default {
add,
del,
edit,
query
}
// b.js文件
import * as methods from 'a.js'
methods.add() // add'
methods.del() // del'
methods.edit() // edit'
methods.query() // query
十、Promise对象
概括:用来解决异步操作,解决冗余的回调地狱
参数:
- pending:操作进行中
- resolve:操作成功
- reject:操作失败
回调函数:
- 成功时回调函数(then)
new Promise((pending, resolve, reject) => {
console.log(resolve, reject)
}).then((res) => {}) // 成功回调
- 失败时回调函数(catch)
new Promise((pending, resolve, reject) => {
console.log(resolve, reject)
}).then((res) => { // 成功回调
console.log(res)
}).catch((err) => { // 失败回调
console.log(err)
})
优点:
- 有效的控制了程序的异步操作
- 解决了回调地狱的问题,提高了代码的可读性
- 可以对项目中的接口进行统一的封装管理
缺点:
- 程序一旦执行,途中无法停止
- 当其中执行程序报错时,不会反应到promise程序以外
- 无法确定pending状态下的程序执行到哪一个阶段(开始,还是结束)
扩展:
- Promise.all:所有任务都执行完成再调用
// Promise 加载队列
let promises = [1,2,3,4].map(function(id){
return getJSON("/post/" + id + ".json");
});
Promise.all(promises).then(function(posts) {
// ...
}).catch(function(reason){
// ...
});
- Promise.race:那个任务执行完成就先输出那个结果
// Promise 加载队列
let promises = [1,2,3,4].map(function(id){
return getJSON("/post/" + id + ".json");
});
// 加载队列中那个先执行完成就先输出那个结果
Promise.race(promises).then(function(posts) {
// ...
}).catch(function(reason){
// ...
});
十一、总结
- 以上是个人总结的常用ES6新增汇总,欢迎各位网友斧正🤝
- 参考以下各位大神文章