一、let,const命令
1. let命令:
- 块级作用域,存在暂存死区,不允许重复声明,不存在变量提升;
2. cosnt命令:
- 声明只读常量,值不能改变;(本质上是变量指向的那个内存地址保存的数据不能变动,因此对于简单的数据类型,值就保存在变量存在的地址;对于复合类型,const只能保证这个指针是固定的,无法控制他的数据结构是否可变)
const foo = {}
// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123
// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only
const a = [];
a.push('Hello'); // 可执行
a.length = 0; // 可执行
a = ['Dave']; // 报错
上面代码中,常量`a`是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给`a`,就会报错。
如果真的想将对象冻结,应该使用Object.freeze
方法。
const foo = Object.freeze({});
// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
foo.prop = 123;
二、解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构、
注意:
1、被解构数据不能为undefined,null,NaN等
2、已申明变量解构赋值,需注意js引擎将{}识别为代码块;如:
// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error
//JavaScript 引擎会将`{x}`理解成一个代码块,从而发生语法错误
//正确写法
({x} = {x: 1});
3、数组本质是特殊的对象,因此可以对数组进行对象属性的解构
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3
4、字符串解构赋值。
这是因为此时,字符串被转换成了一个类似数组的对象。( 数值和布尔值同理)
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
let {length : len} = 'hello';
len // 5
5、提高代码优雅性的解构赋值
我们在对接中经常会出现前后端字段不一致的情况,在赋值的时候会出现很多重复代码看着会很难受,,如:
//初始化表单 这样看着就很难受
const setData = (row: any) => {
form.a = row.aa;
form.b = row.bb;
form.c = row.cc;
};
//使用解构赋值优化后 一行代码就可以解决
const setData = (row: any) => {
const { aa : form.a, bb : form.b, cc : form.c } = row;
};
三、运算符扩展
1、指数运算符(**
)
2 ** 2 // 4
2 ** 3 // 8
//还可以和 = 结合使用
let a = 1;
a **= 2;
//等同于 a = a * a
2、链判断运算符(?.
)
三种用法:
obj?.prop
// 对象属性是否存在obj?.[expr]
// 同上func?.(...args)
// 函数或对象方法是否存在
const firstName = message?.body?.user?.firstName || 'default';
let hex = "#C0FFEE".match(/#([A-Z]+)/i)?.[1];
iterator.return?.()
3、Null 判断运算符(??
)
读取对象属性的时候,如果某个属性的值是null
或undefined
,有时候需要为它们指定默认值。常见做法是通过||
运算符指定默认值。
但是通过 ||
来判断是有错误的,当他的属性值为空字符串、false
、0
时默认值也会生效。这样就与我们的实际要求不符合。
为了避免这种情况引入了??
(null判断运算符)
//这个运算符很适合判断函数参数是否赋值。
function Component(props) {
const enable = props.enabled ?? true;
// …
}
4、逻辑赋值运算符
// 或赋值运算符
x ||= y
// 等同于
x || (x = y)
// 与赋值运算符
x &&= y
// 等同于
x && (x = y)
// Null 赋值运算符
x ??= y
// 等同于
x ?? (x = y)
这三个运算符||=
、&&=
、??=
相当于先进行逻辑运算,然后根据运算结果,再视情况进行赋值运算。
它们的一个用途是,为变量或属性设置默认值。
四、Proxy
1、概述
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写;
var obj = new Proxy({}, {
get: function (target, propKey, receiver) {
console.log(`getting ${propKey}!`);
return Reflect.get(target, propKey, receiver);
},
set: function (target, propKey, value, receiver) {
console.log(`setting ${propKey}!`);
return Reflect.set(target, propKey, value, receiver);
}
});
var proxy = new Proxy(target, handler);
Proxy 对象的所有用法,都是上面这种形式,不同的只是handler
参数的写法。其中,new Proxy()
表示生成一个Proxy
实例,target
参数表示所要拦截的目标对象,handler
参数也是一个对象,用来定制拦截行为。
浏览器录像功能:
const body = document.body;
body.addEventListener('click', async function () {
const stream = await navigator.mediaDevices.getDisplayMedia({ video: true });
const mime = MediaRecorder.isTypeSupported('video/webm; codecs=vp9') ? 'video/webm; codecs=vp9' : 'video/webm';
const mediaRecorder = new MediaRecorder(stream, { mimeType: mime }); // 录制
const chunks = [];
mediaRecorder.addEventListener('dataavailable', function (e) {
chunks.push(e.data);
});
mediaRecorder.addEventListener('stop', function () {
const blob = new Blob(chunks, { type: chunks[0].type });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'video.webm';
a.click();
});
mediaRecorder.start();
});