let和const
相同点:
1、只在声明所在的块级作用域内有效。
2、都不提升,同时存在暂时性死区。
3、不可重复声明。
4、必须遵循 "先声明,后使用"否则会报错
不同点:
1、let声明的变量可以改变,值和类型都可以改变;
2、const声明的常量不可以改变,这意味着,const一旦声明,就必须立即初始化,不能以后再赋值。
对于复合类型的变量,如数组和对象,变量名不指向数据,而是指向数据所在的地址。const命令只是保证变量名指向的地址不变,
并不保证该地址的数据不变。
例如:const aa = []; aa = [1,2](这样会报错),aa[0] = 1(这样不会报错)
如果想让定义的对象或数组的内部数据也不能够修改和改变,可以使用object.freeze(aa)进行冻结,这样为对象添加新属性就不起作用。
函数的扩展
1、允许函数的参数设置默认值,通过等号 = 直接在小括号中给参数赋值。
2、引入 rest 参数,不定参数用来表示不确定参数个数,由 ... 加上一个具名参数标识符组成。
3、函数的 `name` 属性,可以用于返回该函数的函数名。
4、箭头函数主要的两点是:它的 `this` 指向是在它当时定义所在的区域,还一个是它没有一个作用域的提升。
- 函数体内的 `this` 对象指向的是定义时所在的对象,而不是使用时所在的对象。
- 不可以当作构造函数,也就是说不可以使用 `new` 命令。
- 不可以使用 `arguments` 对象,可以使用 `rest` 参数替代。
- 不可以使用 `yield` 命令,因此箭头函数不能用作 `Generator` 函数。
5、函数的length属性:返回没有指定默认值的参数个数
严格模式
函数内部可以设定为严格模式。'use strict';
1、在正常模式下,如果一个变量没有声明就赋值,默认是全局变量。严格模式下禁止这种写法,变量必须先声明,再使用。
2、不能随意删除已经声明好的变量
3、在严格模式下全局作用域中函数的 this 是 undefined。
4、以前构造函数不加 new 也可以调用,当普通函数,this 指向全局对象。
5、严格模式下,如果构造函数不加 new 调用,this 指向的是 undefined,如果给它赋值,会报错。
6、函数不能有重名的参数。
7、函数必须声明在顶层。因为块级作用域,不允许在非函数的代码块内声明函数。(不允许在 if判断 和 for循环 中声明函数)
数组的扩展
1、Array.from():将伪数组转换成真正的数组;可以接收第二个参数,用来对每个元素进行处理。
2、Array.of():将一组值(任意类型,可数组对象等)转换成数组。
3、find():返回符合条件的数组成员的第一个值;
4、findIndex():返回符合条件的第一个数组成员的索引
5、entries():对键值对遍历; keys():对键名遍历; values():对值遍历
6、includes():返回一个布尔值,表示某个数组是否包含给定的值
7:扩展运算符:该运算符主要用于函数调用。替代函数的 apply() 方法;
- 复制数组;合并数组;与结构赋值结合;将字符串转为真正的数组;
8、flat():将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。
对象的扩展
1、函数的name属性,返回函数名。对象方法也是函数,因此也有name属性。
2、属性的遍历
- for...in
- Object.keys(obj)
- Object.getOwnPropertyNames(obj):返回一个数组,包含对象自身的所有属性的键名。
- Reflect.ownKeys(obj)
3、super 关键字:指向当前对象的原型对象。
- 注意,`super`关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。
4、Object.is():比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
5、Object.assign():用于对象的合并;
- 第一个参数是目标对象,后面的参数都是源对象。
- 实行的是浅拷贝,而不是深拷贝
- Object.assign()可以用来处理数组,但是会把数组视为对象。
- 只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制。
6、Object.keys():返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
7、Object.values():返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
8、Object.entries():返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
9、Object.fromEntries():是Object.entries()的逆操作,用于将一个键值对数组转为对象。
10、Object.hasOwn():判断是否为自身的属性,可以接受两个参数,第一个是所要判断的对象,第二个是属性名
11、当对象键名与对应值名相等的时候,可以进行简写,方法也能够进行简写
symbol
1、表示独一无二的值。它属于 JavaScript 语言的原生数据类型之一,其他数据类型是:
undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
2、Symbol 值通过Symbol()函数生成
3、 symbol 类型的值可以作为对象的属性标识符使用
4、现在对象属性名可以为两种类型:一种就是原本的字符串类型,一种即为新增的 symbol 类型。
由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。
这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。
5、Symbol作为对象属性名时,不能用点运算符。因为点运算符是给对象添加一个属性,而不是像[变量名] 一样引用变量的值作为对象的属性。
6、在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。方括号中的属性名代表了Symbol值。
7、Symbol 值作为属性名时,该属性还是公开属性,不是私有属性。
8、Symbol()函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。
9、symbol值不能与其他类型的值进行运算
set和map
- set
set类似于数组,但是成员的值都是唯一的,没有重复的值。可以用于数组去重。
设置:set属性构造函数需要用new生成
Set.prototype.constructor:构造函数,默认就是Set函数
Set.prototype.size:返回Set实例的成员总数
Set.prototype.add():添加某个值返回Set结构本身
Set.prototype.delete():删除某个值,返回一个布尔值,表示删除是否成功
Set.prototype.has():返回一个布尔值,表示该值是否为Set的成员
Set.prototype.clear():清除所有成员,没有返回值
内容不可以重复,写入集合中的数据不会自动转换类型, 在set中相同的对象不相等,在set NaN是相等的
set可以用于数组去重
set中两个空对象,所代表的内存地址是不一样的,所以可以看成两个值
weakset . 与set类似,区别在于其值只能存储对象
- map
JavaScript对象object本质上是键值对的集合,Hash结构。它的缺陷是只能使用字符串作为键;
而map结构优化了这个缺陷,它提供了值-值对的形式,让键名不再局限于字符串,是一种更完整的Hash结构实现方式。
map中传入二维数组时会自动遍历。
Map.prototype.constructor:构造函数,默认就是Map函数
Map.prototype.size:返回Map实例的成员总数
Map.prototype.set(key, value):添加某个值返回Map结构本身
Map.prototype.get():get方法读取Key对应的键值,如果找不到key,返回undefined
Map.prototype.delete():删除某个值,返回一个布尔值,表示删除是否成功
Map.prototype.has():返回一个布尔值,表示该值是否为Map的成员
Map.prototype.clear():清除所有成员,没有返回值
因为map的键值可以是任意值,但是对象所表示的内存地址相同,所以表面上操作的是同一个map对象,但实际上却不是同一个map对象。
Map和Set的区别:
1、map是键值对,任何值都可以作为键值的值。
2、set是类数组数据,是值的集合。
3、map有get方法,可以通过get方法获取值,而set因为只有值,所以没有get方法
4、map和set都是stl中的关联容器,map以键值对的形式存储,key=value组成pair,是一组映射关系。
set只有值,可以认为只有一个数据,并且set中元素不可以重复且自动排序。
promise
Promise,译为承诺,是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大
优点:
链式操作减低了编码难度
代码可读性明显增强
状态:
promise对象仅有三种状态
pending(进行中)
fulfilled(已成功)
rejected(已失败)
特点:
对象的状态不受外界影响,只有异步操作的结果,可以决定当前是哪一种状态
一旦状态改变(从pending变为fulfilled和从pending变为rejected),就不会再变,任何时候都可以得到这个结果
用法:
Promise对象是一个构造函数,用来生成Promise实例
const promise = new Promise(function(resolve, reject) {});
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”
reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”
实例方法
then():
是实例状态发生改变时的回调函数,第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数
then方法返回的是一个新的Promise实例,也就是promise能链式书写的原因
catch():
是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数
Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止
一般来说,使用catch方法代替then()第二个参数
Promise对象抛出的错误不会传递到外层代码,即不会有任何反应
浏览器运行到这一行,会打印出错误提示ReferenceError: x is not defined,但是不会退出进程
catch()方法之中,还能再抛出错误,通过后面catch方法捕获到
finally()
用于指定不管 Promise 对象最后状态如何,都会执行的操作
Promise构造函数存在以下方法:
all()
用于将多个 Promise实例,包装成一个新的 Promise实例
const p = Promise.all([p1, p2, p3]);
只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数
只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数
race()
将多个 Promise 实例,包装成一个新的 Promise 实例
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变
率先改变的 Promise 实例的返回值则传递给p的回调函数
allSettled()
接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例
只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束
resolve()
将现有对象转为 Promise对象
reject()
会返回一个新的 Promise 实例,该实例的状态为rejected
异步解决方案
回调函数
所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,再调用这个函数
Promise
Promise就是为了解决回调地狱而产生的,将回调函数的嵌套,改成链式调用
generator
yield表达式可以暂停函数执行,next方法用于恢复函数执行,这使得Generator函数非常适合将异步任务同步化
Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
执行 Generator 函数会返回一个遍历器对象,可以依次遍历 Generator 函数内部的每一个状态
形式上,Generator函数是一个普通函数,但是有两个特征:
function关键字与函数名之间有一个星号
函数体内部使用yield表达式,定义不同的内部状态
async/await
将上面Generator函数改成async/await形式,更为简洁,语义化更强了
区别:
promise和async/await是专门用于处理异步操作的
Generator并不是为异步而设计出来的,它还有其他功能(对象迭代、控制输出、部署Interator接口...)
promise编写代码相比Generator、async更为复杂化,且可读性也稍差
Generator、async需要与promise对象搭配处理异步情况
async实质是Generator的语法糖,相当于会自动执行Generator函数
async使用上更为简洁,将异步代码以同步的形式进行编写,是处理异步编程的最终方案