当前位置:网站首页>【记录】ES6

【记录】ES6

2022-08-11 05:16:00 Yokirrr_

ES6

声明变量

var

function

let

  • 块级作用域。
  • 不存在变量提升。
  • 同一作用域内不可重复声明。

const

  • 块级作用域。
  • 一定要赋初始值。
  • 值不可修改。
    但是对于数组和对象的元素进行修改,不会报错。因为数组和对象的常量中保存的是对它们的引用地址,值发生改变不会影响引用地址。
    const TEAM = [‘A’, ‘B’, ‘C’];

import

class


注意

  • ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。
  • var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。

解构赋值

解构赋值指允许从数组和对象中提取值,对变量进行赋值。

//数组
//数组的元素是按次序排列的,变量的取值由它的位置决定。
const F4 = ['小沈阳', '刘能', '赵四', '宋小宝'];
let [xiao, liu, zhao, song] = F4;
console.log(xiao);//小沈阳


//对象
const zhao = {
    
	name: '赵本山',
	age: '不详',
	xiaopin: function(){
    
		console.log("aa");
	}
};
//完整写法
//属性名:变量名
let {
    name: name, age: age, xiaopin: xiaopin } = zhao;
//如果变量名和属性名相同,可以简写成
let {
    name, age, xiaopin} = zhao;
//对象的解构赋值可以取到继承的属性。
const obj1 = {
    };
const obj2 = {
    foo: 'bar'};
Object.setPrototypeof(obj1, obj2);
const {
    foo} = obj1;
foo // 'bar'


//字符串
const [a, b, c, d, e] = 'hello';
a //'h'
let {
    length: len} = 'hello';
len //5


//数值和布尔值


//函数参数


//可以指定默认值。使用===判断一个位置是否有值,只有严格等于undefined,默认值才会生效。
let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null

//用途
//1、交换变量的值
let x = 1;
let y = 2;
[x, y] = [y, x];

//2、提取数据
let data = {
    
	id: 42,
	status: 'ok',
	data: [214, 321]
};
let {
    id, status, data: number} = data;
console.log(number); // [214, 321]

//3、设置函数参数的默认值
function(url, {
     async = true, global = true }={
     }){
    
	...
}

//、引入模块的制定方法
const {
     SourceMapConsumer, SourceNode } = require("source-map");

字符串

//模版字符串`
let str = `呃呃呃呃呃呃`;
//允许直接出现换行符,所有的空格和缩进都会被保留。
let html = `<div> <span></span> </div>`;
//变量拼接
let html = `<div> <span>${
      str}</span> </div>`;


//includes()
//返回是否找到了参数字符串。第二个参数表示开始搜索的位置。
let s = 'hello world!';
s.includes('l') // true
s.includes('hello', 6) // false
//startsWith()
//返回参数字符串是否在原字符串的头部。第二个参数表示开始搜索的位置。
s.startsWith('h') // true
s.startsWith('world', 6) // true
//endsWith()
//返回参数字符串是否在原字符串的尾部。第二个参数表示针对前n个字符。
s.endsWith('!') // true
s.endsWith('hello', 5) // true

//repeat()
//返回一个新的字符串,表示将原字符串重复n次。
'x'.repeat(3) // 'xxx'
//参数是小数,会向下取整。
'na'.repeat(2.9) // 'nana'
//参数是负数或Infinity,会报错。
'na'.repeat(Infinity) // RangeError
'na'.repeat(-1) // RangeError
//参数是0~-1之间的小数,则取0。
'na'.repeat(-0.9) // ''
//参数是NaN,则取0。
'na'.repeat(NaN) // ''
//参数是字符串,会先转换成数字。
'na'.repeat('na') // ''
'na'.repeat('3') // 'nanana'

//at()
//返回参数指定位置的字符,支持负索引(即倒数的位置)。
const str = 'hello';
str.at(1) // 'e'
str.at(-1) // 'o'

数值

//Number对象
//Number.EPSILON是JS表示的最小精度。主要用于浮点数。
//接近于2.22044...
function equal(a, b){
    
	if(Math.abs(a-b) < Number.EPSILON){
    
		return ture;
	}else{
    
		return false;
	}
}
console.log(0.1 + 0.2 === 0.3);//false
console.log(equal(0.1+0.2, 0.3));//true

//二进制、八进制
let b = 0b1010;
let o = 0o777;

//Number.isFinite()
//检查是否有限。
isFinite(25) // true
isFinite('25') // true
Number.isFinite(25) // true
Number.isFinite('25') // false

//Number.isNaN()
//检查是否为NaN。
//它们与传统的全局方法isFinite()和isNaN()的区别在于,传统方法先调用Number()将非数值的值转为数值再进行判断,而这两个新方法只对数值有效。
isNaN(NaN) // true
isNaN('NaN') //true
Number.isNaN(NaN) //true
Number.isNaN("NaN") // false
Number.isNaN(1) // false

//Number.parseInt()
//Number.parseFloat()
//将全局方法`parseInt()`和`parseFloat()`,移植到`Number`对象上面,行为完全保持不变。

