ES6 和 ES5 的区别
创建 ECMAScript 的目的是标准化 JavaScript
| 比较项 | ES5 | ES6 |
|---|---|---|
| 定义 | ES5是ECMAScript(由ECMA International定义的商标脚本语言规范)的第五版。 | ES6是ECMAScript(ECMA International定义的商标脚本语言规范)的第六版。 |
| 发布 | 它于2009年推出 | 它于2015年推出。 |
| 数据类型 | ES5支持原始数据类型,包括字符串,数字,布尔值,空值和未定义(undefined)。 | 引入了一种新的原始数据类型symbol以支持唯一值。 |
| 定义变量 | 在ES5中,只能使用var关键字定义变量。 | 在ES6中,有两种定义let和const变量的新方法。 |
| 循环 | 在ES5中,使用了for循环来遍历元素。 | ES6引入了for?of循环的概念,以对可迭代对象的值执行迭代。 |
| 箭头函数 | 在ES5中,function和return关键字均用于定义函数。 | 箭头功能是ES6中引入的新功能,通过它不需要function关键字来定义函数。 |
ES6模块和CommonJS模块有什么区别
ES6
- 使用
import和export关键字来导入和导出模块. - 支持动态导入、可以异步加载模块
CommonJS
- 使用
require和module.exports或exports来导入和导出模块。 - 在设计时没有考虑异步加载的需求,通常在模块的顶部进行同步加载。
// ES6 模块
import { foo } from './module';
export const bar = 'bar';
// CommonJS 模块
const foo = require('./commonjs');
exports.bar = 'bar';
Number 处理
安全整数: -2^53到2^53之间(不含两个端点)
ES6 引入 Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER 这两个常量,用来表示这个范围的上下限。
Number.isSafeInteger()则是用来判断一个整数是否落在这个范围之内。
取整的方式
- Number.parseInt(string, radix)
第一个参数表示要转换的字符串,如果参数不是一个字符串,则将其转换为字符串。 第二个参数是基数即进制,默认为10。 缺点: 一是parseInt这个函数名,看起来就是将字符串转整数的,用在这里不是很适合。 另一个是转字符串有点多此一举,而且肯定会带来性能开销。 - Math.round是四舍五入的,Math.ceil是向上取整,Math.floor是向下取整。
- 利用 位或“|” 操作来取整的手段。(缺点:不能处理超过32位的数值取整,而JavaScript有效整数的范围是53位。)
获取小数部分
- 直接将原数值减去取整后的数值。
- 直接将原数对1取模,即可获得小数部分!
精度缺失问题
为什么会出现
十进制是给人看的,但在进行运算之前,必须先转换为计算机能处理的二进制(0舍1入)。最后,当运算完毕后,再将结果转换回十进制,继续给人看。精度就丢失于这两次转换的过程中。
解决方式
对结果进行处理
对莫个值乘 100 后除 100。
parseFloat((num.toFixed(小数点后面几个数字)); // toFixed() 精度参数须在 0 与20 之间
parseFloat((num.toPrecision((有几个有效数字))
对加减乘除的过程进行处理
正确做法是: 把小数转成整数后再运算
其它库
- Math.js
- big.js
数组的处理
... 运算符
- 展开参数。
- 复制数组、 合并数组、 都是浅拷贝。
- 将字符串转化为真正的数组。
Array.from(): 将类数组对象转换为真正的数组
类数组对象它具有 length 属性、 所以任何有length属性的对象,都可以通过Array.from()方法转为数组。
它的第二个参数可以接收一个函数、 作用类似于数组的 map() 方法。若 map() 函数内部用到了 this 关键字、那么 Array.from() 可传入第三个参数、 用来绑定 this。
Array.of(): 将一组值转化为数组
若没有参数、就返回一个空数组。
fill(填充的成员,起始位置,结束位置)
使用给定的值、填充一个数组
flat(拉平的层数) 将嵌套的数组拉成一维数组 、参数默认为 1、 不改变原数组
特性:
- 如果不管有多少层嵌套,都要转成一维数组,可以用 Infinity 关键字作为参数。如
flat(Infinity) - 如果原数组有空位,flat()方法会跳过空位。
与之类似的还有 flatMap((当前数组的成员, 当前数组的成员的位置, 原数组) => {})
查找类
find((当前值, 当前位置, 原数组) => {})
从前往后: 找到第一个符合条件的成员、并返回它。若没有找到就返回 undefined。
filter((当前值, 当前位置, 原数组) => {})
从前往后:找到符合条件的成员、并以数组的形式返回它们。若没有找到就返回空数组 [ ]。
findIndex((当前值, 当前位置, 原数组) => {})
从前往后:找到第一个符合条件的成员、并返回它的下标。 若没有找到、则返回 -1。
它可以借助 Object.is() 找到 NaN、 它内部是用严等于号进行判断、容易误判。
indexOf(莫个元素)
从前往后:查找数组中的莫个元素、如果找到则返回它的下标。 如果没有找到则返回-1。
lastIndexOf(莫个元素)
从后往前:查找数组中的莫个元素、如果找到则返回它的下标。 如果没有找到则返回-1。
findLast() 和 findLastIndex() 和 find()和findIndex() 类似、只是查找的方向不同
includes(查找的成员,开始查找的位置)
数组中是否包含给定的值、存在则、返回 true 、否则、返回 false。
另外:
- Map 结构的has方法,是用来查找键名的
- Set 结构的has方法,是用来查找值的
队列操作类
改变原数组
arr.push()
从后面添加元素、 返回值是添加完之后的数组长度
arr.pop()
删除最后一位删除元素、 返回的是被删除的元素
arr.shift()
在数组的第一位删除元素、 返回的是被删除的元素
arr.unshift()
在数组前面添加元素、返回的是添加完之后的数组长度
arr.splice(index, n)
从 index 下标开始、删除 n个、 返回的是被删除的元素
不改变原数组
arr.slice(start, end)
从 start 位置开始、到 end (不包括)截取
arr.concat([])
其它类
arr.split()
将字符串转化为数组
arr.every((当前值, 当前位置, 原数组) => {})
依据判断条件、判断数组的元素是否全部满足、 若满足则返回 true 、否则 flase。
arr.some((当前值, 当前位置, 原数组) => {})
依据判断条件、判断数组的元素是否有一个满足、 若满足则返回 true 、否则 flase。
arr.sort()
Arr.sort(function(a, b) {
if (a > b) {
return 1 //返回正数 ,b排列在a之前
} else {
return -1 //返回负数 ,a排列在b之前
}
})
当callback的返回值是正数时、那么 b 会被排列到 a 之前;
当callback的返回值是负数时、那么 a 会被排列到 b 之前;
当callback的返回值是为 0 时、那么 a 与 b的位置保持不变;
字符串的处理
模板字符串
- 所有空格和换行都会保留。
- 可放入任何 JavaScript 表达式。
- 可调用函数。
- 只要不是字符串、会默认调用对象的 toString方法、将其转化为字符串。
- 可以嵌套。
string.includes(字符串, 开始搜索的位置)
返回布尔值,表示是否找到了参数字符串。
string.startsWith(字符串, 开始搜索的位置)
返回布尔值,表示参数字符串是否在原字符串的头部。
string.endsWith(字符串, 从第n个位置直到字符串结束)
返回布尔值,表示参数字符串是否在原字符串的尾部。
string.trim()
删除头尾空格。返回一个新的字符串不改变原字符串。
string.trimStart()
删除头部空格。返回一个新的字符串不改变原字符串。
string.trimEnd()
删除尾部空格。返回一个新的字符串不改变原字符串。
string.replace(字符串)
替换掉第一个匹配的字符。 返回一个新的字符串不改变原字符串。
string.replaceAll(匹配模式, 函数或者字符串)
替换所有匹配的字符。 返回一个新的字符串不改变原字符串。
匹配模式: 可以是一个字符串,也可以是一个全局的正则表达式(带有g修饰符)。
string.at(一个整数)
返回参数指定位置的字符,支持负索引(即倒数的位置)。
此方法数组也可用。
对象的处理
简写方式
const baz = {
foo,
fn(x,y) {
return {x, y}
},
// 取值函数
get foo() {},
// 存值函数
set foo(x) {},
};
baz['f'+ 'oo']
等同于
const baz = {
foo: foo,
fn: function() {
return {x: x, y: y}
}
};
baz.foo
解释: [ ] 内部可以写表达式、不止属性名可以写、方法名也可以写。
super 关键字
它指向对象的原型对象。注意,super关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。(这里只做了解、应对面试)
Object.is(值1,值2)
它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
== 和 === 的区别
==
- 相等运算符
- 自动转换数据类型来比较两个操作数是否相等
===
- 在比较之前,值不会隐式转换为其他值。
- 如果变量值的类型不同,则这些值被视为不相等。
- 如果变量具有相同的类型、不是数字并且具有相同的值,则它们被视为相等。
- NAN 不等于本身
null、underfined、void 0
undefined值是派生自null值的。null作为空对象指针。undefined表示未定义,它的类型只有一个就是undefined。
Object.assign(目标对象,源对象1...)
用于对象的合并,将源对象的所有可枚举属性,复制到目标对象。
注意
- 如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
- 如果只有一个参数,
Object.assign()会直接返回该参数。 - 如果该参数不是对象,则会先转成对象,然后返回。
- 由于
undefined和null无法转成对象,所以如果它们作为参数,就会报错。
Object.hasOwn(所要判断的对象, 属性名)
可以判断是否为自身的属性。
Object.keys()
返回的是一个数组、参数成员是对象自身(不包含继承的)所有可遍历的键名 key。
### Object.values()
返回的是一个数组、参数成员是对象自身(不包含继承的)所有可遍历的键值 value。
Object.values会过滤属性名为 Symbol 值的属性。- 如果
Object.values方法的参数是一个字符串,会返回各个字符组成的一个数组。
Object.entries()
返回的是一个数组、参数成员是对象自身(不包含继承的)所有可遍历的键值对。除了返回值不一样,该方法的行为与Object.values基本一致。
用途
- 遍历对象的属性。
- 将对象转化为真正的 Map 结构。
运算符的扩展
链判断运算符 ?.
如果读取对象内部的某个属性,往往需要判断一下,属性的上层对象是否存在。
// 错误的写法
const firstName = message.body.user.firstName || 'default';
// 正确的写法
const firstName = (message
&& message.body
&& message.body.user
&& message.body.user.firstName) || 'default';
// 由于层层判断过于麻烦、 所以就有了以下写法
const firstName = message?.body?.user?.firstName || 'default';
上面代码使用了`?.`运算符,直接在链式调用的时候判断,左侧的对象是否为`null`或`undefined`。如果是的,就不再往下运算,而是返回`undefined`。
?.运算符相当于一种短路机制,只要不满足条件,就不再往下执行。
a?.b
// 等同于
a == null ? undefined : a.b
a?.[x]
// 等同于
a == null ? undefined : a[x]
a?.b()
// 等同于
a == null ? undefined : a.b()
a?.()
// 等同于
a == null ? undefined : a()
Null 判断运算符 ??
读取对象属性的时候,如果某个属性的值是null或undefined,有时候需要为它们指定默认值。常见做法是通过||运算符指定默认值。但是属性的值如果为空字符串或false或0,默认值也会生效。
所以在ES2020中引入了??、 它只有运算符左侧的值为null或undefined时,才会返回右侧的值。
这个运算符很适合判断函数参数是否赋值。
在 ES2021 引入了新的逻辑赋值运算符
// 或赋值运算符
x ||= y
// 等同于
x || (x = y)
// 与赋值运算符
x &&= y
// 等同于
x && (x = y)
// Null 赋值运算符
x ??= y
// 等同于
x ?? (x = y)
它的作用是为变量和属性设置默认值
// 老的写法
user.id = user.id || 1;
// 新的写法
user.id ||= 1;
Map 和 Set
代理 Proxy(所要代理的目标对象, 配置对象)
可以理解为在目标对象之前设置一层拦截。当外界对该对象进行访问的时候、都必须先通过这层拦截。所以通过代理可以对外界对访问进行过滤和改写。
实例方法
get(目标对象、属性名、 proxy 实例本身)
get方法用于拦截某个属性的读取操作。
set(目标对象、 属性名、属性值、 proxy 实例本身)
set方法用来拦截某个属性的赋值操作。
apply(目标对象、 上下文对象this、目标对象的参数数组)
apply方法拦截函数的调用、call和apply操作。
has(目标对象、 需要查询的属性名)
has()方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是in运算符.
construct(目标对象、 构造函数的参数数组、 创建实例对象时new命令作用的构造函数)
construct()方法用于拦截new命令。
deleteProperty(目标函数、键名key)
deleteProperty方法用于拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除。
Promise
是什么
是异步编程的一种解决方案。简单的说就是一个容器、包含了一个未来才可以确定结果的异步操作事件
特点
- 对象的状态不受外界影响、只能由异步操作的结果决定当前处于那种状态。当处于 pending 状态时、无法得知目前进行到哪一阶段。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。 状态改变只有两种可能
- 从 pending 变为 fullfilled。
- 从 pending 变为 rejected。
要点
- 构造函数、 在
new的时候自动执行。(一旦执行、中途无法取消) - 状态驱动:只能从 pending 变为 fullfilled 或 从 pending 变为 rejected。
- 当
then链式调用时、第一步的结果无论是成功或者失败。都将第一步的结果以成功的状态传给第二步。(把它当作成功的回调)
优点
- 解决回调地狱问题
- 代码可读性高
- 更好的捕获错误
缺点
- Promise 代表已经在进行中的进程(一旦创建就会立即执行)、 中途无法取消
- 当处于 pending 状态时、无法得知目前进行到哪一阶段
- 如果不设置回调函数、promise 内部会抛出错误、不会反应到外部
Promise 类提供了四个静态方法来促进异步任务的并发
Promise.all()
在传入的所有 Promise 都被兑现的时候兑现;任意一个 Promise 被拒绝时拒绝。
Promise.any()
在任意 Promise 被兑现时兑现;仅在所有 Promise 被拒绝时拒绝。
Promise.race()
在任意一个 Promise 被兑现时兑现;任意一个 Promise 被拒绝时拒绝。
Promise.allSettled()
在所有 Promise 被敲定(不是待定状态)的时候兑现。