1.async await
//promise
// await 异步没有依存关系 一般就异步并行
async function f1(){
return await Promise.all([
new Promise((resolve,reject)=>{
setTimeout(() => {
resolve(11);
}, 1000);
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(22);
}, 2000);
})
])
}
f1().then((data)=>{
console.log(data); //[11,22]
})
1)常见书写以及async await注意事项
- await 命令后面的Promise对象,运行结果可能是 rejected,此时等同于 async 函数返回的 Promise 对象被reject。因此需要加上错误处理,可以给每个 await 后的 Promise 增加 catch 方法;也可以将 await 的代码放在 try...catch 中。
- 多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
- await命令只能用在async函数之中,如果用在普通函数,会报错。
- async 函数可以保留运行堆栈。
function b(){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(22);
}, 4000);
});
};
function c(){
return new Promise((resolve, reject) => {
throw new Error('error0')
});
}
const m=async ()=>{
await b();
c()
}
m(); //(node:7016) UnhandledPromiseRejectionWarning: Error: error0
2.如何实现 Promise.race?
- Promise.race返回的仍然是一个Promise. 它的状态与第一个完成的Promise的状态相同。它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个Promise是哪一种状态。
- 如果传入的参数是不可迭代的,那么将会抛出错误。
- 如果传的参数数组是空,那么返回的 promise 将永远等待。
- 如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则 Promise.race 将解析为迭代中找到的第一个值。
Promise.race2 = function (promises) {
//promises 必须是一个可遍历的数据结构,否则抛错
return new Promise((resolve, reject) => {
if (typeof promises[Symbol.iterator] !== 'function') {
//真实不是这个错误
Promise.reject('args is not iteratable!');
}
if (promises.length === 0) {
return;
} else {
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then((data) => {
resolve(data);
return;
}, (err) => {
reject(err);
return;
});
}
}
});
}
//一直在等待态
Promise.race2([]).then((data) => {
console.log('success ', data);
}, (err) => {
console.log('err ', err);
});
//抛错
Promise.race2().then((data) => {
console.log('success ', data);
}, (err) => {
console.log('err ', err);
});
Promise.race2([
new Promise((resolve, reject) => { setTimeout(() => { resolve(100) }, 1000) }),
new Promise((resolve, reject) => { setTimeout(() => { resolve(200) }, 200) }),
new Promise((resolve, reject) => { setTimeout(() => { reject(100) }, 100) })
]).then((data) => {
console.log(data);
}, (err) => {
console.log(err);
});
1)可遍历数据结构的有什么特点?
一个对象要具备可被for...of循环遍历的iterator接口,那么其[Symbol.iterator]属性必须是一个函数,在其部署遍历器生成方法(或者原型链上的对象具有该方法)
- PS: 遍历器对象根本特征就是具有next方法。每次调用next方法,都会返回一个代表当前成员的信息对象,具有value和done两个属性。
//如为对象添加Iterator 接口;
let obj = {
name: "Yvette",
age: 18,
job: 'engineer',
[Symbol.iterator]() {
const self = this;
const keys = Object.keys(self);
let index = 0;
return {
next() {
if (index < keys.length) {
return {
value: self[keys[index++]],
done: false
};
} else {
return { value: undefined, done: true };
}
}
};
}
};
for(let item of obj) {
console.log(item); //Yvette 18 engineer
}
返回遍历器对象,具备可被for...of循环遍历的iterator接口
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
- ES6 的数组、Set、Map 都部署了以下三个方法: entries() / keys() / values(),调用后都返回遍历器对象。
3.如何实现Promise.all()
- 如果传入的参数是一个空的可迭代对象,那么此promise对象回调完成(resolve),只有此情况,是同步执行的,其它都是异步返回的。
- 如果传入的参数不包含任何 promise,则返回一个异步完成. promises 中所有的promise都“完成”时或参数中不包含 promise 时回调完成。
- 如果参数中有一个promise失败,那么Promise.all返回的promise对象失败
- 在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个数组
Promise.all5 = function (promises) {
return new Promise((resolve, reject) => {
let index = 0;
let result = [];
if (promises.length === 0) {
resolve(result);
} else {
function processValue(i, data) {
result[i] = data;
if (++index === promises.length) {
resolve(result);
}
}
for (let i = 0; i < promises.length; i++) {
//promises[i] 可能是普通值
Promise.resolve(promises[i]).then((data) => {
processValue(i, data);
}, (err) => {
reject(err);
return;
});
}
}
});
}
Promise.all5([11,22]).then((data)=>{
console.log(data);
})
4.插入Number 实现a==1 && a==2 && a==3
// number
var name=Symbol();
var obj={
name:'AliceLee',
age:24,
[name]: 'AliceLee1',
}
// 法一
// 实现a==1 && a==2 && a==3
var a = {
i: 1,
toString: function () {
return this.i++;
}
}
console.log(a == 1 && a == 2 && a == 3);
//法二
let value = 1;
Object.defineProperty(window, 'a', {
get: function () {
return value++
}
})
console.log(a == 1 && a == 2 && a == 3);
//法三
var reg=/\d/g;
var a={
reg:/\d/g,
valueOf:function(){
return reg.exec(123)[0];
}
}
console.log(a == 1 && a == 2 && a == 3);
//法四
var a={
valueOf: (function () {
var i= 1;
return function(){
return i++;
}
})()
}
console.log(a == 1 && a == 2 && a == 3);
// parseInt('0111'); //111
// parseInt(0111); //八进制数 73
5. 插入Object.defineProperty与proxy
- Object.defineProperty
let arry = ['travel', 'reading'];
Object.defineProperty(arry, '0', {
get() {
console.log("读取成功");
return temp
},
set(value) {
console.log("设置成功");
temp = value;
}
});
arry[0] = 10; //触发设置成功
arry.push(10); //不能被劫持
- proxy
let hobbits = ['travel', 'reading'];
let p = new Proxy(hobbits, {
get(target, key) {
//if(key === 'length') return true; //如果是数组长度的变化,返回。
console.log('读取成功');
return Reflect.get(target, key);
},
set(target, key, value) {
//if(key === 'length') return true; //如果是数组长度的变化,返回。
console.log('设置成功');
return Reflect.set([target, key, value]);
}
});
p.splice(0, 1) //触发get和set,可以被劫持
p.push('photography'); //触发get和set
p.slice(1); //触发get;因为 slice 是不会修改原数组的
6.执行顺序
console.log('script start');
setTimeout(function () {
console.log('setTimeout---0');
}, 0);
setTimeout(function () {
console.log('setTimeout---200');
setTimeout(function () {
console.log('inner-setTimeout---0');
});
Promise.resolve().then(function () {
console.log('promise5');
});
}, 200);
Promise.resolve().then(function () {
console.log('promise1');
}).then(function () {
console.log('promise2');
});
Promise.resolve().then(function () {
console.log('promise3');
});
console.log('script end');
script start
script end
promise1
promise3
promise2
setTimeout---0
setTimeout---200
promise5
inner-setTimeout---0
7.this 的执行顺序
var number = 1;
var obj = {
'number': 4,
'db1': (function () {
this.number *= 2;
return function () {
this.number *= 2
}
})()
}
var db1 = obj.db1;
db1()
obj.db1()
console.log(number) //4
console.log(obj.number) //8
console.log(number + obj.number) //12
var number = 5;
var obj = {
number: 3,
fn: (function () {
var number;
this.number *= 2;
number = number * 2;
number = 3;
return function () {
var num = this.number;
this.number *= 2;
console.log(num);
number *= 3;
console.log(number);
}
})()
}
var myFun = obj.fn;
myFun.call(null);
obj.fn();
console.log(window.number);
10
9
3
27
20
8. 函数柯理化
function curry(fn, args = []) {
return function(){
let rest = [...args, ...arguments];
if (rest.length < fn.length) {
return curry.call(this,fn,rest);
}else{
return fn.apply(this,rest);
}
}
}
//test
function sum(a,b,c) {
return a+b+c;
}
let sumFn = curry(sum);
console.log(sumFn(1)(2)(3)); //6
console.log(sumFn(1)(2, 3)); //6
9.深拷贝 考虑循环引用的问题 用WeakMap()
function deepClone(obj,hash=new WeakMap()){
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Date) return new Date(obj);
if(hash.has(obj)){
return hash.get(obj);
}
var res=Array.isArray(obj)?[]:{};
hash.set(obj,res);
for(var key in obj){
if(obj.hasOwnProperty(key)){
res[key] = typeof obj[key] === 'object' ? deepClone(obj[key],hash) : obj[key];
}
}
return res;
};
var a=Symbol();
var obj = {
name: 'st',
age: 18,
hobbies: ['reading', 'photography'],
[a]:24,
b:function(){
return 0
}, //被忽略
time:new Date(),
reg:/\d/g, //{}
sex:undefined, //被忽略
// 原型链上的属性无法获取
}
obj.circle = obj;//Maximum call stack size exceeded 循环引用自身
var newObj = deepClone(obj);
obj.hobbies.push('st');
console.log(obj, newObj);
输出:
{ name: 'st',
age: 18,
hobbies: [ 'reading', 'photography' ],
b: [Function: b],
time: 2019-09-06T03:05:04.122Z,
reg: /\d/g,
sex: undefined,
circle: [Circular] }
1)浅拷贝
var newObj = Object.assign({}, obj); //浅拷贝
var obj1 = { ...obj }; //浅拷贝
for(var key in obj){} //浅拷贝
Array.prototype.slice() //浅拷贝
Array.prototype.concat() //浅拷贝
10.函数柯理化
// 通用柯理化
const currying=(fn,...args)=>{
return args.length < fn.length ? (...arguments) => currying(fn, ...args, ...arguments) : fn(...args);
};
function sumFn(a, b, c) {
return a + b + c;
};
var sum = currying(sumFn);
console.log(sum(2,3,5));
console.log(sum(2,3)(5));
console.log(sum(2)(3)(5));