//Number.isInteger()
//判断一个数值是否为整数。
Number.isInteger(25) // true
Number.isInteger(25.1) // false
//存在误判
Number.isInteger(25.0) // true
//如果一个数值的绝对值小于`Number.MIN_VALUE`(5E-324),即小于 JavaScript 能够分辨的最小值,会被自动转为 0。这时,`Number.isInteger`也会误判。
Number.isInteger(5E-324) // false
Number.isInteger(5E-325) // true




//Math对象
//Math.trunc()
//去除一个数的小数部分,返回整数部分。
Math.trunc(4.1) //4
//对于非数值,会先转为数值再处理。
Math.trunc(null) //0
//对于空值和无法截取整数的值,返回NaN。
Math.trunc() //NaN

//Math.sign()
//参数为正数,返回+1;参数为负数,返回-1;参数为0,返回0;参数为-0,返回-0;其他,返回NaN。
//对于非数值,会先转为数值再处理。

//Math.cbrt()
//计算一个数的立方根。

//Math.clz32()
//count leading zero bits in 32-bit binary representation of a number
//将参数转为 32 位无符号整数的形式,然后返回这个 32 位值里面有多少个前导 0。
//对于小数,只考虑整数部分。
//对于非数值,会先转为数值再处理。

//Math.imul()
//返回两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数。

//Math.fround()
//返回一个数的32位单精度浮点数形式。

//Math.hypot()
//返回所有参数的平方和的平方根。

//Math.expm1(x)
//返回e^x-1。

//Math.log1p(x)
//返回log(1+x)。

//Math.log10(x)
//返回log10(x)

//Math.log2(x)

//Math.sinh(x)
//Math.cosh(x)
//Math.tanh(x)
//Math.asinh(x)
//Math.acosh(x)
//Math.atanh(x)

函数

(1)箭头函数

箭头函数适合与this无关的回调,比如定时器、数组的方法回调。
不适合与this有关的回调,比如事件回调、对象的方法。

let f = (a, b) => {
    };
//等同于
let f = function(a, b){
    };

//箭头函数的简写。
//1、省略(),只有一个形参。
let f = a => {
    };
//2、省略{},当代码体只有一条语句时,此时return必须省略。函数执行结果就是返回值。
let f = n => n*n;
//3、返回对象要在对象外加括号,否则会被认为是代码块。
let getItem = id => ({
    id: id, name: "temp"});


//不能作为构造实例化对象。
//构造函数
function Person(name, age){
    
	this.name = name;
	this.age = age;
}
//错误:用箭头函数构造实例化对象
let Person = (name, age)=>{
    
	this.name = name;
	this.age = age;
}

//没有自己的this对象。
//对于普通函数来说,内部的`this`指向函数运行时所在的对象,箭头函数内部的`this`就是定义时上层作用域中的`this`。
function getName(){
    
	console.log(this.name);
}
let getName2 = ()=>{
    
	console.log(this.name);
};
window.name = 'window';
const school = {
    
	name: 'school'
};
getName.call(school);//'school'
getName2.call(school);//'window'


//不能使用arguments对象。如果要使用,可以使用rest参数代替。

//不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

(2)参数

函数参数的默认值

//一般具有默认值的参数位置靠后。
//参数是按顺序赋值的,如果c插在中间即add(a, c=10, b),2会赋值给c,则b=undefined。
function add(a, b, c=10){
    
	return a+b+c;
}
let result = add(1, 2);

//与解构赋值结合
function connect({
    host = '127.0.0.1', username, password, port}){
    
	console.log(host);
	console.log(username);
	console.log(password);
	console.log(port);
}
connect({
    
	username: 'root',
	password: 'root',
	port: 3306
});

rest参数

  • 形式为…变量名
  • 用于获取函数的实参,用来代替arguments。
  • 必须放在参数最后。
  • 返回的是数组。
function date(a, b, ...args){
    
	console.log(a);
	console.log(b);
	console.log(args);
}
data(1, 2, 3, 4,5);
//a = 1, b = 2, args = [3, 4, 5];

(3)属性方法

函数的length属性

//指定了默认值后,length=没有指定默认值的参数个数。
(function (a) {
    }).length // 1
(function (a = 5) {
    }).length // 0
(function (a, b, c = 5) {
    }).length // 2
//不计入rest参数。
(function (...args){
    }).length // 0
//不计入设置了默认值的参数后面的参数个数。
(function (a = 0, b, c){
    }).length // 0
(function f(name, age=18, gender, ...args){
    }).length // 1

//面试题
123['toString'].length + 123//124
//123相当于new Number()
//顺着隐式原型链,new Number()=>Number.prototype,找到toString属性(方法是特殊的属性),toString.length=1

函数的name属性

  • 返回该函数的函数名。
//如果将一个匿名函数赋值给一个变量,ES5会返回空字符串,而ES6会返回变量名。
var f = function(){
    };
//ES5
f.name // ""
//ES6
f.name // "f"

//Function构造函数返回的函数实例,返回anonymous。
(new Function).name // "anonymous"

//bind返回的函数,会加上bound前缀。
function foo(){
    };
foo.bind({
    }).name //"bound foo"

数组

