- Math.pow —— ES2015
console.log(Math.pow(2, 3));
console.log(2 ** 3);
console.log(2 * 2 * 2);
2. Object.entries Object.values —— ES2015
var obj = {
a: 1,
b: 2,
};
Object.keys(obj); // ["a", "b"]
Object.values(obj); // [1, 2]
Object.entries(obj); // [["a", 1], ["b", 2]]
3. ES2019 新增数组 API
Array.prototype.flat
该函数可以将某个数组拍扁
const arr = [1, [2, 3, [4, 5, [6, 7]]]];
const arr1 = arr.flat(); // [1, 2, 3, [4, 5, [6, 7]]]
const arr2 = arr.flat(2); // [1, 2, 3, 4, 5, [6, 7]]
const arr3 = arr.flat(Infinity); // [1, 2, 3, 4, 5, 6, 7]
Array.prototype.flatMap
const arr = ...;
arr.flatMap(fn);
//等效于
arr.map(fn).flat()
示例 1:利用 flatMap 在 map 期间去掉一些数据
const arr = [1, 2, 3, 4, 5];
/*
[
{number:1, doubleNumber: 2},
{number:3, doubleNumber: 6},
{number:5, doubleNumber: 10},
]
*/
写法 1
const arr = [1, 2, 3, 4, 5];
var newArr = [];
for (const item of arr) {
if (item % 2 !== 0) {
newArr.push({
number: item,
doubleNum: item * 2,
});
}
}
console.log(newArr);
写法 2:先筛选后映射
var result = arr
.filter((it) => it % 2 === 1)
.map((it) => ({ number: it, doubleNumber: it * 2 }));
console.log(result);
不建议的方法 3
var result = arr
.map((it) => (it % 2 === 1 ? { number: it, doubleNumber: it * 2 } : []))
.flat();
console.log(result);
//等价于
var result = arr.flatMap((it) =>
it % 2 === 1 ? { number: it, doubleNumber: it * 2 } : []
);
console.log(result);
示例 2:利用 flatMap 分割一个单词数组
const arr = [
"Yestoday is a History",
"Tomorrow is a Mystery",
"Today is a Gift",
"That's why we call it the Present",
];
/*
["Yestoday", "is", "a", "History", "Tomorrow", ...]
*/
写法 1:
const arr = [
"Yestoday is a History",
"Tomorrow is a Mystery",
"Today is a Gift",
"That's why we call it the Present",
];
var result = arr.map((it) => it.split(" "));
//console.log(result);
var result = arr.map((it) => it.split(" ")).flat();
console.log(result);
// 等价于
var result = arr.flatMap((it) => it.split(""));
Object.fromEntries
Object.fromEntries(iterable);
它接收一个可迭代对象,该对象每次迭代必须返回一个包含两项数据的数组(参考 map),该函数会将第一项作为对象的属性名,第二项作为对象的属性值
const arr = [
["a", 1],
["b", 2],
];
Object.fromEntries(arr); // {a:1, b:2}
示例:
function localMoneyFomat(obj) {
//略
}
var obj = {
name: "xxx",
balance: 199.8, //余额
taken: 3000, //消费
};
localMoneyFomat(obj); // {name:"xxx", balance:"¥199.8", taken: "¥3000"}
答案
function localMoneyFomat(obj) {
var result = Object.entries(obj); // 变成数组
console.log(result);
var result = Object.entries(obj).map((it) =>
typeof it[1] === "number" ? [it[0], `¥${it[1]}`] : it
);
console.log(result);
}
var obj = {
name: "xxx",
balance: 199.8, //余额
taken: 3000, //消费
};
localMoneyFomat(obj); // {name:"xxx", balance:"¥199.8", taken: "¥3000"}
解构的方法:
function localMoneyFomat(obj) {
var result = Object.entries(obj).map(([k, v]) =>
typeof v === "number" ? [k, `¥${v}`] : [k, v]
);
return Object.fromEntries(result);
console.log(result);
}
String.prototype.trimStart
同 trimLeft,去掉字符串左边的空格
var str = " abc ";
console.log(str.length);
var str1 = str.trimStart();
console.log(str1);
String.prototype.trimEnd
同 trimRight,去掉字符串右边的空格
ES2020
以前的问题
var person = {
info: {
addr: {
province: "黑龙江",
city: "哈尔滨",
},
},
};
// 如果这是对象是ajax远程获取的,不知道里面是不是空
console.log(person.info.addr.city);
// person可能是NUll,person.info可能是null,person.info.addr可能是null
以前的解决方案:
console.log(person && person.info && person.addr && person.info.addr.city);
可选链操作符(Optional Chaining)
person?.addr?.province;
通过可选链
console.log(person?.info?.addr?.city);
空位合并操作符(Nullish coalescing Operator)
a ?? b;
// 等同于
a === undefined || a === null ? b : a; // a没有东西就取b,有东西就取a
应用
function method(option) {
var a = option.a || 3;
console.log(a);
}
method({
a: 1,
// a:null/undefined/0
b: 2,
c: 3,
});
此方法有 bug,当 a:0
function isDef(vaule) {
return value === undefined || value === null;
}
function method(option) {
var a = isDef(option.a) || 3;
console.log(a);
}
优化
function method(option) {
var a = option.a ?? 3;
console.log(a);
}
method({
a: 1,
// a:null/undefined/0
b: 2,
c: 3,
});
Promise.allSettled
Promise.allSettled([
Promise.resolve(1),
Promise.resolve(2),
Promise.reject("error"),
]).then((result) => {
/*
result: [
{status: "fulfilled", value: 1},
{status: "fulfilled", value: 2},
{status: "rejected", reason: "error"}
]
*/
});
以前:
Promise.all(Promise 数组)
var getTestPromise = (
isSuccess,
dataOrErr // 返回Promise,是成功还是失败;成功后数据是什么,失败后错误是什么
) =>
new Promise((resolve, reject) => {
setTimeout(() => {
if (isSuccess) {
resolve(dataOrErr);
} else {
reject(dataOrErr);
}
}, Math.random() * 1000);
});
var proms = [
// Promise数组
getTestPromise(true, 1),
getTestPromise(true, 2),
getTestPromise(false, 3),
getTestPromise(false, 4),
];
Promise.all(proms)
.then((datas) => {
console.log("Promise.all resolved", datas); // 必须全部成功
})
.catch((reason) => {
console.log("Promise.all rejected", reason); //只要有一个错误,就不用等了,判定为失败
});
Promise.race(Promise 数组)
Promise.race(proms) // 看谁先到终点:已决
.then((data) => {
console.log("Promise.all resolved", data);
})
.catch((reason) => {
console.log("Promise.all rejected", reason);
});
新规范方法 Promise.allSettled 等待全部已决,不存在失败
Promise.allSettled(proms)
.then((result) => {
console.log("Promise.all resolved", result);
})
.catch((reason) => {
console.log("Promise.all rejected", reason);
});
应用
var proms = [
// Promise数组
getTestPromise(true, 1),
getTestPromise(false, new Error("failed")),
getTestPromise(true, 3),
getTestPromise(false, new Error("failed")),
];
Promise.allSettled(proms).then((result) => {
var sum = result.reduce((a, b) => a + (b.value ?? 0), 0); // 这个0表示第一次的值
console.log(result);
console.log(sum);
});
- Dynamic Import
- BigInt新的数据类型(值类型,基本类型)
复习数据类型 typeof 返回:String Number undefined object Boolean function symbol
// 第8种类型
const a = Number.MAX_SAFE_INTEGER * Number.MAX_SAFE_INTEGER;
// Number.MAX_SAFE_INTEGER最大安全整数
// => 8.112963841460666e+31精读丢失了
const b = BigInt(Number.MAX_SAFE_INTEGER) * BigInt(Number.MAX_SAFE_INTEGER);
// => 81129638414606663681390495662081n
typeof b; // => bigint
a + b; // error: Cannot mix BigInt and other types
- globalThis永远指向全局对象
4. Promise/A+
Promise 的规范。Promise 构造函数满足了 PromiseA+规范。通过 es6 的 Promise 构造函数创建的对象满足 PromiseA+规范
只有 html css 属于 w3c
ES2021
- String.prototype.replaceAll
替换字符串中所有的匹配字符
- Promise.any
ES2021 将引入 Promise.any() 方法,一旦该方法从 promise 列表或数组中命中首个 resolve(成功) 的 promise ,就会短路并返回一个值。如果所有 promise 都被 reject ,该方法则将抛出一个聚合的错误信息 (在 Example 1b 里有所展示)。
其区别于 Promise.race() 之处在于,后者在某个 promise 率先 resolve 或 reject 后都会短路。
示例
var proms = [
getTestPromise(true, 1),
getTestPromise(false, new Error("failed")),
getTestPromise(true, 3),
getTestPromise(false, new Error("failed")),
];
Promise.any(proms)
.then((datas) => {
console.log("Promise.all resolved", datas);
})
.catch((reason) => {
console.log("Promise.all rejected", reason);
});
一个成功,就返回成功的那个 data
全部失败,就会返回一个对象,对象里面有一个数组,记录错误
上层工具:bit.dev 研究一下
字节笔试
实现一个函数 toJSON,将传入的数据转换为 JSON 格式的字符串
不可使用 JS 中的 JSON 对象 JSON.stringify()
/**
* 将传入的数据转换为 JSON 格式的字符串
* @param {any} data 要转换的数据
* @returns {String} 返回转换后的 JSON 字符串
*/
function toJSON(data) {
// code here
}
// test
toJSON(""); // -> ""
toJSON("abc"); // -> "abc"
toJSON(123); // -> 123
toJSON({ a: 1, b: 2 }); // -> {"a":1, "b":2}
toJSON(["1", 3, { name: "monica", age: 18 }]); //-> ["1", 3, {"name":"monica", "age":18}]
var specialTypes = ["function", "symbol", "undefined"];
function isArrayItemToNull(item) {
//数组的元素是不是转换成null
const itemType = typeof item;
return (
specialTypes.includes(itemType) || (isNaN(item) && itemType === "number") //判断NaN
);
}
function isDropProp(data) {
return specialTypes.includes(typeof data);
}
function hanldeObject(data) {
// 是不是null
if (data === null) {
return "null";
}
data = data.valueOf();
if (typeof data !== "object") {
// 说明data已经是原始类型
return toJSON(data);
}
// 是数组的情况
if (Array.isArray(data)) {
return `[${data
.map((it) => (isArrayItemToNull(it) ? "null" : toJSON(it)))
.join(", ")}]`;
}
// 是普通对象的情况
const result = Object.entries(data)
.flatMap(([k, v]) => (isDropProp(v) ? [] : `"${k}": ${toJSON(v)}`))
.join(",");
return `{${result}}`;
}
/**
* 将传入的数据转换为 JSON 格式的字符串
* @param {any} data 要转换的数据
* @returns {String|undefined} 返回转换后的 JSON 字符串
*/
function toJSON(data) {
// 给我一个什么类型的值 我应该返回一个什么样的字符串
const type = typeof data; // 拿到data的数据类型
switch (type) {
case "boolean":
case "number":
return "" + data;
case "bigint":
throw new TypeError("Do not know how to serialize a BigInt");
case "string":
return `"${data}"`;
case "function":
case "undefined":
case "symbol":
return;
case "object":
return hanldeObject(data);
}
}
// test
console.log(
toJSON({
a: undefined,
b: Symbol("1"),
d: () => {},
c: "abc",
e: {
a: 1,
b: [{ name: "monica", age: 18 }, 44, {}],
},
})
);
// console.log(toJSON(""));
// toJSON(""); // -> ""
// toJSON("abc"); // -> "abc"
// toJSON(123); // -> 123
// toJSON({ a: 1, b: 2 }); // -> {"a":1, "b":2}
// toJSON(["1", 3, { name: "monica", age: 18 }]); //-> ["1", 3, {"name":"monica",
- var、let、const 之间的区别?
- 作用域
- 重复声明
- 是否会挂载到 window
- 定义前访问(暂时性死区 TDZ)
- 语义
- ES6 中的
class
和传统的构造函数有什么区别?
- 是否必须使用
new
调用 - 严格模式
- 原型上的方法是否可被枚举
- 原型上的方法是否能使用
new
调用
class A {
method1() {}
method2() {} //不可枚举
}
// new A.prototype.method1();不能new
function B() {}
B.prototype.m1 = function () {}; //可枚举
B.prototype.m2 = function () {};
// console.log(Object.keys(B.prototype));
new B.prototype.m1(); //可以new
- 箭头函数和普通的函数表达式有什么区别?
this
指向arugments
- 不能使用
new
function m() {
var m2 = () => {
console.log(arguments.length); //箭头函数没有arguments 5
};
m2(1, 2, 3);
}
m(1, 2, 3, 4, 5);
- 下面的输出结果是多少
const promise = new Promise((resolve, reject) => {
//立即执行
console.log(1);
resolve();
console.log(2);
});
promise.then(() => {
//微队列
console.log(3);
});
console.log(4); //1243
- 下面 Set 结构,打印出的 size 值是多少
let s = new Set();
s.add([1]);
s.add([1]); //字面量 这是两个数组
console.log(s.size);
- 下面的代码输出结果是
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 1000);
});
const promise2 = promise1.then(() => {
//等着1
throw new Error("error");
});
console.log("promise1", promise1);
console.log("promise2", promise2);
setTimeout(() => {
console.log("promise1", promise1);
console.log("promise2", promise2);
}, 2000);
变式
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 1000);
});
const promise2 = promise1.catch(() => {
//2取决于1的话,看处理没处理这个状态,处理了,看他处理过程,没有处理就漏下来
throw new Error("error"); //此处成功了没有处理,状态和1一样。这里只处理了错误
});
console.log("promise1", promise1);
console.log("promise2", promise2);
setTimeout(() => {
console.log("promise1", promise1);
console.log("promise2", promise2); //fulfilled
}, 2000);
变式
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(); //promise是rejected
}, 1000);
});
const promise2 = promise1
.catch(() => {
//处理了错误,处理的过程没报错
return 2;
})
.then(() => {
//此处要执行
});
console.log("promise1", promise1);
console.log("promise2", promise2);
setTimeout(() => {
console.log("promise1", promise1); // rejected
console.log("promise2", promise2); // fulfiled
}, 2000);
变式
const promise1 = new Promise((resolve, reject) => {
// 这里要是报错,发生在同步代码里面,返回rejected。
setTimeout(() => {
throw 1; //但是此处跑错是在异步代码里面。执行的此处的时候,已经没有proimise环境了
}, 1000);
});
const promise2 = promise1.catch(() => {
return 2;
});
console.log("promise1", promise1);
console.log("promise2", promise2);
setTimeout(() => {
console.log("promise1", promise1); // pending
console.log("promise2", promise2); // pending
}, 2000);
- 下面代码的运行结果是
const promise = new Promise((resolve, reject) => {
resolve("success1");
reject("error");
resolve("success2");
});
promise
.then((res) => {
console.log("then: ", res);
})
.catch((err) => {
console.log("catch: ", err);
});
- 下面的代码输出结果是多少
Promise.resolve(2)
.then((res) => {
console.log(res);
return 2;
}) //返回一个新Promsie,状态为成功
.catch((err) => {
return 3;
})
.then((res) => {
console.log(res); //2
});
- 下面的代码输出结果是多少
Promise.resolve()
.then(() => {
return new Error("error!!!"); //这里是return 不是throw。没报错,只是返回了一个错误对象
})
.then((res) => {
console.log("then: ", res);
})
.catch((err) => {
console.log("catch: ", err);
});
- 下面的代码输出结果是多少
Promise.resolve(1) // promise fullfilled 1
.then(2) //如果then里传递的不是函数,就当没执行就行
.then(Promise.resolve(3)) //传递的是对象,then必须传函数,也是无效
.then(console.log); //函数 console.log(1)