ES6简介
ECMAScript 第六代标准
let 和 const
用于声明变量或声明常量
变量和常量
var 和 let 声明的就是变量,变量初始化后还可以重新赋值。
const 声明的是常量,常量一旦初始化后就不能重新赋值,否则报错。常量可以防止不经意间改变了不能改变的量。如果常量值的类型是引用类型,例如对象,可以修改对象属性的值。
const 声明常量一旦声明,就必须完成初始化,否则报错
let、const 与 var 的区别
- 重复声明:var 支持重复声明,let 与 const 不支持。
- 变量提升:let 与 const 不存在变量提升。
- 暂时性死区:只要作用域内存在 let 和 const ,他们声明的量就会绑定作用域,该量不再受外部影响。
- window对象的属性和方法:let 和 const 声明的量不会变成 window 对象的属性或方法。
- 块级作用域: let 与 const 存在块级作用域。
模板字符串
一般字符串:单引号和双引号。
模板字符串:反引号。
特征:
- 模板字符串中所有空格、换行、缩进都被保留在输出中。
- 同样可以使用转义字符输出反引号、反斜杠等特殊字符。
- 可以直接在模板字符串中使用
${}
注入内容(变量,属性值,函数值,计算值等)
标签模板
是函数调用的一种特殊形式。模板字符串可以紧跟在一个函数后面,该函数将被调用来处理这个模板字符串,这被成为“标签模板”功能,例如:
alert('hello')
//等同于
alert`hello`
"标签"指的就是函数,紧跟在后面的模板字符串就是他的参数。
如果模板字符串中有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。
let a = 5;
let b = 10;
function tag(tpldata,...values){
console.log(tpldata);
console.log(values);
console.log(arguments);
}
tag`hello ${a+b} world ${a*b}`
//等同于
tag(['hello',' world ',''],15,50)
“标签模板”的一个重要应用,就是过滤HTML字符串,防止用户注入代码
let message =
SaferHTML`<p>${sender} has sent you a message.</p>`;
function SaferHTML(templateData) {
let s = templateData[0];
for (let i = 1; i < arguments.length; i++) {
let arg = String(arguments[i]);
// Escape special characters in the substitution.
s += arg.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">");
// Don't escape special characters in the template.
s += templateData[i];
}
return s;}
箭头函数
写法: ()=>{}
小括号内参数,等号大于号,中括号内函数体。
通常需要用一个变量或常量接收。
注意事项
- 单个参数可省略小括号,0个或多个不可省略。
- 单行函数体可同时省略大括号和 return ,必须同时。
- 单行对象如果要省略大括号,需要在对象外加小括号:例如
const add = (x+y)=>({value:x+y})
箭头函数没有自己的this
非箭头函数执行一定会产生属于这个函数的this,箭头函数没有自己的this,只会从自己的作用域链的上一层继承 this.
箭头函数使用注意
- 不能作为构造函数。
- 需要 this 指向调用对象的时候箭头函数不适用。
- 需要 arguments 的时候,箭头函数没有 arguments 。可以用剩余参数替代。
Iterator 迭代器/遍历器
找到 iterator
先创建一个数组 const arr = [1,2]
用控制台查看,深挖其属性会有个 Symbol.iterator ,执行该方法 arr[Symbol.iterator]()
执行后会返回一个 Array Iterator{}
可以用一个量接收。
使用Iterator
iterator调用 next() 方法,会返回 {value: xxx , done: xxx}
可迭代对象
只要有 Symbol.iterator 方法,且这个方法调用后会产生一个 iterator 。
例如:数组、字符串、arguments、NodeList、Set、Map、剩余参数 等。
一般对象不是可迭代对象,可以给一般对象强行添加 Symbol.iterator 方法。
obj[Symbol.iterator] = ()=>{
let index = ;
return(
next(){
index++;
……
}
)
}
//类数组对象可以直接偷数组原型上的
LEISHUZU[Symbol.iterator] = Array[Symbol.iterator]
for of
想要遍历一些东西的时候,五花八门,对象用 for(...in...) ,数组用 for 循环、forEach 方法。而 iterator 只有一种遍历方式,就是“下一个”,一般用系统封装好的 for(...of...)
for(let item of arr){
}
- for(...of...) 循环只会遍历出那些 done 为false时对应的 value 值。(如果改写了对象的Symbol.iterator()之后比如把done改为false则会疯狂输出)
- for(...of...) 可以和 break 、 continue 一起使用。
可迭代对象的方法
forEach()
forEach() 方法可遍历 可迭代对象 。
forEach() 传入的第一个参数 是一个回调函数。回调函数可以使用三个参数,按顺序分别是 (1)可遍历对象键值对的值 (2)可遍历对线键值对的键 (3)可遍历对像本身。
forEach() 传入的第二个参数 是 this 指向(非箭头函数时才可用)。例如:
let arr = [11,22,33];
arr.forEach((value,key,self)=>{
console.log(value,key,self)
},arr)
keys()
一些可迭代对象可以执行 keys() 方法,遍历此方法得到的对象,可以取得键名(例如数组的索引值,可迭代对象的键名)。例如:
let arr = [1,2,3]
for(let k of arr.keys()){
console.log(k)
}
values()
可迭代对象的 values() 方法,遍历此方法返回的对象可以取得键值对的值(低版本浏览器不支持)
let arr = [1,2,3]
for(let k of arr.values()){
console.log(k)
}
entries()
可迭代对象的 entries() 方法,遍历此方法返回的对象可以取得键值对(索引+值组成的数组)
let arr = [1,2,3]
for(let k of arr.entries()){
console.log(k)
}
生成器函数
生成器函数,在旧函数声明方法 function fc(){}
中,在function关键字和函数名中间插入一个*号
function* (){}
普通函数执行时没有停止功能 Generator函数可以暂停
Generator 生成器 返回的是iterator接口
CO库就是不停的调用next方法将最后结果返回
Generator 中 yield 后面只能跟 Thunk 函数或 Promise 对象
function * gen(){
console.log(arg);
let one = yield 111;
console.log(one)
}
let iterator = gen('AAA')
console.log(iterator.next());
console.log(iterator.next('BBB'))
next方法里面可以传入实参,传入的实参将会作为上一个yield整体返回的结果
展开运算符
... 可用于 可迭代对象 的展开。
例如,可以用于数组展开,把数组拆成一个一个数字。例如:Math.min 和Math.max 只能计算一串参数的最大最小值不能传入数组,这时就能传入数组同时用展开运算符展开。
let arr = [1,2,3];
//直接Math.min(arr)则不计算,可以
Math.min(...arr);
展开运算符可用于数组浅复制(浅克隆),例如
let arr1 = [1,2,3];
let arr2 = [...arr1]
所以展开 可迭代对象 外直接套一个中括号可以快速转变为一个数组。
展开运算符可以用于 对象 展开
但不能直接展开,只能在 {} 大括号中展开。
所以还可以用于对象复制,也可以用于合并对象,用于合并对象时,后展开的与前展开的对象同名的属性会覆盖。
展开空对象没有效果
let obj1 = {name:'mingzi',age:18}
let obj2 = {...obj1}
展开运算符只能“浅展开”
即只能展开一层
展开运算符特殊用法:剩余参数
当函数执行传入 比形参数量更多的 实参时,可以用剩余参数接受,写法 ...xxx ,本质是个数组,即使没有值,也是个控股数组,读取时不用 ... 直接读 xxx 即可。例如
function func(a,b,...sycs){console.log(sycs)}
func(1,2,3,4,5,6,7,8)
//返回数组[3,4,5,6,7,8]
箭头函数中的剩余参数
箭头函数中,因为箭头函数只有一个参数的时候可以省略小括号,但即使只有一个剩余参数,也不能省略小括号。
箭头函数没有arguments,所以可以用剩余参数替代,且剩余参数可以用数组的方法。
剩余参数必须、只能是最后一个参数,之后不能有其他参数,否则报错
剩余参数可以与解构赋值结合使用。
剩余参数与对象解构赋值结合使用会成为剩余元素。
解构赋值
- 将 可迭代对象 的值 赋给一个 可迭代对象 书写形式的结构,例如:
const [a,b] = [1,2]
- 对象也可以使用解构赋值,但必须满足 1.模式(结构)匹配 2.属性名相同的完成匹配。
- 其他数值类型也可以使用解构赋值,例如number和boolean,会先将等号右边的值先转为对象。但无法解构其内容,只能提取继承的属性。
- undefined 和 null 无法进行解构赋值。
可迭代对象全部都可以使用数组形式完成结构赋值,字符串还可以使用对象的结构完成解构赋值,例如: let {0:a} = 'bilibili'
,此时 a 为下标为 0 的字母b。
解构赋值的默认值
可以给解构赋值的常量变量赋一个默认值,例如 let[a=1,b=2]=[]
注意:只有右边与左边解构赋值严格等于 undefined 时,默认值才会生效。默认值拥有惰性求值的特性,即用得到才执行求值式求值,用不到则不执行。
解构赋值的应用用途
解构赋值可以用于快捷交换变量值,例如
let x=1,y=2;
[x,y]=[y,x]
//此时x和y就快速交换了值。
Set
Set是一些列无序、没有重复值的数据集合。
无序: Set没有下标去标识每一个值,所以set是无序的,不能像数组一样通过下标去访问 set 的成员,但遍历 set 的时候,是根据成员添加进 set 的顺序进行遍历的。
没有重复值: Set会自动去重,Set重复值的判断遵循全等原则,但NaN除外,在Set中NaN也不可重复。
创建一个 Set
使用 Set 构造函数 const se = new Set()
即可创建一个set,创建 Set 时可以传入一个可迭代对象作为参数,构造出来的Set就会拥有对象里的成员,例如:
let arr = [1,2,3]
const se = new Set(arr)
Set 的属性
size:可以访问Set里面的成员个数。new Set().size
会返回一个0.
Set 的常用方法
方法 | 作用 |
---|---|
add() | 添加成员,可连续使用 |
has() | 查看是否有某个成员,返回布尔值 |
delete() | 删除某个成员 |
clear() | 清除所有成员 |
forEach() | 遍历 |
add
可以连续添加,例如:
const se = new Set()
se.add(1).add(2).add(3)
delete
如果删除不存在的成员,则什么都不会发生,也不会报错
forEach
Set 的 forEach 是按照成员添加进Set的顺序遍历的
Set 用途
Set 可以用于 可迭代对象 去重,例如数组去重,字符串去重。或者需要使用Set方法的地方也可以转换成Set
Map
Map 和对象都是键值对的集合。
Map 和对象的区别:
对象一般用字符串当作键,Map 可以用所有数据类型的值当键,包括引用类型。
创建一个 Map
使用 Map 构造函数 const ma = new Map()
即可创建一个 Map ,创建 Map 时可以传入一个 entry object (例如二维数组,二维set对象,map对象),例如:
let arr2d = [
[1,2],
[3,4],
[5,6]
]
const ma = new Map(arr2d);
Map 属性
size:获取有几个键值对,上面的代码然后 ma.size
会返回3.
Map 的方法
方法 | 作用 |
---|---|
set() | 添加新成员 |
get() | 获取成员 |
has() | 判断是否有这个成员返回布尔值 |
delete() | 删除成员,如果没有则无事发生也不报错 |
clear() | 清除所有成员 |
forEach() | 遍历成员 |
set
可连续使用,例如 new Map().set(9,8).set(7,6)
,当后添加的成员与前添加的键名一样时,后添加的会覆盖前添加的。
get
获取成员,当获取不存在的成员时返回 undefined
Map 其他注意事项
Map 重复键名的判断方式遵循全等原则,NaN例外。
Map 用途
当你只需要键值对结构时,或者需要Map的方法时,或者使用字符串以外的值做键时。
ES6其他新增技巧
对象字面量增强
- 属性的简洁表示法:已定义的变量或常量,可以直接写进对象里当其属性,例如:
let name = 'mingzi';
let obj = {name}; //等同于let obj = {name:name}
obj.name //直接返回 'mingzi'
- 方法的简洁表示法:对象的方法可以省略冒号和 function 关键字,例如:
//const obj = { func : function(){} }
const obj = { func(){} }
- 方括号语法可以写在对象字面量里,方括号可以注入变量值,运算值等,例如:
let bianliang = 'x'
const obj = {
[bianliang] : 18;
}
obj.x //返回18
函数参数的默认值
可以给函数的参数设置一个默认值,例如:
function xjiay(x=1,y=2){
return x+y
}
xjiay()
//直接执行不传参数则使用默认值
- 生效条件:不传参或者传的是undefined的时候,默认值才会生效。
- 同样拥有惰性求值特性。
ES6 其他新增方法
ES6字符串新增方法
includes() 方法
用于判断字符串是否有某些字符。
用法:第一个参数传入的是一个值,返回布尔值判断字符串内是否有这个值。第二个参数表示开始搜索的位置。
startsWith() 和 endsWith
用于判断参数是否在字符串的头部和尾部,返回布尔值。
例如 abcd.startsWith('ab') 返回true,abcd.endsWith('cd')返回true
repeat()
repeat() 方法返回一个新的字符串,表示将源字符串重复n次。例如:
'rero'.repeat(4);
//输出rerorerorerorero
参数如果不是整数会自动向下取整,为0次则不输出内容,为负数则报错
padStart() 和 padEnd()
pad是填充的意思,用于补全字符串长度,无法改变原字符。
用法:
- 第一个参数表示“需要补到的长度”是多少,通常是一个整数。
- 第二个参数表示“补入的值”,如果不传参数2,默认使用空格代替。
- 如果第一个参数小于或等于原字符串长度,则补全不生效,返回原字符串。
- 如果第二个参数补入的值长度,补入后总长度不满足第一个参数,则循环再补,补到满足长度。
- 如果第二个参数补入的值长度,补入后总长度超过第一个参数,则只补需要补的长度,后面的截去。
padStart() 是从头部开始补, padEnd() 是从尾部开始补。例如:
'x'.padStart(5,'ab') //返回 'ababx'
'y'.padEnd(5,'6688') //返回 'y6688'
trimStart() 和 trimEnd()
trim是去掉不必要部分的意思,用于清除字符串的首或尾的空格,中间的空格不会清除。
trimStart() 等同于 trimLeft() ,trimEnd() 等同于 trimRight()。
同时去除头尾空格的方法为 trim()。
matchAll()
matchAll() 方法返回一个正则表达式在当前字符串的所有匹配
返回的是⼀个遍历器(Iterator),⽽不是数组。
ES6数组新增方法
includes()
数组的 includes() 方法,可以判断数组中是否含有某个成员,判断基于全等原则,NaN除外。第一个参数传入的是一个值,返回布尔值判断数组内是否有这个值。第二个参数表示开始搜索的位置。
Array.from()
Array.from() 可以将 可迭代对象 和 类数组对象 转换成数组。
- 第一个参数表示的是要转换的对象。本来是什么类型的值,如果没发生显式或隐式类型转换,转换后数组的每个成员还是原来的类型。
- 第二个参数是一个回调函数,用于将转换后的数组内的每一个成员进行处理然后返回新数组。例如
Array.from('01',(count)=>{return Boolean(count)})
将成员转成布尔类型。例如Array.from('12',(count)=>{return count*2})
将成员每个乘以2。 - 第三个参数指定/修改this指向
Array.of()
Array.of()方法用于将一组值转化为数组,即新建数组,而不考虑参数的数量或类型。
//使⽤Array.of()创建数组
console.log(Array.of()); //[] 创建⼀个空数组
console.log(Array.of(8)); //[8] 创建只有⼀个元素值为8的数组 console.log(Array.of(1, 2, 3)); //[1,2,3] 创建⼀个值为1,2,3的数组
//以前直接使⽤Array创建数组
console.log(Array()); //[] 创建⼀个空数组
console.log(Array(4)); // [ , , , ] 创建拥有4个元素空值的数组
console.log(Array(1, 2, 3)); //[1,2,3] 创建⼀个值为1,2,3的数组
find() 和 findIndex()
find() 方法找到满足条件的第一个立即返回这个值。
findIndex() 方法找到满足条件的第一个立即返回其索引。
- 第一个参数是一个回调函数,回调函数的参数分别为 (1)可遍历对象键值对的值 (2)可遍历对像键值对的键 (3)可遍历对像本身。可以在这个函数里指定规则。
- 第二个参数是回调函数里面的 this 指向
some() 和 every()
ARR.every() 和 ARR.every() 目的:确定数组的所有成员是否满足指定的测试
- some() 方法:只要其中一个为true 就会返回true。
- every() 方法:必须所有都返回true才会返回true,哪怕有一个false,就会返回false.
const data =[
{name:'zhangsan',age:22,sex:'man'},
{name:'lisi',age:25,sex:'woman'},
{name:'wangwu',age:23,sex:'man'},
];
//使⽤some判断data中是否含有⼀条name以"wang"开头的
let s1 = data.some(v => v['name'].startsWith("wang"));
console.log(s1); //true
//使⽤every判断data信息中是否都是age⼤于20的信息。
let s2 = data.every(v => v['age']>20);
console.log(s2); //true
若有⼀个不符合则返回false
fill()
ARR.fill() 函数,使用指定的元素替换原数组内容,会改变原来的数组。
参数一:要改变成的内容;参数二:要改变的开始位置;参数三:要改变的结束位置。
//空数组则没有替换
console.log([].fill(6)); //[]
//将数组中的值都替换成指定值6
console.log([1,2,3].fill(6));//(3) [6, 6, 6]
//从数组索引位置2开始替换成指定值6,替换到数组结束位置。
console.log([1,2,3,4,5].fill(6,2)); //(5) [1, 2, 6, 6, 6]
//从数组索引位置2开始替换到索引位置4前结束。
console.log([1,2,3,4,5].fill(6,2,4)); //(5) [1, 2, 6, 6, 5]
ES6对象新增方法
Object.assign()
Object.assign() 作用是合并对象
传入的参数为多个对象。本质是将后面参数的对象合并到第一个参数中,会改变第一个参数自身。如果不想改变任何参数,可以在第一个参数写一个空对象,例如: Object.assign({},obj1,obj2)
注意事项:基本数据类型作为源对象时,会先转换成对象,再合并。合并时如果出现同名属性,后面的会把前面的覆盖。
Object.keys() 、Object.values() 、 Object.entries()
这三个方法都是Object构造函数上的, 传入的参数是一个对象,执行后分别返回键名组成的数组、值组成的数组、键值对组成的数组。
为什么返回的不是 可迭代对象 ?因为 keys 是ES5的方法,ES5 中没有 Iterator 的概念,所以为了统一,Object 的这三个方法返回的都是数组。
Object.fromEntries()
是 Object.entries() 的逆操作,将可迭代对象作参数传入Object.fromEntries()中,会返回一个对象。
Object.is()
- ES5 ⽐较两个值是否相等,只有两个运算符:相等运算符(==)和严格相等运算符(===)。 它们都有缺点,前者会⾃动转换数据类型,后者的NaN不等于⾃身,以及+0等于-0。 JavaScript 缺乏⼀种运算,在所有环境中,只要两个值是⼀样的,它们就应该相等。
- ES6 提出“Same-value equality”(同值相等)算法,⽤来解决这个问题。 Object.is就是部署这个算法的新⽅法。它⽤来⽐较两个值是否严格相等,与严格⽐较运算符 (===)的⾏为基本⼀致。
Object.is('foo', 'foo') // true
Object.is({}, {}) //false
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
Object.getOwnPropertyDescriptors()
ES5 的Object.getOwnPropertyDescriptor()⽅法会返回某个对象属性的描述对象 (descriptor)。 ES2017 引⼊了Object.getOwnPropertyDescriptors()⽅法,返回指定对象所有⾃身属性(⾮继承 属性)的描述对象
const obj = { foo: 123, get bar() { return 'abc' } };
Object.getOwnPropertyDescriptors(obj);
// { foo:
// { value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:
// { get: [Function: get bar],
// set: undefined,
// enumerable: true,
// configurable: true } }
、proto属性,Object.setPrototypeOf()和Object.getPrototypeOf()
JavaScript 语⾔的对象继承是通过原型链实现的。ES6 提供了更多原型对象的操作⽅法。 具体详⻅⽂档
Object.defineProperty
参数一:给谁添加属性
参数二:添加属性的属性名
参数三:配置项,是一个对象,其中包括value。
此方法定义的属性默认是不可枚举/遍历的,可在配置项里修改enumerable:true
开启遍历。
定于的属性默认是不可以被修改的,可在配置项修改 writable:true
开启修改
定义的属性默认是不可以被删除的,可在配置项修改 configurable:true
开启删除
类与对象
class (类)
- Javascript 的类,写法为
class 类名{ }
注意没有圆括号和分号。
- 类也可以是匿名的,所以可以用表达式形式定义类
const 类名 =class{ }
-
type of 类
返回的也是一个 function ,类里的方法本质上也是相当于写在这个 function 上的 prototype 上,所以 class 是构造函数的语法糖。
所以衍生出了“立即执行类”,例如:
//加new因为constructor必须要有new才能执行。
(new class {
constructor(){
执行语句;
}
})
constructor
class里的构造方法 constructor 用法,如下:
class 类名{
constructor(参数1,参数2...参数n){
this.属性名1 = 参数1;
this.属性名2 = 参数2
}
}
- 构造方法 constructor 里面的 this 直接指向实例化出来的对象。
- 构造方法 constructor 里面一般不定义方法,只定义属性,因为 constructor 里的方法会使每个实例都新生成一个自己的方法,占用新内存。
- 所以共享的方法直接写在类里即可,不用写在 constructor 里面,注意写法,方法与方法之间没有逗号,直接写
方法名(){ }
即可,不用加function关键字,例如:
class 类名{
constructor(参数1,参数2...参数n){
this.属性名1 = 参数1;
this.属性名2 = 参数2
}
方法1 (){ }
方法2 (){ }
}
类的方法(静态方法)
使用关键字 static ,写在声明里,是只有类可以访问的,实例无法访问,例如:
//static 静态方法名(){}
class Lei{
static func(){
console.log('静态方法')
}
}
Lei.func()
类的属性(静态属性)
有三种方法:
- 类名.属性名 = 值
- 声明里写 static 静态方法(){return 值;}
- 声明里直接写 static 静态属性 = 值
方法3存在兼容性问题,低版本浏览器不支持。
实例对象
如何创建一个实例:
new 类名();
即可生成一个实例对象,这个实例对象会拥有 class 里面的 constructor 的属性。例如
class Person{
constructor(a,b){
this.name = a;
this.age = b;
}
}
const student = new Person('ming',24);
这个 student 就会拥有 name 和 age 属性,属性值是什么取决于你写的是定值还是参数。
也可以给属性值添加默认值(截至2021年7月默认值已失效)
JS 类与对象 的私有属性和方法
想要实现私有,可以使用闭包实现,或者利用模块化。
class 继承
使用关键字 extends 和关键字 super ,例如:
class Person{
constructor(a,b){
this.name = a;
this.age = b;
}
func(){console.log(1)}
}
class Student extends Person{
}
此时 Student 这个类就会拥有 Person 的所有构造方法和共享方法。
子类如果想要拥有自己的构造方法,则必须配合 super 关键字使用,否则会报错;
super 前面不能放任何this操作,否则报错。例如
class Person{
constructor(a,b){
this.name = a;
this.age = b;
}
func(){console.log(this.name)}
}
class Student extends Person{
constructor(x,y,c){
super(x,y)
//这里super接收的参数会扔到父类的constructor中执行,this指向子类实例
this.newProp = c
}
}
子类想要使用父类的方法,子类调用的父类方法里的this指向的是父类,所以要在之类的构造方法里使用super
class 中的 super 关键字
- 在构造方法和一般方法中使用,super 代表的都是父类的原型 SUPERCLASS.prototype
- 在静态方法 static FUNCTION(){} 中使用,代表的是父类自身,this 指向子类。
- super 要么接点要么接括号,否则浏览器会报错。
class中的get和set
当实例调用读取父类方法时会触发get方法,get方法里面返回的值就是触发后返回的值
当实例修改父类方法时会触发set方法,set方法必须带有一个形参
class Phone{
get price(){
console.log('价格属性被读取了')
return 'iloveyou'
}
set price(newVal){
console.log('价格被修改了')
}
}
let s = new Phone()
console.log(s.price); //这里会触发get price并得到里面的返回值
s.price = 'free'; //这里会触发set
Module 模块系统
模块系统解决的主要问题:
- 模块化的问题。
- 消除全局变量。
- 管理加载顺序。
import、export、export default 和 script type='module'
- 只要你会用到 import 或 export ,在使用 script 标签加载的时候,就要使用
<script type='module'></script>
- 一个模块如果没有导出,也可以直接将其导入,被导入的代码都会执行一遍,多次导入同一个模块也只执行一遍,但无法使用模块的东西。
export default
export default 可以直接接模块里的定变量名,类或类名,方法或方法名等。
- 注意一个模块只能有一个 export default
- 注意 export default 导出的东西是按语句顺序执行的,没有提升。
export default 的 import 直接写导出的东西然后命名即可,名字可以随便取。
export
export 导出可以有两种形式。
- 接声明或语句,例如
export let a = 'cosin'
- 接大括号,例如
export {导出1,导出2}
export 的 import 只能用大括号接收,例如import{导出1,导出2}
如果导出或导入的东西想改名称,可以使用 as
关键字,例如:
export {name as newName} //此时import 接收的是 newName
import{newName as newnew}
import
import三种形式导入
- 通用形式导入,用as后接一个名字当作接受的对象
import * as m1 from './js/m1.js'
console.log(m1.name)
m1.fn()
- 解构赋值形式导入
import {name,fn} from './js/m1.js'
import {name as mingzi,fn as fangfa} from './js/m2/js'
import {default as mod} from './js/m3.js'
- 简便形式 仅针对 export deafault 默认暴露
import m3 from './js/m3.js'
同时导入
因为 export 和 export default 的导入方式不同,所以想一次导入这两种导出,可以使用:
import default导出的,{非default导出} from '路径'
- 采用整体导入,使用通配符 * 星号然后接 as 然后接一个名字,就代表导入所有导出的,包括 export 和 export default 的,例如:
import * as obj from './module.js'
导入的内如是一个 Module 对象,导出的东西都会变成这个 Module 对象的属性,default 的内容会变成 default 属性
Module 注意事项
- 导入的变量是只读的,导入的对象的属性值可以修改。
- 一个模块可以直接写export,即导入后直接导出,此时这个模块不可以使用导入的任何东西,相当于一个中转站。
- import 和 export 命令具有提升效果,会提升到整个模块的头部并率先执行。所以 import 和 export 别写在代码块中,想要按条件导入,可以使用 import() 函数。
- 模块顶层的 this 指向 undefined ,可以利用这点提示使用模块加载,例如:
if(type of this !== 'undefined'){
throw new Error('请使用模块加载')
}
ES6 数值拓展
Number.EPSILON
Number.EPSILON是 Javascript表示的最小进度,可以用来做浮点运算判断 、
fuction equal(a,b){
if(Math.abs(a-b)<Number.EPSILON){
return true;
}else{
return false;
}
}
console.log(equal(0.1+0.2,0.3))
Number.isFinite 检测一个数值是否为有限数
console.log(Number.isFinite(100))
Number.isNaN
isNaN旧方法扔进Number中
Math.trunc()
将数字(参数)的小数部分抹掉
Math.sign()
判断参数是正数、负数、还是0
直接书写N进制数字
let b = 0b1010
let o = 0o777
ES7 新特性
includes
可以检测数组是否拥有该组员
两个星号(乘号)
两个星号后面接的数字代表几次方,2 ** 10 类似于 Math.pow(2,10)
ES8
async 函数
在函数前面加上 async 关键字
async function fn(){
}
async函数返回结果是一个promise,返回的promise状态由内容决定
- 如果返回的东西是一个Promise对象,则由该promise决定成功还是失败
- 如果返回结果是抛出一个错误,则状态为失败reject,例如 throw new Error('err')
- 其他返回结果大多为成功resolve/fulfilled
await
- await 要放在 async 函数中
- await 右侧的表达式一般为 promise 对象
- await 返回的是 promise 成功的值
- await 的 promise 失败了,就会抛出异常,需要使用 try{}catch{} 捕获
ES9
正则捕获分组
?<>
方向断言
?<=
dotAll 拓展
结尾加上s
ES10
数组拓展 flat
将多维数组转化为低维数组
ARR.flat()
参数是数字,意义为展开深度为几层,例如三维转一维,深度就是3-1=2
数组拓展 flatMap
如果数组使用map之后返回一个多元数组,flatMap则是把多元数组变回一维数组,
ARR.flatMap() 就是数组的map方法和flat方法结合
Symbol.prototype.description
let sb = Symbol('HQM')
sb.description
ES11
对象的私有属性
在属性前面加上井号
class Person{
name;
#age;
#weight;
constructor(name,age,weght){
this.name = name;
this.#age = age;
this.#weight = weight;
}
}
const girl = new Person('hong',18,'45kg')
console.log(girl.#age) //此时会报错,私有属性不能在外部直接访问,可以在类定义一个内部方法通过内部方法访问
Promise.allSettled
- Promise.all 是有一个失败则直接返回失败。
- 而 Promise.allSettled 是无论成功还是失败都会把所有参数里的Promise全部执行完再返回结果。结果都是成功
- Promise.allSettled() 和 Promise.all() 的参数都是一个可迭代对象(通常为数组)
可选链操作符
?.
当一个函数的参数 是一个对象的时候,如果要找传入的对象是否有这个值,一般需要层层判断,有了可选链操作符,直接使用 ?. 即可,不会报错
const fn = (config) => {
console.log(config.db.a1);
}
fn({
db: {
a1: '111',
a2: '222'
}
})
//如果有这个参数则不会报错
const fn = (config) => {
console.log(config.db.a1);
}
fn()
//如果没有这个参数则报错,只能使用 config&&config.db&&config.db.a1
有了可选链操作符,只需要这样即可
console.log(config?.db?.a1)
动态import
主要用来提升性能,动态import就是不在文件头部使用import导入模块,而是使用import()这个函数在使用的时候才导入,函数的参数就是导入这个模块的路径。
导入执行之后返回的是一个Promise,用then后的回调函数的参数接收此模块
BigInt() 大整数
在整数后面加一个字母n,就是大整型数据类型
let bi = 521n
console.log(bi,typeof bi)
使用 BigInt() 方法,往里面穿一个整型数字,就会转变为大整型数字
let norm = 123
console.log(BigInt(norm))
运用场景是大数值运算,BigInt不能和普通Int做运算
let max = Number.MAX_SAFE_INTEGER
console.log(max)
console.log(max+1)
console.log(max+2)
//此时就会计算丢失精度
console.log(BigInt(max))
console.log(BigInt(max)+BigInt(1))
console.log(BigInt(max)+BigInt(2))
//使用BigInt之后就没有问题