(1)扩展运算符

扩展运算符…

  • 能将数组转化为用逗号隔开的参数序列。
const strs = ['a', 'b', 'c'];
function f(){
    
	console.log(arguments);
}
f(...strs);
//等同于
f('a', 'b', 'c');

//应用
//1、数组合并(浅拷贝)
//以前:因为push()参数不能是数组,需要利用apply方法。
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2);
//ES6
arr1.push(...arr2);

//2、数组的克隆(深拷贝)
const str1 = ['a', 'b'];
const str2 = [...str1];

//3、将伪数组转为真正的数组
//可以实现将arguments转为真正的数组。
const divs = document.querySelectorAll('div');
const divArr = [...divs];

//4、将数组内的成员作为函数的参数
//以前:利用apply方法。
f.apply(null, args);
//ES6
f(...args);

(2)属性方法

//Array对象自身的方法
//Array.from():可以将类似数组的对象、可遍历的对象(包括Set和Map)转为真正的数组。
var arrayLike = {
    
	'0': 'a',
	'1': 'b',
	'2': 'c',
	length: 3
};
//ES5
var arr1 = [].slice.call(arrayLike);// ['a', 'b', 'c']
//ES6
let arr2 = Array.from(arrayLike);// ['a', 'b', 'c']
//还可以接受第二个参数,作用类似于数组的`map`方法,用来对每个元素进行处理,将处理后的值放入返回的数组。
Array.from(arrayLike, x => x * x);
//等同于
Array.from(arrayLike).map(x => x * x);

//Array.of():将一组值,转为数组。规避Array()的诡异行为。
Array.of() // []
Array.of(3) // [3]
Array.of(3, 11, 8) //[3, 11, 8]
//Array()
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]



//Array原型对象上的方法
//copyWithin(target, start, end):在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。使用这个方法,会修改当前数组。
/* target(必要):从该位置开始替换数据。可负数。 start:从该位置开始读取,默认为0。 end:从该位置前停止读取,默认为数组长度。 */
[1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5]

//find():返回第一个符合条件的数组成员。
//find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。
[1, 2, 3, 4, 5].find((value, index, arr)=>{
    
	return value > 3;
}) // 4
//find方法还可以接受第二个参数,绑定回调函数的this对象。
//findIndex():返回第一个符合条件的数组成员下标。
//以上方法都可以发现NaN。

//fill(value, start, end):按照value填充[start, end)数组。
/* value(必要):用来初始化的值。 start:开始位置,默认为0。 end:结束位置, 默认为数组长度。 */

//entries():对键值对的遍历。返回的是Iterator对象。
for(let [index, elem] of ['a', 'b'].entries()){
    
	console.log(index, elem);
}
//keys():对键名的遍历。返回的是Iterator对象。
for(let index of ['a', 'b'].keys()){
    
	console.log(index);
}
//values():对键值的遍历。返回的是Iterator对象。
for(let elem of ['a', 'b'].values()){
    
	console.log(elem);
}

//at():接受一个整数作为参数,返回对应位置的成员,支持负索引。这个方法不仅可用于数组,也可用于字符串和类型数组(TypedArray)。
//如果参数位置超出了数组范围,则返回undefined。
const arr = [5, 12, 8, 130];
arr.at(2) // 8
arr.at(-2) // 8

(3)数组的空位

数组的空位指的是,数组的某一位置上没有任何值。

  • 比如Array(3) // [, , ,]

ES5

  • forEach(), filter(), reduce(), every()some()都会跳过空位。
  • map()会跳过空位,但会保留这个值
  • join()toString()会将空位视为undefined,而undefinednull会被处理成空字符串。

ES6

  • 将空位转为undefined。

对象

//对象的简写
//允许在大括号里直接写入变量和函数,作为对象的属性和方法。
//同名变量简写。
let name = 'a';
const obj = {
    
	name,
	//等同于
	//name: name
	improve(){
    }
	//等同于
	//improve: function(){}
};

//对象的定义(字面量)
//ES5:属性名不能是表达式。
var obj = {
    
	foo: true,
	abc: 123
};
//ES6:属性名可以是表达式、变量,要用方括号扩起来。
let lastWord = 'last_word';
const a = {
    
	'first_word': 'hellp',
	[lastWord]: 'world',
	['e'+'nd']: '!'
}

//遍历对象的属性
//for...in:遍历对象自身的、继承的可枚举属性(不含Symbol属性)
//Object.keys(obj):返回数组,包括对象自身的可枚举属性的键名(不含Symbol属性)。
//Object.getOwnPropertyNames(obj):返回数组,包括对象自身的所有属性的键名(不含Symbol属性)。
//Object.getOwnPropertySymbols(obj):返回数组,包括对象自身的所有Symbol属性的键名。
//Reflect.ownKeys(obj):返回数组,包括对象自身的所有属性的键名。


//对象的方法
//Object.is():判断两个值是否相同。
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
//==:自动转换数据类型
//===:NaN不等于自身;+0等于-0

