当前位置: 首页 > 工具软件 > esnext > 使用案例 >

ESNEXT(ES6及以后)常用API解析

洪德寿
2023-12-01

ES6及以后新增的常用API解析

注:例子建立在非严格模式下,新版chrome浏览器下

严格模式下:window为undefined

node下:window为global

let和const和var的区别

for(var i = 0 ; i < 3 ; i++){
	setTimeout(()=>{
        console.log(i);
    },0)
}

输出

3

3

3

为什么?

因为for循环是同步任务顺序执行,var定义是全局变量,setTimeout为宏任务,会放到下一轮任务队列里面,所以等到setTimeout输出的时候,i的值就就是已经经过for循环变成3了。

所以如何修改使其输出0,1,2

1.闭包

将通过闭包将变量i变成局部变量

for(var i = 0 ; i < 3 ; i++) {
	(function(i){
		setTimeout(()=>{
			console.log(i);
		},0)
	})(i);
}

2.let

for(let i = 0 ; i < 3 ; i++) {
	setTimeout(()=>{
        console.log(i);
    },0)
}

这里的i只在块级作用域下生效

//块级作用域
{
	setTimeout(()=>{
        console.log(i);
    },0)
}

const和let一样只在块级作用域下生效

但是不允许修改

var有变量提升的作用,let和const没有

console.log(a); //undefined
var a = '1';

console.log(b); //报错
let b = '2';

console.log(c); //报错
const c = '3';

变量提升等价

console.log(a);
var a = '1';

//等价于
var a;
console.log(a);
a = '1';

普通函数和箭头函数

1.箭头函数不能被用作构造函数,普通函数可以

2.箭头函数没有arguments,普通函数有

3.箭头函数都是匿名函数,普通函数可以是匿名函数,也可以不是匿名函数

4.普通函数和箭头函数的this指向有区别

具体看我之前写的《一文彻底搞懂普通函数和箭头函数this指向区别》

class

class Test {
	constructor(name) {
		this.name = name;
	}
	
	static getFormatName() {
		return `${this.name} - xixixi`
	}
	
	getName(){
		return `${this.name} - xixi`
	}
}

其中,静态方法的this指向Test类,普通方法的this指向实例化对象

模板字符串

const year = '2021';
const month = '10';
const day = '01';
let template = '${year}-${month}-${day}';
console.log(template); //2021-10-01

解构

1.数组解构

每一个解构属性与数组索引对齐

// 基础类型数组解构
let [a, b, c] = [1, 2, 3]
console.log(a, b, c) // 1, 2, 3
// 对象数组解构
let [a, b, c] = [{name: '1'}, {name: '2'}, {name: '3'}]
console.log(a, b, c) // {name: '1'}, {name: '2'}, {name: '3'}
// ...解构
let [head, ...tail] = [1, 2, 3, 4]
console.log(head, tail) // 1, [2, 3, 4]

2.对象解构

每一个解构属性与对象属性名称一致

// 对象属性解构
let { f1, f2 } = { f1: 'test1', f2: 'test2' }
console.log(f1, f2) // test1, test2
// 可以不按照顺序,这是数组解构和对象解构的区别之⼀
let { f2, f1 } = { f1: 'test1', f2: 'test2' }
console.log(f1, f2) // test1, test2
// 解构对象重命名
let { f1: rename, f2 } = { f1: 'test1', f2: 'test2' }
console.log(rename, f2) // test1, test2
// 嵌套解构
let { f1: {f11}} = { f1: { f11: 'test11', f12: 'test12' } }
console.log(f11) // test11

3.解构的原理是什么?

针对可迭代对象的Iterator接⼝,通过遍历器按顺序获取对应的值进⾏赋值.

3.1 那么 Iterator 是什么?

Iterator是一种接口,它能为各种不一样的数据提供统一的访问机制。换句话说,任何数据有Iterator

接口了,都可以通过遍历器进行遍历操作。就比如ES6中的for of就是遍历器,它就可以遍历包含

Iterator接口的数据。

3.2 Iterator有什么⽤?

为各种数据解构提供统⼀的访问接⼝

使得数据解构能按次序排列处理

可以使⽤ES6最新命令 for of进⾏遍历

function generateIterator(array) {
    let nextIndex = 0
    return {
        next: () => nextIndex < array.length ? {
            value: array[nextIndex++],
            done: false
        } : {
            value: undefined,
            done: true
        }
    };
}
const iterator = generateIterator([0, 1, 2])
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())

3.3 可迭代对象是什么?

可迭代对象是Iterator接⼝的实现。这是ECMAScript 2015的补充,它不是内置或语法,⽽仅

仅是协议。任何遵循该协议点对象都能成为可迭代对象。可迭代对象得有两个协议:可迭代协

议和迭代器协议。

可迭代协议:对象必须实现iterator⽅法。即对象或其原型链上必须有⼀个名叫

Symbol.iterator的属性。该属性的值为⽆参函数,函数返回迭代器协议。

迭代器协议:定义了标准的⽅式来产⽣⼀个有限或⽆限序列值。其要求必须实现⼀个next()⽅

法,该⽅法返回对象有done(boolean)和value属性。

3.4 手写一个可迭代对象

const obj = {
	count:0,
	[Symbol.iterator]: function() {
		return {
			next: () =>{
				this.count++;
				if(this.count >= 10){
					return {
						done:true,
						value:undefined
					}
				}else{
					return {
						done:false,
						value:this.count
					}
				}
			}
		}
	}
}

