ES(6-11)全版本语法大全
本篇文章为课程笔记,可能有错误
ES6
es6是js的规格,js是es6的实现
1. 新的声明方式:let
变量
- 不属于顶层对象window
- 不允许重复声明
- 不存在变量提升
- 暂时性死区
- 块级作用域
1. 不属于顶层对象window
1 |
|
let的出现是为了弥补var将变量挂在window上的缺陷
static文件夹下的文件是原封不动地上传到浏览器
而src文件夹下的文件会经过webpack打包,会规避一些问题
2. 不允许重复声明
var可以多次重复声明(最后一次声明会覆盖前面的声明),而let不能(会报错)
可以避免重复命名
3. 不存在变量提升
1 |
|
而let不存在变量提升
4. 暂时性死区
1 |
|
5. 块级作用域
1 |
|
块级作用域使得代码更加安全
- 允许在块级作用域内声明函数
- 函数声明类似于
var
,即会提升到全局作用域或函数作用域的头部 - 同时,函数声明还会提升到所在的块级作用域的头部
参考:https://zhuanlan.zhihu.com/p/100856823
2. 新的声明方式:const
常量,不能被重新赋值
1 |
|
对于引用类型,const不能改变其引用地址,但是可以改变堆内存中的值
1 |
|
- 不属于顶层对象window
- 不允许重复声明
- 不存在变量提升
- 暂时性死区
- 块级作用域
区别:
var let const 函数级作用域 块级作用域 块级作用域 变量提升 不存在变量提升 不存在变量提升 值可更改 值可更改 值不可更改
let VS const
默认情况下优先使用const,如果需要被改变再考虑let
let 变量 const 常量
3. ==解构赋值(常用)==
- 按照一定模式,从数组和对象中提取值,对变量进行赋值
- 数组解构
- 对象解构
- 字符串解构
- 应用
默认参数的使用(当没有传这个值的时候,默认赋该值)
等号左右两边的结构一样即可
1 |
|
数组通过索引进行配对(按顺序解构)
对象通过键名进行配对(变量必须和属性同名)
解构也适用于嵌套结构的对象(要使用一样的结构)
1 |
|
嵌套赋值:
1 |
|
- 字符串的解构和数组相似
1
2
3
4
5
function foo([a,b,c]) {
console.log(a,b,c)
}
let arr = [1,2,3]
foo(arr)对于json
1
2
let json = '{"a":"hello","b":"world"}'
let {a,b} = JSON.parse(json) //将json格式输出成对象,再进行解构赋值
使用了别名之后,真正被赋值的是后者
1 |
|
注意:
1 |
|
数值和布尔值的解构赋值:
会先转换为对象
解构赋值的规则:
只要等号右边的值不是对象或数组,就先转换为对象
undefined
和null
无法转为对象,故无法进行解构赋值函数的参数也可以使用解构赋值
用途:
交换变量的值
1
2
3
4let x = 1;
let y = 2;
[x, y] = [y, x];从函数返回多个值
1
2
3
4
5
6
7
8
9
10
11
12
13
14// 返回一个数组
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
// 返回一个对象
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();函数参数的定义
1
2
3
4
5
6
7// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});提取JSON数据
函数参数的默认值
遍历Map结构
输入模块的指定方法
1
const { SourceMapConsumer, SourceNode } = require("source-map");
4. 数组的各种遍历方式
ES5中的数组遍历方式
- for循环
- forEach():没有返回值,只是针对每个元素调用func
- map():返回新的Array,每个元素为调用func的结果
- filter():返回符合func条件的元素数组
- some():返回布尔,判断是否有元素符合func条件
- every():返回布尔,判断每个元素是否符合func条件
- reduce():接收一个函数作为累加器
- for in ???
1 |
|
ES6中数组遍历方法
- find():返回第一个通过测试的元素
- findIndex():返回的值为该通过第一个元素的索引
- for of
- values()
- keys()
- entries()
1 |
|
5. 数组的扩展
类数组/伪数组
有长度,但不能使用数组的方法
Array.from()
Array.of()
copyWithin()
fill()
includes()
es5中,可以通过slice方法将伪数组转换成数组
1 |
|
es6中:
1 |
|
NAN == NAN 不相等
6. 函数的参数
- 参数的默认值
- 与解构赋值结合
- length属性
- 作用域
- 函数的name属性
1. 参数的默认值
1 |
|
2. 与解构赋值结合
1 |
|
与默认值一同使用
1 |
|
3. length属性
返回没有指定默认值的个数
4. 作用域
1 |
|
1 |
|
5. 函数的name属性
(new Function).name //输出anonymous
7. 拓展运算符 与 rest参数
…
扩展运算符:把数组或者类数组展开成用逗号隔开的值
rest参数:把逗号隔开的值组合成一个数组
互逆操作
如果…放在等号左边或是形参上,则rest参数
如果…放在等号右边或是实参上,则扩展运算符
1 |
|
1 |
|
1 |
|
1 |
|
8. 箭头函数
this指向定义时所在的对象,而不是调用时所在的对象
箭头函数里没有this,会往外一层去找this
不可以当作构造函数
不可以使用arguments对象
箭头函数的写法:箭头左边是参数,右边是方法体
let sum = (x,y) => {
return x + y
}
//可以简写成 let sum = (x,y) => x + y (方法体只有一行代码)
1 |
|
1 |
|
9. 对象的扩展
属性简洁表示法
属性名表达式
Object.is() 即===
拓展运算符 与 Object.assign()
in
对象的遍历方式
1. 属性简洁表示法 属性名表达式
1 |
|
2. Object.is()
obj1 == obj2 //false
obj存储的是一个引用地址,每一个obj都会进行一次new Object(),在堆内存中进行存储,所以哪怕两个对象内容一模一样,在堆内存中的位置也是不一样的,故返回false
同样 Object.is(obj1 == obj2) //false
let obj1 = obj2
Object.is(obj1 == obj2) //true
3. 拓展运算符 与 Object.assign()
1 |
|
4. in
判断对象中是否存在
如果是数组:
console.log(3 in arr) //下标为3是否存在
5. 对象的遍历方式
1 |
|
10. 深拷贝与浅拷贝
1. 浅拷贝
1 |
|
1 |
|
改变内容,都会改变(因为改变的是引用地址)
2. 深拷贝
JSON方式
JSON.parse() 将JSON字符串转换成JavaScript对象
JSON.stringify() 将JavaScript对象转换成JSON字符串
1
2
3
4
5
6
7
8
9let Foo = {
a: {
c:1
},
b: 4
}
let str = JSON.stringify(Foo)
let newFoo = JSON.parse(str)
newFoo.a.c = 5递归
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30let checkType = data => {
return Object.prototype.toString.call(data).slice(8, -1)
}
let deepClone = target => {
let targetType = checkType(target)
let result
// 初始化操作
if (targetType === 'Object') {
result = {}
} else if (targetType === 'Array') {
result = []
} else {
// 都不是的话证明是基本数据类型,基本数据
// 类型只会有一个值,所以直接返回这个值就可以了
return target
}
// target不是基本类型,进入遍历
for (let i in target) {
let value = target[i]
let valueType = checkType(value)
if (valueType === 'Object' || valueType === 'Array') {
result[i] = deepClone(value) // 递归
} else {
// 是基本类型直接赋值
result[i] = value
}
}
return result
}
11. 面向过程与面向对象
面向过程:强调实现需求的步骤
面向对象:对象的属性、方法
JavaScript是一种基于对象的语言
类是对象的模板,定义了同一组对象共有的属性和方法
12. ES5中的类与继承
组合式继承
1 |
|
13. ES6中的类与继承
1. class是语法糖
1 |
|
2. 继承 extends
1 |
|
3. Setters&Getters
1 |
|
使用这种方式可以在里面写语句
eg.
set age(val) {
if (val > 0 && val < 10) {
#age = val
}
}
4. 静态方法
使用static
来标记
1 |
|
- 类中的构造器不是必须写的,要写实例进行一些初始化的操作,如添加指定属性时才写
- 如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的
- 类中所定义的方法,都是放在了类的原型对象上,供实例去使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//传统方法
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
//class方法
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() { //方法必须使用该语法,方法名(){}
return '(' + this.x + ', ' + this.y + ')';
}
}Object.assign()一次向类添加多个方法
1 |
|
- 类必须使用
new
调用
es5里,实例的属性是函数原型的属性
在es6中,static声明静态属性,属性属于类不属于实例
1
2
3
4
5
6
7
function Phone(){
}
Phone.name = '手机'; //name属性属于函数对象的,不属于实例对象,称为静态属性
Phone.prototype.size = '5.5inch'; //原型
let nokia = new Phone(); //实例化
console.log(nokia.name); //报错
console.log(nokia.size); //输出 5.5inch
1 |
|
- 取值get 存值set
14. 新的原始数据类型Symbol
let s = new Symbol() 错误,不能使用new
Symbol不是对象,不能添加属性(是一种类似于字符串的数据类型)
1. 独一无二
这个可以保证相同key值的也保存下来(比如重名学生)
1 |
|
2. 自动调用toString()函数
1 |
|
3. Symbol.for()
在全局中注册的
不会每次调用都返回一个新的 Symbol 类型的值,而是先检查给定的key是否已经存在,不存在才新建
1 |
|
4. Symbol.keyFor()
返回一个已经登记的Symbol类型值的key
1 |
|
5. 属性遍历
1 |
|
可以很好地保护symbol值
6. 消除魔术字符串
1 |
|
1 |
|
15. 新的数据结构Set
数据结构 Se类似于数组,但是成员的值都是唯一的,没有重复的值
1. 基本语法
生成 Set 实例
1 |
|
1 |
|
添加数据
1 |
|
1 |
|
添加重复的数据是无效的
删除数据
1 |
|
统计数据
1 |
|
数组去重
1 |
|
合并去重
1 |
|
交集
1 |
|
差集
1 |
|
2. 遍历方式
1 |
|
3. WeakSet
区别:
成员只能是对象,而不能是其他类型的值
没有size属性,不能遍历
弱引用
所谓垃圾回收机制:
如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在
1 |
|
16. 新的数据类型Map
类似于对象,键值对的集合
“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键
也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应
是一种更完善的 Hash 结构实现
如果你需要“键值对”的数据结构,Map 比 Object 更合适。
1. 基本语法
实例化
1 |
|
添加数据
1 |
|
删除数据
1 |
|
统计数据
1 |
|
查询数据
1 |
|
2. 遍历方式
1 |
|
Map VS Object:
键的类型
Object的键: 字符串或者 Symbols
Map 的键: 任意值
键的顺序
Object的键:无序
Map的键值:有序
进行遍历时,Map 对象是按插入的顺序返回键值。
键值对的统计
Object的个数:只能手算
Map的个数:用size
键值对的遍历
Object:先获取键数组,再进行迭代
Map:可直接进行迭代
性能
在涉及频繁增删键值对的场景下,Map 会有些性能优势
3. WeekMap
1 |
|
区别:
WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名
不计入垃圾回收机制
17. 字符串的扩展
1. Unicode表示法(少用)
Unicode有啥用:
保证简便高效和保持与已有编码标准兼容之间的平衡
在内部使用Unicode的应用程序,能够同时存储和处理世界上所有的字符,这消除了传统的国际化方法所面临的一些困难
- es5
1 |
|
只限于码点在\u0000~\uFFFF之间的字符
超出须用两个双字节的形式表示
1 |
|
- es6
将码点放入大括号
1 |
|
1 |
|
2. 遍历器接口
1 |
|
3. ==模板字符串==
多行字符串
使用后,不需要使用/n换行
插入表达式
1
2
3
4var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b} and
not ${2 * a + b}.`);如果模板字符串中的变量没有声明,会报错
1
2// 变量place没有声明
let msg = `Hello, ${place}`; // 报错嵌套模板
标签模板
==tag函数(?)==
4. 扩展方法
String.fromCodePoint()
从 Unicode 码点返回对应字符(可以识别大于0xFFFF的字符)
弥补了
String.fromCharCode()
方法的不足String.includes()
是否包含该字符串(es5中使用indexOf)
1
2const str = 'imooc'
console.log(str.includes('mo')) //trueString.startsWith()
判断是否在头部
1
2const str = 'imooc'
console.log(str.endsWith('mooc')) //trueString.endsWith()
判断是否在尾部
上述三个方法都有第二个参数n
includes和startsWith从第n个位置直到字符串结束
endsWith是对前n个字符
String.repeat(n)
将原字符串重复n次后返回一个字符串
如果是小数,会被取整
如果是负数或者infinity,报错
NaN等同0
1
2
3const str = 'yl'
const newStr = str.repeat(10)
console.log(newStr) //ylylylylylylylylylylString.raw() 在斜杆前面再加一个斜杆
1
String.raw`Hi\n${2+3}!` //"Hi\\n5!"
1
2// 等同于`foo${1 + 2}bar` "foo3bar"
String.raw({ raw: ['foo', 'bar'] }, 1 + 2)String.codePointAt() 返回码点的十进制值
String.normalize()
String.trimStart()【trimLeft()】 消除头部的空格,尾部会被保留
String.trimEnd() 【trimRight()】消除尾部的空格,头部会被保留
String.matchAll() 返回一个正则表达式在当前字符串的所有匹配
String.replaceAll(searchValue, replacement) 替换掉所有匹配值
searchValue不能是不带g修饰符的正则表达式,会报错
replacement为替换的文本,也可以是函数,或是以下特殊字符串:
$&
:匹配的子字符串。$
`:匹配结果前面的文本。$'
:匹配结果后面的文本。$n
:匹配成功的第n
组内容,n
是从1开始的自然数。这个参数生效的前提是,第一个参数必须是正则表达式。$$
:指代美元符号$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25// $& 表示匹配的字符串,即`b`本身
// 所以返回结果与原字符串一致
'abbc'.replaceAll('b', '$&')
// 'abbc'
// $` 表示匹配结果之前的字符串
// 对于第一个`b`,$` 指代`a`
// 对于第二个`b`,$` 指代`ab`
'abbc'.replaceAll('b', '$`')
// 'aaabc'
// $' 表示匹配结果之后的字符串
// 对于第一个`b`,$' 指代`bc`
// 对于第二个`b`,$' 指代`c`
'abbc'.replaceAll('b', `$'`)
// 'abccc'
// $1 表示正则表达式的第一个组匹配,指代`ab`
// $2 表示正则表达式的第二个组匹配,指代`bc`
'abbc'.replaceAll(/(ab)(bc)/g, '$2$1')
// 'bcab'
// $$ 指代 $
'abc'.replaceAll('b', '$$')
// 'a$c'
在es5中使用replace()如果想要匹配所有,需要使用正则表达式
18. 正则表达式的拓展
作用:检索、替换那些符合某个模式(规则)的文本
eg. 验证表单(匹配)、过滤页面内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)
1. RegExp构造函数
- 利用RegExp对象来创建
- 利用字面量创建
1 |
|
1 |
|
测试正则表达式 test() 返回布尔值 regexObj.test(str)
检测是否符合正则表达式要求的规范
正则表达式里面不需要使用引号
2. y修饰符
“粘连”修饰符
后一次匹配都从上一次匹配成功的下一个位置开始
与g修饰符类似,全局匹配
不同:
- g修饰符只要剩余位置中存在匹配就可
- y修饰符确保匹配必须从剩余的第一个位置开始
1
2
3
4
5
6
7
8
9
10
var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;
r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]
r1.exec(s) // ["aa"]
r2.exec(s) // null
//y修饰符号隐含了头部匹配的标志^
- 检测 y 标志 =>
sticky
1 |
|
- lastIndex 指定从xx位置开始匹配
3. u修饰符
Unicode模式
处理大于
\uFFFF
的Unicode字符点字符 除了换行符以外的任意单个字符
1
2
3
4var s = '𠮷';
/^.$/.test(s) // false
/^.$/u.test(s) // true,需要添加u字符i修饰符
1
2/[a-z]/i.test('\u212A') // false
/[a-z]/iu.test('\u212A') // trueunicode 是否设置了
u
修饰符处理不兼容es6:
1
2
3
4
5
6
7
8function hasRegExpU() {
try {
var pattern = new RegExp(".", "u");
return true;
} catch (ex) {
return false;
}
}
4. flags属性
source 获取正则表达式的文本
flags 返回正则表达式中石油标志组成的字符串形式
1
2
3var re = /ab/g;
console.log(re.source); // "ab"
console.log(re.flags); // "g"
5. 后行断言
- 先行断言:
x
只有在y
前面才匹配,必须写成/x(?=y)/
先行否定断言:
x
只有不在y
前面才匹配,必须写成/x(?!y)/
后行断言:
x
只有在y
后面才匹配,必须写成/(?<=y)x/
- 后行否定断言:
x
只有不在y
后面才匹配,必须写成/(?<!y)x/
6. 具名组匹配
用圆括号分组
1 |
|
ES2018引入了具名组匹配
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
7. 引用
如果要在正则表达式内部引用某个“具名组匹配”,可以使用\k<组名>
的写法
8. 正则匹配索引
indices 返回每个组
indices.groups 提供具名组匹配
Z
的开始位置和结束位置获取组匹配不成功,均返回
undefined
1 |
|
1 |
|
19. 数值的拓展
1. 二进制0B 八进制0O
1 |
|
1 |
|
2. 新增方法
Number.isFinite() 检查一个数值是否为有限的
1
2
3
4
5
6
7
8
9//数值就会返回true,其他的都是false
Number.isFinite(15) // true
Number.isFinite(0.8) // true
Number.isFinite(NaN) // false
Number.isFinite(Infinity) // false
Number.isFinite(-Infinity) // false
Number.isFinite('foo') // false
Number.isFinite('15') // false
Number.isFinite(true) // falseNumber.isNaN() 检查一个值是否为NaN
1
2
3
4
5
6
7
8//NAN值就返回true
Number.isNaN(NaN) // true
Number.isNaN(15) // false
Number.isNaN('15') // false
Number.isNaN(true) // false
Number.isNaN(9 / NaN) // true
Number.isNaN('true' / 0) // true
Number.isNaN('true' / 'true') // trueNumber.parseInt()
在es5中,parseInt是window上的
Number.parseFloat()
同上
Number.isInteger() 判断一个数值是否为整数
JavaScript 内部,整数和浮点数采用的是同样的储存方法,所以 25 和 25.0 被视为同一个值。
存在误判的情况 例如精度丢失、小于Number.MIN_VALUE
1
2
3
4
5
6
7Number.isInteger(25) // true
Number.isInteger(25.1) // false
Number.isInteger() // false
Number.isInteger(null) // false
Number.isInteger('15') // false
Number.isInteger(true) // falseNumber.MAX_SAFE_INTEGER 最大安全数:2^53 = 9007199254740991
Number.MIN_SAFE_INTEGER -9007199254740991
Number.isSafeInteger() 在-2^53^到2^53^之间(不含两个端点)
Number.EPSILON 表示 1 与大于 1 的最小浮点数之间的差 [可接受的最小误差范围]
最小精度。误差如果小于这个值,就可以认为已经没有意义了,即不存在误差
3. Math拓展
ES6 在 Math 对象上新增了 17 个与数学相关的方法。所有这些方法都是静态方法,只能在 Math 对象上调用
Math.trunc() 去除一个数的小数部分,返回整数部分
true代表1,false代表0,其余非数值的返回NaN
1
2
3
4
5
6
7console.log(Math.trunc(5.5))
console.log(Math.trunc(-5.5))
console.log(Math.trunc(true)) // 1
console.log(Math.trunc(false)) // 0
console.log(Math.trunc(NaN)) // NaN
console.log(Math.trunc(undefined)) // NaN
console.log(Math.trunc()) // NaNMath.sign() 判断正数、负数、零
true和false会转换为数值后进行判断
1
2
3
4
5
6console.log(Math.sign(5)) // 1
console.log(Math.sign(-5)) // -1
console.log(Math.sign(0)) // 0
console.log(Math.sign(NaN)) // NaN
console.log(Math.sign(true)) // 1
console.log(Math.sign(false)) // 0Math.cbrt() 计算一个数的立方根,非数的返回NaN
Math.clz32() 将参数转为 32 位无符号整数的形式,返回 32 位值里面有多少个前导 0 只考虑整数部分
1
2
3Math.clz32(1000) // 22 1000 的二进制形式是0b1111101000,一共有10位,所以32位之中有22个前导0
Math.clz32(0b01000000000000000000000000000000) // 1
Math.clz32(0b00100000000000000000000000000000) // 2左移运算符(
<<
)与Math.clz32
方法直接相关Math.imul() 效果和
(a*b)|0
相同,可以处理溢出的情况1
2
3Math.imul(-2, -2) // 4
(0x7fffffff * 0x7fffffff)|0 // 0
Math.imul(0x7fffffff, 0x7fffffff) // 1
Math.fround() 将64位双精度浮点数转为32位单精度浮点数
1
2
3
4
5
6
7
8
9
10
11
12
13// 丢失精度
Math.fround(0.7) // 0.699999988079071
//对于 NaN 和 Infinity,此方法返回原值
Math.fround(NaN) // NaN
Math.fround(Infinity) // Infinity
//先将其转为数值,再返回单精度浮点数
Math.fround('5') // 5
Math.fround(true) // 1
Math.fround(null) // 0
Math.fround([]) // 0
Math.fround({}) // NaN
Math.hypot() 返回所有参数的平方和的平方根
先将非数值的转换为数值,无法转换的返回NaN
1
2
3
4
5
6
7Math.hypot(3, 4); // 5
Math.hypot(3, 4, 5); // 7.0710678118654755
Math.hypot(); // 0
Math.hypot(NaN); // NaN
Math.hypot(3, 4, 'foo'); // NaN
Math.hypot(3, 4, '5'); // 7.0710678118654755
Math.hypot(-3); // 3Math.expm1()
Math.expm1(x)
=> ex - 1 ==Math.exp(x) - 1
。Math.log1p()
Math.log1p(x)
==Math.log(1 + x)
Math.log10() 返回以 10 为底的
x
的对数Math.log2() 返回以 2 为底的
x
的对数
以上三个方法,如果
x
小于 0,则返回 NaN
- 双曲函数方法:
Math.sinh(x)
返回x
的双曲正弦Math.cosh(x)
返回x
的双曲余弦Math.tanh(x)
返回x
的双曲正切Math.asinh(x)
返回x
的反双曲正弦Math.acosh(x)
返回x
的反双曲余弦Math.atanh(x)
返回x
的反双曲正切
20. 代理proxy
自定义一些常用行为如查找、赋值、枚举、函数调用等
1. 基本语法
1 |
|
target :用来代理的“对象”,被代理之后不能直接被访问
handler :实现代理的过程
2. 拦截操作场景
1 |
|
场景 1
从服务端获取的数据希望是只读,不允许在任何一个环节被修改。
1 |
|
使用 Proxy :
1 |
|
场景 2
校验
1 |
|
场景 3
对读写进行监控:
1 |
|
场景 4
实例一个对象,每个对象都有一个自己的 id 而且只读。
1 |
|
3. 常用拦截操作
get
拦截对象属性的读取
1 |
|
set
拦截对象属性的设置
1 |
|
has
拦截propKey in proxy的操作,返回一个布尔值。
1 |
|
ownKeys
拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for…in循环,返回一个数组
该方法返回目标对象所有自身的属性的属性名
而Object.keys()的返回结果仅包括目标对象自身的可遍历属性
1 |
|
deleteProperty
拦截delete proxy[propKey]的操作,返回一个布尔值
1 |
|
apply
拦截 Proxy 实例作为函数调用的操作,比如proxy(…args)、proxy.call(object, …args)、proxy.apply(…)
1 |
|
construct
拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(…args)
1 |
|
21. 反射Reflect
和Proxy一起使用
1. 设计目的
- 将Object属于语言内部的方法放到Reflect上
1 |
|
- 修改某些Object方法的返回结果,让其变得更合理
1 |
|
- 让Object操作变成函数行为
1 |
|
Reflect对象的方法与Proxy对象的方法一一对应
(只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法)
1 |
|
Reflect 是一个内置的对象,提供拦截 JavaScript 操作的方法,这些方法与处理器对象的方法相同
Reflect不是一个函数对象,因此它是不可构造的。
Reflect没有构造函数(不能与new使用,或将Reflect对象作为函数调用
Reflect的所有属性和方法都是静态的
2. 常用方法
Reflect.apply(target, thisArgument, argumentsList)
参数 | 含义 | 必选 |
---|---|---|
target | 目标函数 | Y |
thisArgument | target函数调用时绑定的this对象 | N |
argumentsList | target函数调用时传入的实参列表,该参数应该是一个类数组的对象 | N |
1 |
|
ES5 对比
与ES5中Function.prototype.apply()方法类似
1
Function.prototype.apply.call(Math.floor, undefined, [1.75])
Reflect.construct(target, argumentsList[, newTarget])
参数 | 含义 | 必选 |
---|---|---|
target | 被运行的目标函数 | Y |
argumentsList | 调用构造函数的数组或者伪数组 | Y |
newTarget | 该参数为构造函数, 参考 new.target 操作符,如果没有newTarget参数, 默认和target一样 | N |
如果target或者newTarget不是构造函数,抛出TypeError
1 |
|
Reflect.defineProperty()
静态方法 Reflect.defineProperty() 基本等同于 Object.defineProperty() 方法,唯一不同是返回 Boolean 值。
Reflect.defineProperty(target, propertyKey, attributes)
参数 | 含义 | 必选 |
---|---|---|
target | 目标对象 | Y |
propertyKey | 要定义或修改的属性的名称 | Y |
attributes | 要定义或修改的属性的描述 | Y |
1 |
|
Reflect.deleteProperty 允许你删除一个对象上的属性
返回一个 Boolean 值表示该属性是否被成功删除
Reflect.deleteProperty(target, propertyKey)
参数 | 含义 | 必选 |
---|---|---|
target | 删除属性的目标对象 | Y |
propertyKey | 将被删除的属性的名称 | Y |
1 |
|
Reflect.get(target, propertyKey[, receiver])
参数 | 含义 | 必选 |
---|---|---|
target | 需要取值的目标对象 | Y |
propertyKey | 需要获取的值的键值 | Y |
receiver | 如果遇到 getter,此值将提供给目标调用 | N |
1 |
|
Reflect.getOwnPropertyDescriptor()
与 Object.getOwnPropertyDescriptor() 方法相似
如果在对象中存在,则返回给定的属性的属性描述符,否则返回 undefined
Reflect.getOwnPropertyDescriptor(target, propertyKey)
参数 | 含义 | 必选 |
---|---|---|
target | 需要寻找属性的目标对象 | Y |
propertyKey | 获取自己的属性描述符的属性的名称 | N |
1 |
|
对比
如果该方法的第一个参数不是一个对象(一个原始值),那么将造成 TypeError 错误
而对于 Object.getOwnPropertyDescriptor,非对象的第一个参数将被强制转换为一个对象处理
1
2
3
4
5
Reflect.getOwnPropertyDescriptor("foo", 0)
// TypeError: "foo" is not non-null object
Object.getOwnPropertyDescriptor("foo", 0)
// { value: "f", writable: false, enumerable: true, configurable: false }
Reflect.getPrototypeOf(target)
参数 | 含义 | 必选 |
---|---|---|
target | 获取原型的目标对象 | Y |
Reflect.has(target, propertyKey)
参数 | 含义 | 必选 |
---|---|---|
target | 获取原型的目标对象 | Y |
propertyKey | 属性名,需要检查目标对象是否存在此属性 | Y |
Reflect.isExtensible(target)
参数 | 含义 | 必选 |
---|---|---|
target | 获取原型的目标对象 | Y |
Reflect.ownKeys()
返回一个由目标对象自身的属性键组成的数组
返回值等同于 Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
Reflect.ownKeys(target)
参数 | 含义 | 必选 |
---|---|---|
target | 获取原型的目标对象 | Y |
1 |
|
Reflect.preventExtensions(target)
参数 | 含义 | 必选 |
---|---|---|
target | 获取原型的目标对象 | Y |
1 |
|
Reflect.set(target, propertyKey, value[, receiver])
参数 | 含义 | 必选 |
---|---|---|
target | 获取原型的目标对象 | Y |
propertyKey | 设置的属性的名称 | Y |
value | 设置的值 | Y |
receiver | 如果遇到 setter,this 将提供给目标调用 | N |
1 |
|
改变指定对象的原型
Reflect.setPrototypeOf(target, prototype)
参数 | 含义 | 必选 |
---|---|---|
target | 获取原型的目标对象 | Y |
prototype | 对象的新原型 (一个对象或 null) | Y |
1 |
|
22. 异步操作
1 |
|
(1)(3)属于主线程任务,为同步操作,(2)为异步任务,先进入Event Table中,等待0秒后进入Event Queue中等待主线程的任务全部完成后,再读取任务队列中结果进入主线程执行。
所以,如果有一个异步任务经过2秒后进入到Event Queue中,但是主线程的任务需要5秒才能执行完毕,此时的异步任务会在Event Queue中等待主线程任务完成,即等待3秒后进入主线程。
Ajax
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23function ajax(url,callback) {
// 1. 创建XMLHttpRequest对象
var xmlhettp
if(window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest()
} else { //兼容早期浏览器
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP')
}
// 2. 发送请求
xmlhttp.open('GET',url,true)
xmlhttp.send()
// 3. 服务端相应
xmlhttp.onreadystatechange = function () {
if(xmlhttp.readState === 4 && xmlhttp.staus === 200) {
var obj = JSON.parse(xmlhttp.responseText])
callback(obj)
}
}
}
var url = '...';
ajax(url,res => {
console.log(res)
})
23. Promise
1. 基本用法
1 |
|
2. 状态
1 |
|
1 |
|
3. 使用Promise发送ajax请求
单纯使用ajax需要嵌套非常多层
使用Promise有大量重复代码,抽离出来写成一个函数,使得代码可读性更强,也有利于后期维护
1 |
|
统一捕获err
1 |
|
4. Promise的静态方法
Promise.resolve(‘success’)
Promise.reject(‘fail’)
1 |
|
Promise.all([…]) 所有对象都完成之后才会进入res,只要有一个是失败的,都会进入err中
可应用于上传多张图片中
1 |
|
1 |
|
Promise.race([…]) 只要有一个成功,整个就会进入res中
可应用于请求图片超时
1 |
|
1 |
|
24. Generator
1 |
|
对应结果:
1 |
|
使用Generator进行ajax请求
1 |
|
25. Module
- export default 默认,导入不需要知道命名(可以直接使用别名)
- import * from ‘../../xx.js’
把庞大的代码拆开
将多个功能的代码按功能进行分开,以达到多个模块组合在一起形成一个功能复杂的功能
好处:
- 防止命名冲突
- 代码复用
- 高维护性
语法
<script type="module"> </script>
也可以使用
<script src="./src/js/app.js" type="module"></script>
将引用部分放到另一个js文件里export 对外接口
导入的时候命名要完全一样,可以起别名,起了别名之后文件中使用只能使用别名,原名已经失效了
export 和 export default 可以一起使用
import add, {str} from '../../xxx.js'
分别暴露:在要暴露的语句前面+export
统一暴露:在某个位置使用export{},将要暴露的数据放在花括号里面
在模块文件里,使用export default
export default {
...
}
这样就可以直接使用了
默认暴露:export.default = { },这种方法在调用时需要添加default
导入不需要知道命名(可以直接使用别名)
import 输入其他模块提供的功能
通用的导入方式:import * as m1 from “./src/js/m1.js”;
导入的是全部
解构赋值的形式:
- import{school,teach} from “./src/js/m1.js”;
- import{default as m1} from “./src/js/m1.js”;
重名时需要使用别名,不然会报错
简便形式(针对默认暴露):improt m3 from “./src/js/m3.js”
使用babel
安装工具
npm i babel-cli babel-preset-env browerify -D
编译:
npx babel src/js -d dist/js --presets=babel-preset-env
先 [原文件目录] 后 [存放文件目录]- 打包 :
npx browserify dist/js/app.js -o dist/bundle.js
将存放文件目录下的文件打包生成bundle.js文件
ES7
1. 数组拓展
- Array.prototype.includes(searchElement[,fromIndex])
includes VS indexOf
- includes 返回布尔值,可以检测NaN
- indexOf 返回index / -1,不可以检测NaN
幂运算符:**
等同于Math.pow()
ES8
1. 异步编程解决方案Async Await
两者成对出现
代码可读性更强
1 |
|
之前的ajax请求代码:
1 |
|
2. 对象拓展
Object.values() 获得值
Object.entries() 获得数组(key和value)
1
2
3
4
5const res = Object,keys(obj).map(key => obj[key])
console.log(res)
//上面可以写成
console.log(Object.values(obj))1
2console.log(Object.entries(['a','b','c']))
//["0","a"],["1","b"],["2","c"]
3. 对象属性描述
- Object.getOwnPropertyDescriptors()
- value 当前对象的默认值
- writable 是否可以修改
- enumerable 是否可以通过for..in方式循环
- configurable 是否可以删除
4. 字符串拓展
String.prototype.padStart() 头部补全
String.prototype.padEnd() 尾部补全
第一个参数为长度,第二个参数为用于补全的字符串
1 |
|
1 |
|
1 |
|
5. 尾逗号
允许数参数列表使用尾逗号
ES9
1. 异步迭代for await of
- for-await-of
- Symbol.asyncIterator
1 |
|
1 |
|
2. 正则表达式拓展
dotAll
dot不能匹配\n \r(包括两者的Unicode)
1
2
3
4
5
6
7const reg = /./s //匹配任意单个字符
console.log(reg.test('5')) //true
console.log(reg.test('x')) //true
console.log(reg.test('\n')) //true
console.log(reg.test('\r')) //true
console.log(reg.test('\u{2028}')) //true
console.log(reg.test('\u{2029}')) //true具名组匹配
1
2
3
4
5
6const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/; //用圆括号分组
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; // 1999
const month = matchObj[2]; // 12
const day = matchObj[3]; // 311
2
3
4
5const reg = /(?<year>\d{4}-(?<month)\d{2}-(?<day>\d{2}))
const groups = reg.exec('2020-02-01').groups
//使用解构赋值
const {year, month,day} = groups
console.log(year, month, day)后行断言 match
- 先行断言:
x
只有在y
前面才匹配,必须写成/x(?=y)/
先行否定断言:
x
只有不在y
前面才匹配,必须写成/x(?!y)/
后行断言:
x
只有在y
后面才匹配,必须写成/(?<=y)x/
- 后行否定断言:
x
只有不在y
后面才匹配,必须写成/(?<!y)x/
- 先行断言:
3. 对象拓展Rest&Spread
1 |
|
4. Promise拓展finally()
Promise.prototype.finally()
无论失败还是成功都会执行finally里面的语句【例如:成功失败相同的代码逻辑、关闭操作】
5. 字符串扩展
放松模板字符串文字限制,对一些错误不报错,返回undefined
ES10
1. 对象扩展
Object.fromEntries() 返回对象结构 【和Object.Entries()相反(返回键对结构)】
1
2
3
4
5
6
7// map => 对象
const map = new Map()
map.set('name', 'n1')
map.set('name', 'n2')
console.log(map)
const fromEntries = Object.fromEntries(map)
console.log(map) //对象格式
2. 字符串扩展
- String.prototype.trimStart()【trimLeft()】 消除头部的空格,尾部会被保留
- String.prototype.trimEnd() 【trimRight()】消除尾部的空格,头部会被保留
- String.prototype.trim() 消除空格
3. 数组扩展
Array.prototype.flat(num) 对多维数组进行扁平化操作
1
2
3
4const arr = [1,2,3,[4,5,6,[7,8,9,10,11],12]] //三维数组
console.log(arr.flat().flat().flat())
console.log(arr.flat(3))
console.log(arr.flat(Infinity))Array.prototype.flatMap()
1
2
3const arr = [1,2,3,4,5]
//const res = arr.map(x => [x + 1]).flat() 等价于↓
const res = arr.flatMap(x => [x + 1])
4. 修订toString()
返回源代码中的实际文本片段【原样输出返回一模一样的原始代码,包括注释空格等等】
5. 可选的Catch Binding
省略catch绑定的参数和括号
1 |
|
6. JSON扩展
- JSON superset
- JSON.stringify() 增强能力
1 |
|
1 |
|
7. Symbol扩展
- Symbol.prototype.description 只读属性,不可写【修改description也不会报错,但是不能起作用】
1 |
|
ES11
1. 全局模式捕获matchAll()
String.prototype.matchAll() 和正则一起使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51const str = `
<html>
<body>
<div>第一个div</div>
<p>这是p</p>
<div>第二个div</div>
<span>这是span</span>
<div>第三个div</div>
</body>
</html>
`
//exec g
function selectDiv1(regExp, str) {
let matches = []
while(true) {
const match = regExp.exec(str)
if(match == null) {
break
}
matches.push(match[1]) //完整匹配
}
return matches
}
const regExp = /<div>(.*)</div>/g
const res1 = selectDiv1(regExp, str)
console.log(res1) //["第一个div","第二个div","第三个div"]
//match
//console.log(str.match(regExp)) //["<div>第一个div</div>","<div>第二个div</div>","<div>第三个div</div>"]
//replace
function selectDiv2(regExp, str) {
let matches = []
str.replace(regExp, (all, first) => {
matches.push(first) //完整匹配
})
return matches
}
const res2 = selectDiv2(regExp, str)
console.log(res2) //["第一个div","第二个div","第三个div"]
//matchAll
function selectDiv3(regExp, st){
let matches = []
for(let match of str.matchAll(regExp)){
matches.push(match[1]) //完整匹配
}
return matches
}
const res3 = selectDiv3(regExp, str)
console.log(res3) //["第一个div","第二个div","第三个div"]matchAll方法的正则表达式需要有g(全局匹配)
2. 动态导入Dynamic import()
按需引入,使得页面渲染更快
懒加载
eg. 点击按钮才导入某个模块、才开始渲染这一部分的东西
3. 新的原始数据类型BigInt
1 |
|
4. Promise扩展allSettled()
- Promise.allSettled()
- allSettled() Vs all()
1 |
|
如果使用all(),则其中有一个reject都会导致整个进程进入“失败”;而allSettled(),成功的会返回status: "fulfilled" value:{...}
,失败的返回reson: {...}
,使用filter进行过滤获得请求成功的数据
5. 全局对象globalThis
提供一个标准的方式去获取不同环境下的全局对象
1 |
|
6. 可选链Optional chaining
先判断这个方法属性是否存在,如果存在再往下取
1 |
|
?.
中间不能有空格
7. 空值合并运算符Nullish coalescing Operator
1 |
|
??
中间不能有空格
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!