//Object.assign():将源对象的所有可枚举属性复制到目标对象。返回目标对象。(拷贝源对象自身的可枚举属性,包括Symbol属性;浅拷贝)
//第一个参数是目标对象,后面的参数都是源对象。
const target = {
     a: 1, b: 2 };
const source = {
     b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);// { a: 1, b: 4, c: 5 }
console.log(returnedTarget);// { a: 1, b: 4, c: 5 }
//可以用来处理数组,但会把数组看作对象。
Object.assign([1, 2, 3], [4, 5]) // [4, 5, 3]
//只能复制值,如果要复制的值是一个取值函数,那么将求值后再复制。

//Object.setPrototypeOf(target, prototype):设置原型对象。
//Object.getPrototyoeOf(target):获取原型对象。

super关键字

  • 指向当前对象的原型对象
//super.foo等同于Object.getPrototypeOf(this).foo或Object.getPrototypeOf(this).foo.call(this)
const proto = {
    
	foo: 'hello'
};
const obj = {
    
	foo: 'world',
	find(){
    
		return super.foo;
	}
};
Object.setPrototypeOf(obj, proto);
obj.find()// "hello"

//只能用在对象的方法中,用在其他地方都会报错。目前只有对象方法的简写法可以让JS引擎确定定义的是对象的方法。
//error: super用在属性里面
const obj = {
    
	foo: super.foo
};
//error: super用在一个函数里,再赋值给foo属性。
const obj = {
    
	foo: ()=> super.foo
};
const obj = {
    
	foo: function(){
    
		return super.foo;
	}
};

__proto__

  • 内部属性。
  • 无论从语义的角度,还是从兼容性的角度,都不要使用这个属性,而是使用下面的Object.setPrototypeOf()(写操作)、Object.getPrototypeOf()(读操作)、Object.create()(生成操作)代替。

symbol

ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol的原因。
表示独一无二的值。基本上,它是一种类似于字符串的数据类型。


特点

  • Symbol的值是唯一的,用于解决命名冲突的问题。
  • Symbol定义的对象属性不能使用for…in、for…of循环遍历,也不会被Object.keys()Object.getOwnPropertyNames()JSON.stringify()返回。但是可以使用Object.getOwnPropertySymbols()来获取对象的所有Symbol属性名;或者使用Reflect.ownkeys来获取对象的所有键名。
//创建symbol
let s = Symbol();

//Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述。
//主要是为了在控制台显示,或者转为字符串时,比较容易区分。
let s1 = Symbol('foo');
let s2 = Symbol('bar');
console.log(s1);//Symbol(foo);
console.log(s2);//Symbol(bar);
console.log(s1.toString());//'Symbol(foo)';
console.log(s2.toString());//'Symbol(bar)';

//如果SymbOl函数的参数是一个对象,则会调用该对象的toString方法,将其转为字符串,然后再生成一个Symbol值。

//Symbol函数的参数指示表示对当前Symbol值的描述,因此相同参数的Symbol函数的返回值也是不相等的。
let s1 = Symbol();
let s2 = Symbol();
s1===s2;//false

let s3 = Symbol('foo');
let s4 = Symbol('foo');
s3===s4;//false

//description属性可以直接返回Symbol的描述。
s3.description//"foo"

//Symbol值不能与其他类型的值进行运算,会报错。
"aaaa" + s;//TypeError: can't convert symbol to string

//Symbol值可以转为字符串、布尔值,但是不能转为数值。
String(s);//'Symbol()'
Boolean(s);//true
Number(s);//TypeError

//Symbol值作为对象属性名。
let s = Symbol();
//1
let a = {
    };
a[s] = 'hello';
//2
let a = {
    
	[s]: 'hello'
};
//3
let a = {
    };
Object.defineProperty(a, s, {
    value: 'hello'});
a[s]//'hello'

//Symbol值作为对象属性名时,不能用点运算符。
//点运算符后面总是字符串。如果不将Symbol值放在方括号里,会将代表Symbol值的变量名作为字符串解析,从而键名就不是变量名所代表的Symbol值。
let s = Symbol();
let obj = {
    
	[s]: function(arg){
    
	}
};
//等同于
let obj = {
    
	[s](arg){
    }
}//有时,我们希望重新使用同一个 Symbol 值,Symbol.for()方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1===s2;//true

Symbol属性

//hasInstance
//当其他对象使用instanceof来判断是否为该对象的实例时,会调用该方法。
class Even{
    
	static [Symbol.hasInstance](obj){
    
		return Number(obj) % 2 === 0;
	}
}
1 instanceof Even//false

//isConcatSpreadable
//布尔值,表示该对象用于Array.prototype.concat()是否可以展开。
//数组默认可以展开(undefined/true),对象默认不可以。
let arr2 = ['c', 'd'];
arr2[Symbol.isConcatSpreadable] = false;
['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']

iterator

const arr = ['a', 'b', 'c'];
//for...in遍历键名
for(let i in arr){
    
	console.log(i);
}
//0
//1
//2

//for...of遍历键值
for(let i of arr){
    
	console.log(i);
}
//'a'
//'b'
//'c'

Iterator
作用

  • 为各种数据结构提供统一的访问接口。
  • 使得数据结构的成员能够按照某种次序排列。
  • 供for…of消费。当使用for…of遍历时,会自动寻找Iterator接口,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性。