for(let item of obj){
	console.log(item);
}

//或者
const obj = {
    0: 'a',
    1: 'b',
    2: 'c',
    length:3,
    [Symbol.iterator]:Array.prototype[Symbol.iterator]
}

for(let item of obj){
    console.log(item);
}

遍历

1.for in

一般用于遍历对象属性

不建议遍历数组,因为for in会把原型链上的东西也遍历出来

没有break

2.for of

仅遍历当前对象

遍历可迭代对象,包括Array,Map,Set,String,arguments,NodeList等

可以与break,continue,return配合

Object

1.Object.keys

该方法返回一个给定对象的自身可枚举属性组成的数组

const obj = { a: 1, b: 2 };
const keys = Object.keys(obj); // [a, b]

手写实现一个函数模拟Object.keys?

function getObjectKeys(obj) {
	let result = [];
	for(const prop in obj){
		if(obj.has)
	}
}
let obj = { a: 1, b: 2 };
obj.__proto__.c = 3;
console.log(getObjectKeys(obj));

2.Object.values

该⽅法返回⼀个给定对象⾃身的所有可枚举属性值的数组

const obj = { a: 1, b: 2 };
const keys = Object.values(obj); // [1, 2]

3.Object.entries

该⽅法返回⼀个给定对象⾃身可枚举属性的键值对数组。

const obj = { a: 1, b: 2 };
const keys = Object.entries(obj); // [['a',1], ['b',2]]

4.Object.create()

以方法第一个参数作为原形对象,创建一个新对象

当传入第二个参数时

const b = Object.create(Person.prototype, {
	name: {
		value: 'coco',
		writable: true,
		configurable: true,
		enumerable: true,
	},
	sex: {
		enumerable: true,
		get: function () {
			return 'hello sex'
		},
		set: function (val) {
			console.log('set value:' + val)
		}
	}
})
console.log(b.name)
console.log(b.sex)

5.Object.assign()

浅拷贝,类似

function shallowClone(source) {
	const target = {};
	for (const i in source) {
		if (source.hasOwnProperty(i)) {
			target[i] = source[i];
		}
	}
	return target; 
}

Array

1.Array.flat

打平数组

flat() ⽅法会按照⼀个可指定的深度递归遍历数组,并将所有元素与遍历到的⼦数组中的元素

合并为⼀个新数组返回

const arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
const arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
const arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
//使⽤ Infinity,可展开任意深度的嵌套数组
const arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

第一个参数为深度,当传Infinity时,无论深度是多少都直接打平

手写一个Array.flat

function arrayFlat(array,depth){
	if(depth > 0){
		array = array.reduce((res,item)=>{
			if(!Array.isArray(item)){
				res.push(item)
			}else{
				res = res.concat(arrayFlat(item,depth-1));
			}
			return res;
		},[]).slice()
	}
	return array;
}

2.Array.includes

includes() ⽅法⽤来判断⼀个数组是否包含⼀个指定的值,根据情况,如果包含则返回 true,

否则返回false。

const array1 = [1, 2, 3];
console.log(array1.includes(2));//true

其实它有两个参数, 只不过我们平时只使⽤⼀个.

  • valueToFind

需要查找的元素值。

  • fromIndex 可选(不常用)

从fromIndex 索引处开始查找 valueToFind。如果为负值,则按升序从 array.length +

fromIndex 的索引开始搜 (即使从末尾开始往前跳 fromIndex 的绝对值个索引,然后往后搜

寻)。默认为 0。

3.Array.find

find() ⽅法返回数组中满⾜提供的测试函数的第⼀个元素的值。否则返回 undefined。

callback

在数组每⼀项上执⾏的函数,接收 3 个参数:

  • element

当前遍历到的元素。

  • index可选

当前遍历到的索引。

  • array可选

数组本身

const test = [
	{name: 'a', age: 11 },
	{name: 'b', age: 20 },
	{name: 'c', age: 50}
];
function callback(element,index,array) {
	return element.name === 'a'; 
}
console.log(test.find(callback));

4.Array.from

4.1 Array.from() ⽅法从⼀个类似数组或可迭代对象创建⼀个新的,浅拷⻉的数组实例。

arrayLike

想要转换成数组的伪数组对象或可迭代对象。

mapFn 可选

如果指定了该参数,新数组中的每个元素会执⾏该回调函数。

4.2 Array.from() 可以通过以下⽅式来创建数组对象:

伪数组对象(拥有⼀个 length 属性和若⼲索引属性的任意对象)

可迭代对象(可以获取对象中的元素,如 Map和 Set 等)

console.log(Array.from('foo'));//['foo']
console.log(Array.from([1, 2, 3], x => x + x));//[2,3,4]
const set = new Set(['foo', 'bar', 'baz', 'foo']);
Array.from(set);
// [ "foo", "bar", "baz" ]
const map = new Map([[1, 2], [2, 4], [4, 8]]);
Array.from(map);
// [[1, 2], [2, 4], [4, 8]]
const mapper = new Map([['1', 'a'], ['2', 'b']]);
Array.from(mapper.values());
// ['a', 'b'];
Array.from(mapper.keys());
// ['1', '2'];

5.Array.of

Array.of() ⽅法创建⼀个具有可变数量参数的新数组实例,⽽不考虑参数的数量或类型。

Array.of(7); // [7]
Array.of(1, 2, 3); // [1, 2, 3]
 类似资料: