ES6+

ES6简介

ECMAScript 第六代标准

let 和 const

用于声明变量或声明常量

变量和常量
var 和 let 声明的就是变量,变量初始化后还可以重新赋值。
const 声明的是常量,常量一旦初始化后就不能重新赋值,否则报错。常量可以防止不经意间改变了不能改变的量。如果常量值的类型是引用类型,例如对象,可以修改对象属性的值。
const 声明常量一旦声明,就必须完成初始化,否则报错

let、const 与 var 的区别

  1. 重复声明:var 支持重复声明,let 与 const 不支持。
  2. 变量提升:let 与 const 不存在变量提升。
  3. 暂时性死区:只要作用域内存在 let 和 const ,他们声明的量就会绑定作用域,该量不再受外部影响。
  4. window对象的属性和方法:let 和 const 声明的量不会变成 window 对象的属性或方法。
  5. 块级作用域: let 与 const 存在块级作用域。

模板字符串

一般字符串:单引号和双引号。
模板字符串:反引号。

特征:

  1. 模板字符串中所有空格、换行、缩进都被保留在输出中。
  2. 同样可以使用转义字符输出反引号、反斜杠等特殊字符。
  3. 可以直接在模板字符串中使用${} 注入内容(变量,属性值,函数值,计算值等)

标签模板

是函数调用的一种特殊形式。模板字符串可以紧跟在一个函数后面,该函数将被调用来处理这个模板字符串,这被成为“标签模板”功能,例如:

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, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;");

    // Don't escape special characters in the template.
    s += templateData[i];
  }
  return s;}

箭头函数

写法: ()=>{} 小括号内参数,等号大于号,中括号内函数体。
通常需要用一个变量或常量接收。

注意事项

  1. 单个参数可省略小括号,0个或多个不可省略。
  2. 单行函数体可同时省略大括号和 return ,必须同时。
  3. 单行对象如果要省略大括号,需要在对象外加小括号:例如 const add = (x+y)=>({value:x+y})

箭头函数没有自己的this

非箭头函数执行一定会产生属于这个函数的this,箭头函数没有自己的this,只会从自己的作用域链的上一层继承 this.

箭头函数使用注意

  1. 不能作为构造函数。
  2. 需要 this 指向调用对象的时候箭头函数不适用。
  3. 需要 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是填充的意思,用于补全字符串长度,无法改变原字符。
用法:

  1. 第一个参数表示“需要补到的长度”是多少,通常是一个整数。
  2. 第二个参数表示“补入的值”,如果不传参数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()

类的属性(静态属性)

有三种方法:

  1. 类名.属性名 = 值
  2. 声明里写 static 静态方法(){return 值;}
  3. 声明里直接写 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 关键字

  1. 在构造方法和一般方法中使用,super 代表的都是父类的原型 SUPERCLASS.prototype
  2. 在静态方法 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 模块系统

模块系统解决的主要问题:

  1. 模块化的问题。
  2. 消除全局变量。
  3. 管理加载顺序。

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 导出可以有两种形式。

  1. 接声明或语句,例如 export let a = 'cosin'
  2. 接大括号,例如 export {导出1,导出2}
    export 的 import 只能用大括号接收,例如 import{导出1,导出2}

如果导出或导入的东西想改名称,可以使用 as 关键字,例如:

export {name as newName}    //此时import 接收的是 newName
import{newName as newnew}

import

import三种形式导入

  1. 通用形式导入,用as后接一个名字当作接受的对象
import * as m1 from './js/m1.js'
console.log(m1.name)
m1.fn()
  1. 解构赋值形式导入
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'
  1. 简便形式 仅针对 export deafault 默认暴露
import m3 from './js/m3.js'

同时导入

因为 export 和 export default 的导入方式不同,所以想一次导入这两种导出,可以使用:

  1. import default导出的,{非default导出} from '路径'
  2. 采用整体导入,使用通配符 * 星号然后接 as 然后接一个名字,就代表导入所有导出的,包括 export 和 export default 的,例如:
import * as obj from './module.js'

导入的内如是一个 Module 对象,导出的东西都会变成这个 Module 对象的属性,default 的内容会变成 default 属性

Module 注意事项

  1. 导入的变量是只读的,导入的对象的属性值可以修改。
  2. 一个模块可以直接写export,即导入后直接导出,此时这个模块不可以使用导入的任何东西,相当于一个中转站。
  3. import 和 export 命令具有提升效果,会提升到整个模块的头部并率先执行。所以 import 和 export 别写在代码块中,想要按条件导入,可以使用 import() 函数。
  4. 模块顶层的 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状态由内容决定

  1. 如果返回的东西是一个Promise对象,则由该promise决定成功还是失败
  2. 如果返回结果是抛出一个错误,则状态为失败reject,例如 throw new Error('err')
  3. 其他返回结果大多为成功resolve/fulfilled

await

  1. await 要放在 async 函数中
  2. await 右侧的表达式一般为 promise 对象
  3. await 返回的是 promise 成功的值
  4. 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之后就没有问题

绝对全局对象 globalThis

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容