遍历过程

  • 创建一个指针对象,指向当前数据结构的起始位置。
    let iterator = arrSymbol.iterator;
  • 第一次调用对象的next方法,指针自动指向数据结构的第一个成员。
    iterator.next();
  • 接下来不断调用next方法,指针一直向后移动,直到指向最后一个成员。
  • 每调用next方法返回一个包含value和done属性的对象。

原生具备Iterator接口的数据结构如下:

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • arguments
  • NodeList
//对象没有默认部署Iterator接口。
//手写iterator
const obj = {
    
	data: [
		'b',
		'c',
		'd'
	],
	[Symbol.iterator](){
    
		let index = 0;
		return {
    
			next: ()=>{
    
				if(index < this.data.length){
    
					return {
    value: this.data[index++], done: false};
				}else{
    
					return {
    value: undefined, done: true};
				}
			}
		}
	}
}
//调用
for(let i of obj){
    
	console.log(i);
}
//'b'
//'c'
//'d'

generator

//应用
//1、逐步获取数据
function getUsers(){
    
	setTimeout(()=>{
    
		let data = 'users';
		//next()方法可以带一个参数,会被当作当前yield表达式的返回值。没有参数,则返回值是undefined。
		iterator.next(data);
	}, 1000);
}
function getOrders(){
    
	setTimeout(()=>{
    
		let data = 'orders';
		iterator.next(data);
	}, 1000);
}
function getGoods(){
    
	setTimeout(()=>{
    
		let data = 'goods';
		iterator.next(data);
	}, 1000);
}
function* gen(){
    
	let users = yield getUsers();
	let orders = yield getOrders();
	let goods = yield getGoods();
}
//调用Generator函数后,并不执行,而是返回指向内部状态的指针对象。
let iterator = gen();
//第一次使用next(),传递参数是无效的。
iterator.next();

所谓"异步",简单说就是一个任务不是连续完成的,可以理解成该任务被人为分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。
比如,有一个任务是读取文件进行处理,任务的第一段是向操作系统发出请求,要求读取文件。然后,程序执行其他任务,等到操作系统返回文件,再接着执行任务的第二段(处理文件)。这种不连续的执行,就叫做异步。
相应地,连续的执行就叫做同步。由于是连续执行,不能插入其他任务,所以操作系统从硬盘读取文件的这段时间,程序只能干等着。

Set

Set

  • 只有key,没有value。(key唯一)
//声明set
//可以接受数组(或者具有iterable接口的其他数据结构)作为参数。
let s = new Set([12324]);
s // [1, 2, 3, 4]
//添加新的元素:返回Set结构本身。
//不会发生类型转换,判断两个值是否不同是通过类似于===,但认为NaN等于自身,两个对象总是不相等的。
s.add(1);
//删除元素:返回布尔值,表示是否删除成功。
s.delete(4);
//检测是否存在某个元素:返回布尔值,表示该元素是否为Set的成员。
console.log(s.has(4));// false
//元素个数
console.log(s.size);
//清除所有成员:没有返回值。
s.clear();

//遍历方法(按照插入顺序遍历)
//Set结构没有键名,只有键值(键名=键值)
Set.prototype.keys()
Set.prototype.values()
Set.prototype.entries()
Set.prototype.forEach()

//应用
//1、去重
//数组
let arr = [1,2,3,4,5,4,3,2,1];
let result = [...new Set(arr)];
//字符串
[...new set('abbbdas')].join('');//"abds"
//2、交集
let arr2 = [4,5,6,5,6];
let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
//3、并集
let union = [...new Set([...arr, ...arr2])];
//4、差集 
let result = [...new Set(arr)].filter(item => !new Set(arr2).has(item));

WeakSet

  • 与Set类似,但是成员只能是对象(可以是数组或类似数组的对象)。
  • 对象都是弱引用(垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中)。
  • 不可遍历。
//声明
let ws = new WeakSet();
//添加
const obj = {
    };
ws.add(obj);
//删除
ws.delete(obj);
//检查是否存在
ws.has(obj);

Map

Map

  • 既有key也有value。
  • 它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
  • 也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。
//声明
let m = new Map();
//添加
m.set('name', 'a');
m.set('change', function(){
    
	...
});
let a = {
    
	name: 'b'
};
m.set(a, [1, 2, 3]);
//大小
m.size // 3
//删除
m.delete('name');
//获取
m.get('change') // function(){...}
//检查
m.has('change') //true
//清空
m.clear();

	
//只有对同一个对象的引用,Map 结构才将其视为同一个键。Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。
const map = new Map();
map.set(['a'], 555);
map.get(['a']) // undefined
	
	
//遍历方法(按照插入顺序)
Map.prototype.keys()
Map.prototype.values()
Map.prototype.entries()
Map.prototype.forEach()

WeakMap

  • 类似Map,但是只接受对象(除了null)作为键名。
  • 键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内。因此,只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用。
//声明
let wm = new WeakMap();
let key = {
    };
let obj = {
    };
