ES6++


  1. 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

学习网站https://wangdoc.com/

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",
  1. var、let、const 之间的区别?
  • 作用域
  • 重复声明
  • 是否会挂载到 window
  • 定义前访问(暂时性死区 TDZ)
  • 语义
  1. 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
  1. 箭头函数和普通的函数表达式有什么区别?
  • this指向
  • arugments
  • 不能使用new
function m() {
  var m2 = () => {
    console.log(arguments.length); //箭头函数没有arguments  5
  };

  m2(1, 2, 3);
}
m(1, 2, 3, 4, 5);
  1. 下面的输出结果是多少
const promise = new Promise((resolve, reject) => {
  //立即执行
  console.log(1);
  resolve();
  console.log(2);
});

promise.then(() => {
  //微队列
  console.log(3);
});

console.log(4); //1243
  1. 下面 Set 结构,打印出的 size 值是多少
let s = new Set();
s.add([1]);
s.add([1]); //字面量   这是两个数组
console.log(s.size);
  1. 下面的代码输出结果是
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);
  1. 下面代码的运行结果是
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);
  });
  1. 下面的代码输出结果是多少
Promise.resolve(2)
  .then((res) => {
    console.log(res);
    return 2;
  }) //返回一个新Promsie,状态为成功
  .catch((err) => {
    return 3;
  })
  .then((res) => {
    console.log(res); //2
  });
  1. 下面的代码输出结果是多少
Promise.resolve()
  .then(() => {
    return new Error("error!!!"); //这里是return 不是throw。没报错,只是返回了一个错误对象
  })
  .then((res) => {
    console.log("then: ", res);
  })
  .catch((err) => {
    console.log("catch: ", err);
  });
  1. 下面的代码输出结果是多少
Promise.resolve(1) // promise  fullfilled   1
  .then(2) //如果then里传递的不是函数,就当没执行就行
  .then(Promise.resolve(3)) //传递的是对象,then必须传函数,也是无效
  .then(console.log); //函数  console.log(1)

文章作者: Sunny
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Sunny !
  目录