JS学习5
let/const
let
用于声明块级作用域的变量,具有暂时性死区(声明前使用会报错)的约束。
const
只包含声明和初始化两个操作。
对于for循环,js每执行一次循环都会创建一个块作用域。
解构赋值
// 常见操作
let a = 1, b=2;
// 使用解构赋值来交换变量值
[a, b] = [b, a]
扩展运算符
...
符号常用于拷贝原始对象,注意,该运算符只进行一层拷贝(浅拷贝)。
let obj = {
name: "132",
address: {
city: "cs",
}
}
let newObj = {...obj};
newObj.address.city = "wh";
console.log(obj.address.city); // wh
rest
arguments
可以获取调用者传入的所有参数,但是得到的是一个类数组。
// 将类数组对象转换为数组对象
Array.prototype.slice.apply(arguments);
...rest
参数用于接收没有形参表示的实参(多余的传入值),并直接转化为数组对象。
function restFunc(a,b, ...others){
console.log(a); // 12
console.log(b); // 234
console.log(others); // [12, 1]
}
restFunc(12, 234, 12,1);
Symbol
作用:表示独一无二的值,使用 对象 实现唯一性。
实现参考网站
https://github.com/mqyqingfeng/Blog/issues/87
Map 和Set
Map
对于Map来说, key
可以为任意值, 包括对象和任意基本类型。(包括null
和undefined
)
关键点:
- 遍历Map得到的是一个有序的序列,顺序为插入顺序。
- 通过拉链法来解决哈希冲突。
WeakSet/Map
- 集合中的值只能为对象。值得注意的是,如果以数组传入该结构,最终存储的为数组内的元素。(对于
Map
,接收对象为键名(null、undefined
除外)) WeakSet/Map
对成员/键名的引用为弱引用,因此,在某个成员/键名只被WeakSet/Map
引用后,垃圾回收机制会对该成员/键名进行回收。- 由于
WeakSet/Map
中的成员随时可能被垃圾回收掉,因此该结构无法迭代。 WeakSet/Map
没有size
属性。- 设计目的:防止内存泄露
let set = new WeakSet();
let obj = {};
set.add(obj);
obj = null;
console.log(set.has(obj)); // false
let map = new WeakMap();
let obj = {};
map.set(obj, 123);
// key为弱引用
obj = null;
console.log(map.get(obj)) // undefined
let key = {};
let val = {test:1};
map.set(key ,val);
// value 为正常引用
val = null;
console.log(map.get(key)) // {test:1}
WeakMap 的应用:部署私有属性,当实例被删除时,私有属性也会被自动回收,降低内存泄露的风险。(来源:阮一峰的教程)
const _counter = new WeakMap();
const _option = new WeakMap();
class Count {
constructor(counter, option) {
// 将实例作为key,私有属性作为value
_counter.set(this, counter);
_option.set(this, option);
}
dec() {
let counter = _counter.get(this);
if (counter < 1) {
return;
}
counter--;
_counter.set(this, counter);
// 当计数器为0时,停止并调用函数
if (counter === 0) {
_option.get(this)();
}
}
}
const count = new Count(2, () => {console.log("finished")});
count.dec();
count.dec();
Promise
定义:一个容器,保存了某个未来才会结束的事件的结果(异步执行),入参为 resolve
,表示将状态切换为成功,并将结果作为参数传出;rejected
,表示状态切换为失败,传出给定错误。
状态定义:pending、fulfilled、rejected
。
目的:
- 解决异步请求的嵌套地狱
- 通过
Promise.all
合并多个任务的结果。
Promise A+
一个简单的Promise实现(利用了发布订阅设计思想):
class PromiseSelf{
static Pending = "PENDING";
static Fulfilled = "FULFILLED";
static Reject = "REJECT";
constructor(executor){
this.status = PromiseSelf.Pending;
this.value = undefined;
this.successCall = [];
this.failCall = [];
const resolve = (value) =>{
this.status = PromiseSelf.Fulfilled;
this.value = value;
this.successCall.forEach(fn => fn(value));
}
const reject = (error) =>{
this.status = PromiseSelf.reject;
this.value = error;
this.failCall.forEach(fn => fn(value));
}
try {
executor(resolve, reject);
} catch (error) {
console.log(error);
}
}
then(onFulfilled, onReject){
if(this.status === PromiseSelf.Fulfilled){
// 执行成功则调用
onFulfilled(this.value);
}
if(this.status === PromiseSelf.reject){
// 执行失败调用
onReject(this.value);
}else{
// 否则加入
this.successCall.push(onFulfilled);
this.failCall.push(onReject);
}
// 返回当前对象,作为链式调用
return this;
}
}
new PromiseSelf((resolve, reject) =>{
resolve("success");
//reject("error");
}).then(x =>{
console.log(x);
}, e=>{
console.log(e); // error
})
迭代器和生成器
迭代器
// 自定义迭代器 es5
function iteratorSelf(items){
let i =0;
// 返回一个函数对象
return{
next: function(){
let done = (i < items.length);
let value = done ? items[i++]:undefined;
return{
value: value,
done: done,
}
}
};
}
let arr = iteratorSelf([1,2,3,4]);
let cur = arr.next();
while(cur.done){
console.log(cur.value);
cur = arr.next();
}
生成器
// 生成器 es6
function *generatorSelf(items){
for(let i=0;i<items.length;i++){
yield items[i];
}
}
let gen = generatorSelf([1,2,3,4]);
for(let val of gen){
console.log(val);
}
async/await
作用:
async
用于异步函数执行,返回Promise对象。await
用于等待异步执行结果,可以理解为将异步执行转化为同步。
实现:利用了Generator的思想来实现,关键点在于对自动执行next()方法的处理。
// 通过生成器来实现 async/await的效果
function *testGen(){
const data = yield getData();
console.log("data", data);
const data2 = yield getData();
console.log("data2", data2);
return 'success';
}
function asyncToGenerator(gen){
return function(){
// 生成生成器的实例
const g = gen.apply(this, arguments);
return new Promise((resolve, reject) =>{
function step(key, arg){
let res = null;
try {
// 将方法当成属性使用这点学到了
res = g[key](arg);
} catch (error) {
return reject(error);
}
// 得到的是一个结构体
// console.log(res);
const {value, done} = res;
if(done){
return resolve(value);
}else{
return Promise.resolve(value).then(
// 只要不是最后一个,就会一直递归解开Promise
val => step('next', val),
// 否则报错
err => step('throw', err));
}
}
step('next');
})
}
}
asyncToGenerator(testGen)();
https://juejin.cn/post/6844904102053281806