//添加
wm.set(key, obj);
//删除
vm.delete(key);
//获取
vm.get(key)
vm.has(key)

//应用
//1、dom节点作为键名。

Proxy

代理器

  • 在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
//声明
//target表示要拦截的目标对象,handler用来定制拦截行为。
var proxy = new Proxy(target, handler);

//get():拦截某个属性的读取操作。
var person = {
    
	name: 'a'
};
var proxy = new Proxy(person, {
    
	get: function(){
    
		...
	}
});

//set()

Reflect

Promise

Promise对象代表一个异步操作。

  • 有三种状态:pending、fulfilled、rejected。状态只会改变一次且不可逆。
  • 作用
    解决回调地狱问题。
    代码可读性提高。
//应用
//封装AJAX
const p = new Promise((resolve, reject)=>{
    
	const xhr = new XMLHttpRequest();
	xhr.open('GET', 'url');
	xhr.send();
	xhr.onreadystatechange = function(){
    
		if(xhr.readystate === 4){
    
			if(xhr.status >= 200 && xhr.status < 300){
    
				resolve(xhr.response);
			}else{
    
				reject(xhr.status);
			}
		}
	}
});
//then():第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数。
//then()方法的返回结果是promise对象。promise对象的状态由回调函数的执行结果决定。
p.then(value => {
    
	//1、返回非promise类型的值,promise对象状态为fulfilled,值为该返回值。
	return 123;
	//2、返回promise类型的值,promise对象状态为该promise对象的状态,值为resolve/reject函数里的参数。
	return new Promise((resolve, reject)=>{
    
		resolve('ok');
	});
	//3、抛出错误,promise对象状态为rejected,值为Error的参数。
	throw new Error('出错啦');
	
}, error => {
    
	console.log(error);
	...
});
//catch():rejected状态的回调函数。
p.catch(error=>{
    

})

Class

class Phone{
    
	//构造方法:名字不能修改。
	constructor(brand, price){
    
		this.brand = brand;
		this.price = price;
	}
	//必须使用函数式写法,不能使用对象写法
	call(){
    
		console.log('a');
	}
	//静态属性:不能被实例对象访问到,只能通过Phone.change()访问到。
	static name = '手机';
	static change(){
    
		console.log('b');
	}
	//当通过实例对象读取该属性时触发,返回值就是函数的返回值。
	get price(){
    
		console.log('get');
		return '1';
	}
	//当通过实例对象设置该属性时触发。
	set price(value){
    
		console.log('set');
	}
}

let huawei = new Phone('华为', 4128);
huawei.call();//'a'
huawei.change();//undefined
console.log(huawei.price);
//'get'
//'1'
huawei.price = '2';
//'set'

class SmartPhone extends Phone{
    
	constructor(brand, price, size, color){
    
		super(brand, price);
		this.size = size;
		this.color = color;
	}
	//子类对父类继承的重写
	call(){
    
		...
	}
}


模块化

好处

  • 防止命名冲突。
  • 代码复用。
  • 高维护性。

ES6之前的模块化规范

  • CommonJs=>NodeJS、Browserify
  • AMD=>requireJS
  • CMD=>seaJS
//export命令:规定模块的对外接口。
//1、分别暴露:直接在要暴露的变量前面加export。
//m1.js
export let s = 's';
export function f(){
    
	...
}
//2、统一暴露
//m2.js
let s = 's';
function f(){
    
	...
}
export {
    s, f};
//3、默认暴露
export default{
    
	s: 's',
	f: function(){
    
		...
	}
}


//import命令:输入其他模块提供的功能。
//1、在文件里直接引入
<script type="module">
	//1、通用导入
	import * as m1 from './src/js/m1.js';
	console.log(m1.s);
	import * as m2 from './src/js/m2.js';
	console.log(m2.s);
	import * as m3 from './src/js/m3.js';
	console.log(m3.default.s);
	//2、解构赋值
	import {
    s, f} from './src/js/m1.js';
	consoel.log(s);
	import {
    s as s_plus, f as f_plus} from './src/js/m2.js';
	console.log(s_plus);
	import {
    default as m3} from './src/js/m3.js';
	console.log(m3.s);
	//3、简便:针对默认暴露
	import m3 from "./src/js/m3.js";
	console.log(m3.s);
</script>
//2、利用标签引入:用的ES6,兼容性不佳。
<script src="./src/js/app.js" type="module"></script>
//app.js
	import * as m1 from './src/js/m1.js';
	console.log(m1.s);
	import * as m2 from './src/js/m2.js';
	console.log(m2.s);
	import * as m3 from './src/js/m3.js';
	console.log(m3.default.s);
	//导入npm包语法
	import $ from 'jquery';
//3、babel转化后打包
<script src="dist/bundle.js"></script>

Babel

Babel是一个ES6转码器,可以将ES6代码转为ES5代码,从而在老版本的浏览器执行。

//.babelrc(run control)
{
    	
	//要被转换的
	"presets": [
		"@babel/env",
		"@babel/preset-react"
	],
	"plugins": []
}

babel-cli:实现命令行转码工具。
babel-preset-env:实现转码。
browserify(webpack):打包工具。


ES7

数组

//Array原型对象的方法
//includes():返回数组是否包含给定的值。
/* 第一个参数(必要):给定值。 第二个参数:搜索的起始位置,默认为0。 */
//可以查找NaN。
[1, 2, 3].includes(3, 1) //true

运算符

指数运算符**

2**4 //16

//运算时是右结合。
2 ** 3 ** 2// 相当于 2 ** (3 ** 2)


a **= 2 //相当于a = a * a

ES8

字符串

//字符串补全长度:如果某个字符串不够指定长度,会在头部或尾部补全。
//头部补全padStart()
'x'.padStart(5, 'ab') // 'ababx'
//尾部补全padEnd()
'x'.padEnd(5, 'ab') // 'xabab'
//原字符串长度+补全字符串长度>指定长度,则截去超出部分的补全字符串。
'x'.padEnd(5, '0123456') // 'x0123'
//如果省略第二个参数,默认使用空格补全。
'x'.padStart(5) // ' x'

对象

//Object.getOwnPropertyDescriptors():返回对象自身的所有属性的描述对象。
//Object.keys():返回对象自身的所有可遍历属性的键名。
//Object.values()
//Object.entries()

async函数

//async函数的返回值为promise对象。promise对象的结果由async函数执行的返回值决定(和then差不多)。
async function fn(){
    
	return new Promise((resolve, reject)=>{
    
		resolve('a');
	});
}
const result = fn();
console.log(result);

await表达式

const p = new Promise((resolve, reject)=>{
    
	resolve('success');
});
async function main(){
    
	//await必须要放在async函数中。
	//await右侧的表达式一般为promise对象。
	//await返回的是promise成功的值。如果promise失败了,会抛出异常,需要通过try...catch捕获。
	try{
    
		let result = await p;
	}catch(e){
    
		console.log(e);
	}
}


//应用
//async与await封装AJAX请求
function send(url){
    
	return new Promise((resolve, reject)=>{
    
		const xhr = new XMLHttpRequest();
		xhr.open('GET', url);
		xhr.send();
		xhr.onreadystatechange = function(){
    
			if(xhr.readystate === 4){
    
				if(xhr.status >= 200 && xhr.status < 300){
    
					resolve(xhr.response);
				}else{
    
					reject(xhr.status);
				}
			}
		}
	})
}
async function main(){
    
	let result = await send('url');
	console.log(result);
}
main();

ES9

对象

//rest参数(浅拷贝)
let {
    x, y, ...z} = {
    x: 1, y: 2, a: 3, b: 4}
x // 1
y // 2
z // {a: 3, b: 4}
//解构赋值等号右边必须是一个对象。如果等号右边是undefined或null,就会报错,因为它们无法转为对象。
let {
     ...z } = null; //error
let {
     ...z } = undefined; //error
//rest参数必须是最后一个参数,否则会报错。
let {
    x, ...y, ...z } = obj; //error

//扩展运算符(对象自身的所有可遍历属性)
let a_copy = {
    ...a};
//等同于
let a_copy = Object.assign({
    }, a);

正则

//命名捕获分组
//未使用时
let str = '<a href="http://www.baidu.com">abcd</a>';
const reg = /<a href="(.*)">(.*)<\/a>/;
console.log(reg.exec(str));
/* [ '<a href="http://www.baidu.com">abcd</a>', 'http://www.baidu.com', 'abcd', groups: undefined, ........... ] */

//使用后
const reg1 = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
console.log(reg1.exec(str));
/* [ '<a href="http://www.baidu.com">abcd</a>', 'http://www.baidu.com', 'abcd', groups: { text: 'abcd', url: 'http://www.baidu.com' }, ........... ]*/


//正向断言:根据后面的内容判断前面的内容。
//提取出啦啦啦前面的数字。
let str = 'js62349216你知道吗555啦啦啦';
const reg = /\d+(?=啦)/;
console.log(reg.exec(str));
//反向断言:根据前面的内容判断后面的内容。
const reg1 = /(?<=吗)\/d+/;
console.log(reg1.exec(str));


//dotAll模式
//.表示除换行符以外的任意单个字符。


ES10

字符串

//trimStart()
//返回原字符串消除头部的空格(tab、换行)后的新字符串。
//trimEnd()
const s = ' abc ';
s.trim() // 'abc'
s.trimStart() // 'abc '
s.trimEnd() // ' abc'

函数

toString()

  • 以前toString()方法返回函数代码本身,但会省略注释和空格。现在会返回一模一样的原始代码。

try…catch

//以前明确要求`catch`命令后面必须跟参数,接受`try`代码块抛出的错误对象。
try{
    
	...
}catch(err){
    
	...
}
//现在允许`catch`语句省略参数。
try{
    
	...
}catch{
    
	...
}

数组

ES2019明确规定,Array.prototype.sort()的默认排序算法必须稳定。

//flat():将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。
[1, 2, [3, 4]].flat() // [1, 2, 3, 4]
//可以传入一个参数,表示要“拉平”的层数,默认为1。如果不管有多少层嵌套,都要转成一维数组,可以用`Infinity`关键字作为参数。
[1, 2, [3, [4, 5]]].flat(2) // [1, 2, 3, 4, 5]
[1, [2, [3]]].flat(Infinity) // [1, 2, 3]

//flatMap():先执行map(),再对返回值组成的数组执行flat()方法。返回一个新数组,不改变原数组。
//只能展开一层数组。
[2, 3, 4].flatMap(x => [x, x * 2]);
//[[2, 4], [3, 6], [4, 8]].flat()
//[2, 4, 3, 6, 4, 8]

对象

//Object.fromEntries():将一个键值对数组转为对象。
Object.fromEntries([
  ['foo', 'bar'],
  ['baz', 42]
])
// { foo: "bar", baz: 42 }


ES11

运算符

链运算符?.

//左侧的对象是否为null或undefined。如果是,则返回undefined;如果不是,则往下运算。
const firstName = message?.body?.user?.firstName || 'default';

a?.b //a == null ? undefined : a.b
a?.[x] //a == null ? undefined : a[x]
a?.b() //a == null ? undefined : a.b()
a?.() //a == null ? undefined : a()

Null判断运算符??

//左侧的值是否为null或undefined。如果是则返回右侧的值。
const animationDuration = response.settings?.animationDuration??300;
//先判断response.setting是不是null或undefined,是则返回undefined;不是则判断response.setting.animationDuration是不是null或undefined,是则返回300。

数值

新数据类型BigInt

  • 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。
//BigInt类型的数据必须添加后缀n。
const a = 315264786478n;
//BigInt与普通整数是两种值,它们并不相等。
42n === 42 //false
//可以用typeof。
typeof 123n //'bigint'
//可以用负号,不能用正号。
-42n //正确
+42n //错误


//BigInt()
//将其他类型的值转为BigInt。

class

//私有属性#:无法在类外部读取。
class Person{
    
	name;
	#age;
	constructor(name, age){
    
		this.name = name;
		this.#age = age;
	}
	intro(){
    
		console.log(this.#age);
	}
}

Promise

//allSettled():返回一个Promise对象。状态永远是resolved;值是传入的Promise数组返回的结果组成的数组。
console.log(Promise.allSettled([p1, p2]));
//all():返回一个Promise对象。传入的Promise数组都成功,状态是resolved值是传入的Promise数组返回的结果组成的数组;否则状态是rejected,值是失败的Promise返回的值。
console.log(Promise.all([p1, p2]));

globalThis

始终指向全局对象(不论是浏览器还是node环境下)。

模块化

//动态import
btn.onclick = function(){
    
	import('./hello.js').then(module=>{
    
		module.hello();
	});
}


ES12

运算符

逻辑赋值运算符

//或赋值运算符
x ||= y // x || (x = y)
user.id = user.id || 1;
user.id ||= 1;

//与赋值运算符
x &&= y // x && (x = y)

//Null赋值运算符
x ??= y // x ?? (x = y)

字符串

//replaceAll()
'aabbcc'.replace('b', '_') // 'aa_bcc'
'aabbcc'.replaceAll('b', '_') // 'aa__cc'
//第一个参数,如果正则表达式是一个不带g修饰符的正则表达式,会报错。
'aabbcc'.replaceAll(/b/, '_') // error
//第二个参数,可以是以下特殊字符串。
//$&表示匹配字符串
'abbc'.replaceAll('b', '$&') // $&指`b`本身,结果是'abbc'
//$`表示匹配结果前面的文本
'abbc'.replaceAll('b', '$`') // 对于第一个b,$`指`a`;对于第二个b,$`指的是`ab`;结果是'aaabc'
//$'表示匹配结果后面的文本
'abbc'.replaceAll('b', `$'`) // 对于第一个b,$'指的是`bc`;对于第二个b,$'指的是`c`;结果是'abccc'
//$n表示匹配成功的第n组内容(第一个参数必须是正则表达式)
'abbc'.replaceAll(/(ab)(bc)/g, '$2$1') // $1表示正则表达式的第一组匹配(每对括号是一个分组),指的是`ab`;$2表示正则表达式的第二组匹配,指的是`bc`;结果是'bcab'
//$$表示$
'abbc'.replaceAll('b', '$$') // 'a$$c'

数值

//数值分隔符
//不能放在数值的最前面或最后面。
//不能两个或两个以上的分隔符连在一起。
let num = 1_000_000_000;
//没有指定间隔的位数。
123_000 === 12_300 //true
//小数和科学计数法也可以使用。
//小数点的前后不能有分隔符。
//科学计数法里面,表示指数的e或E前后不能有分隔符。
0.000_001
1e10_000
//Number()、parseInt()、parseFloat()不支持数值分隔符。

WeakRef

用于创建对象的弱引用(弱引用实例不会妨碍原始对象被GC清除)。

let target = {
    };
let wr = new WeakRef(target);
//deref():如果原始对象存在,返回原始对象;如果原始对象不存在,则返回undefined。
let obj = wr.deref();
if(obj){
    
	...
}
原网站

版权声明
本文为[Yokirrr_]所创,转载请带上原文链接,感谢
https://blog.csdn.net/Youkirrr_/article/details/123158404