ES 新特性
1.let、const关键字
let 关键字用来声明变量,使用 let 声明的变量有几个特点
- 不允许重复声明
- 块级作用域
- 不存在变量提升
- 不影响作用域链
const 关键字用来声明常量,const 声明有以下特点
- 声明必须赋初始值
- 标识符一般为大写
- 不允许重复声明
- 值不允许修改
- 块级作用域
注意:对象属性修改和数组元素变化不会触发 const 错误。
var、let、const的区别?
- var声明变量存在变量提升,let和const不存在变量提升
- let和const只能在块作用域里访问
- 同一作用域下let和const不能声明同名变量,而var可以
- const定义常量,而且不能修改,但是在定义的对象时对象属性值可以改变
2.变量的解构赋值
从数组和对象中提取值,对变量进行赋值,这被称为 解构赋值。
约等于python的赋值,但是要使用关键字。
比如:
const arr = ['red', 'green', 'blue']
let [r, g, b] = arr
3.新增Symbol
JavaScript 的七种基本数据类型
- 值类型(基本类型):number、boolean、string、undefined、null、symbol
- 引用数据类型:object(包括 array、function)
Symbol 的特点
- Symbol 的值是唯一的,用来解决命名冲突的问题
- Symbol 值不能与其他数据进行运算
- Symbol 定义的对象属性不能使用 for…in 循环遍历,但是可以使用 Reflect.ownKeys 来获取对象的所有键名
Symbol 的创建
- 创建 Symbol()创建
- 使用 Symbol.for() 方法创建,名字相同的 Symbol 具有相同的实体
- 输出 Symbol 变量的描述,使用 description 属性
4.模板字符串
模板字符串(template string)是增强版的字符串,用反引号 ` 标识,特点
- 可以使用 ${xxx} 形式输出变量,近似 EL 表达式
- 字符串中可以出现换行符
let name = 'cess'
console.log(`hello, ${name}`)
当遇到字符串与变量拼接的情况使用模板字符串
字符串新方法
includes()
判断字符串是否包含参数字符串,返回boolean值。startsWith()
/endsWith()
,判断字符串是否以参数字符串开头或结尾。返回boolean值。这两个方法可以有第二个参数,一个数字,表示开始查找的位置。repeat()
方法按指定次数返回一个新的字符串。padStart()
/padEnd()
,用参数字符串按给定长度从前面或后面补全字符串,返回新字符串。
5.rest参数
ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments,作用与 arguments 类似,将接收的参数序列转换为一个数组对象(arguments 是伪数组)
语法格式:fn(a, b, ...args)
,写在参数列表最后面
适用不定个数参数函数的场景
6.运算符
spread 扩展运算符
扩展运算符spread也是三个点...
,它好比 rest 参数的逆运算,将一个数组、伪数组转为用逗号分隔的参数序列,对数组进行解包,扩展运算符也可以将对象解包
可用在调用函数时,传递的实参,将一个数组转换为参数序列(与rest参数的区别,一个用在形参,一个实参)
可用于展开数组:把数组变成n个值。
可用于数组合并:let C = […A, …B],同理也可用于对象合并。
数组克隆,如果元素是引用类型的话,这种数组克隆属于浅拷贝:let arr2 = […arr1]
可选链 ?.
ES2020(ECMAScript 2020)中引入的一个特性,它允许你安全地访问对象的嵌套属性,而不必进行显式的检查。使用?.操作符,它允许你读取位于连接对象链深处的属性的值,而不必显式地检查链中的每一环是否有效。如果链中的某个环节是null或undefined,表达式短路返回undefined,并且不会继续向下访问。
函数绑定运算符::
在ES2020及之后的版本中也没有被正式采纳。这个运算符的目的是提供一个更简洁的方式来进行函数绑定,类似于Function.prototype.bind方法。
函数绑定运算符::的预期工作方式如下:
方法调用:::左边的值应该是一个对象,右边的函数是该对象的一个方法。这个运算符会将方法绑定到其所有者对象上,并返回一个新的函数。
指数运算符 **
在 ES7 中引入指数运算符 **
,用来实现幂运算,功能与 Math.pow(a, b)
结果相同
7.对象Object
对象简写
声明对象时的属性名与引用的变量名相同就可以省略
新增Map
它类似于对象,也是键值对的集合。但是 “键” 的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了 iterator 接口,所以可以使用扩展运算符 ...
和 for...of
进行遍历。
使用new Map()创建:
let mp1 = new Map();
mp1.set('aaa', 111);
mp1.set('bbb', 222);
mp1.set('ccc', 333);
let mp2 = new Map([
['aaa', 111],
['bbb', 222],
['ccc', 333]
]);
console.log(mp1['aaa']); // 111
console.log(mp2.get('bbb')); // 222
Map 的属性和方法:(k 为键,v为值)
- size:返回 Map 的元素(键值对)个数
- set(k, v):增加一个键值对,返回当前 Map
- get(k):返回键值对的键值
- has():检测 Map 中是否包含某个元素
- clear():清空集合,返回 undefined
新增Set
Set(集合),它类似于数组,但 成员的值都是唯一的,集合实现了 iterator 接口,所以可以使用扩展运算符 ...
和 for...of
进行遍历。
使用new Set() 创建。
let st1 = new Set()
let st2 = new Set([可迭代对象])
属性和方法
- st.size:返回集合个数
- st.add(item):往集合中添加一个新元素 item,返回当前集合
- st.delete(item):删除集合中的元素,返回 boolean 值
- st.has(item):检测集合中是否包含某个元素,返回 boolean 值
- st.clear():清空集合
- 集合转为数组:[…st]
- 合并两个集合:[…st1, …st2]
数组新方法
- Array.from()是内置对象Array的方法,实例数组不能调用:将可迭代对象转换为新的数组:函数可接受3个参数(后两个参数可以没有):第一个表示将被转换的可迭代对象(如果只有一个参数就是把形参转变成数组);第二个是回调函数,将对每个数组元素应用该回调函数,然后返回新的值到新数组;第三个是回调函数内this的指向。
- includes() 参数:数值 -------- 返回值:true/false;查看数组中是否存在这个元素,存在就返回true,不存在就返回false。
- map()、filter() 参数:函数-------- 返回值:数组:map() 要利用原数组经过运算后的数组;filter()方法是将符合挑选的筛选出来成为一个新数组,新数组不会影响旧数组。
- forEach() 参数:函数-------- 返回值:undefined:循环遍历数组中的每一项,没有返回值。
- find() 参数:函数-------- 返回值:数值:查找数组中符合条件的第一个元素,直接将这个元素返回出来。
- some()、every() 参数:函数-------- 返回值:true/false。some()找到一个符合条件的就返回true,所有都不符合返回false。every()方法是数组所有值都符合条件才会返回true,有一个不符合返回false。
object新方法
- Object.is()方法用来判断两个值是否为同一个值,返回一个布尔类型的值。(与
===
相同)
console.log(Object.is(NaN, NaN)); // true
console.log(NaN === NaN); // false
- Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象,并返回目标对象。对象的合并,相当于浅拷贝;属性相同,后面的会覆盖前面的。
- Object.keys() 返回对象所有属性
- Object.values() 返回对象所有属性值
- Object.entries() 返回多个数组,每个数组是 key–value(把每一个键值对都变成一个数组,key是一个值,value是一个值,如果嵌套对象,还会继续变数组。)
- Object.setPrototypeOf 用于设置对象的原型对象
- Object.getPrototypeof 用于获取对象的原型对象,相当于
__proto__
8.函数
参数默认值
ES6 允许给函数参数设置默认值,当调用函数时不给实参,则使用参数默认值
具有默认值的形参,一般要靠后。
箭头函数
箭头函数实现了一种更加简洁的书写方式。箭头函数内部没有arguments,也没有prototype属性,所以不能用new关键字调用箭头函数。
let fn = (param1, param2, …, paramN) => {
// 函数体
return expression;
}
- 如果形参只有一个,小括号可以省略
- 如果函数体只有一条语句,花括号可以省略,函数的返回值为该条语句的执行结果,如果是 return 语句,return 必须省略
- 箭头函数 this 是静态的,始终指向声明时所在作用域下 this 的值,call 等方法无法改变其指向
- 箭头函数适合与 this 无关的回调:定时器、数组的方法回调
- 箭头函数不能作为构造函数实例化
- 不能使用 arguments
9.class
- 通过class 关键字,可以定义类。基本上,ES6 的 class 可以看作一个语法糖。
class person {
//关键字声明方式
constructor(name) {
this.name=name
}
say() {
console.log("hello");
}
}
var p = new person('p');
- 类的继承通过extends关键字实现。
子类必须在constructor中调用super()
class SmartPhone extends Phone {
// 构造方法
constructor(brand, price, color, size){
super(brand, price); // Phone.call(this, brand, price)
this.color = color;
this.size = size;
}
photo() {
console.log("拍照");
}
// 子类重写父类方法,super.call()可以调父类方法
call() {
console.log('我可以进行视频通话');
}
}
3.函数对象的属性 方法是属于函数对象的,其创建的实例对象无法使用,这就是静态成员
class Phone{
//静态属性
static name = '手机';
static change() {
console.log("我可以改变世界");
}
}
let nokia = new Phone();
console.log(nokia.name); // undefined
console.log(Phone.name);
4.getter / setter: get 将对象属性绑定到 查询该属性时将被调用的函数;set是在修改某一属性时所给出的相关提示。
10.模块化
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来
模块化的优势有以下几点
- 防止命名冲突
- 代码复用
- 高维护性
模块功能主要由两个命令构成
export
命令用于规定模块的对外接口import
命令用于输入其他模块提供的功能
export:
分别暴露:
export let school = '尚硅谷';
export function teach() {
console.log("我们可以教给你开发技能");
}
统一暴露:
let school = '尚硅谷';
function findJob(){
console.log("我们可以帮助你找工作!!");
}
export {school, findJob}
默认暴露:
export default {
school: 'ATGUIGU',
change: function(){
console.log("我们可以改变你!!");
}
}
import:
// 通用导入
import * as m1 from './js/m1.js';
// 解构赋值导入
import {school, teach} from "./src/js/m1.js";
import {school as guigu, findJob} from "./src/js/m2.js";
import {default as m3} from "./src/js/m3.js";
// 简单,只适合默认暴露
import m3 from "./src/js/m3.js";
11.Iterator
迭代器Iterator是一种接口,为各种不同的数据结构提 供统一的访问机制。任何数据结构只要部署 Iterator 接口(在 js 中接口就是对象的一个属性),就可以完成遍历操作
- ES6 创造了一种新的遍历命令for…of循环,Iterator 接口主要供 for…of 消费
- for…in 取的是索引,for…of 取的是 value
- 原生具备 iterator 接口的数据(可用 for of 遍历)
Array、 Arguments、Set、Map、String、TypedArray、NodeList
使用 next() 方法遍历原生自带 iterator 接口的数据。
工作原理:
- 创建一个指针对象,指向当前数据结构的起始位置。
- 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员。
- 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员。
- 每调用 next 方法返回一个包含 value 和 done 属性的对象。
12.生成器函数
生成器函数是 ES6 提供的一种 异步编程解决方案。一般函数从开始运行到它结束之前,不会被任何事情打断,生成器(Generator)函数允许函数在执行过程中暂停和恢复执行。而生成器可以在执行当中暂停自身,可以立即恢复执行,也可以过一段时间之后恢复执行,所以生成器它不能像普通函数那样保证运行到完毕。生成器函数的特殊之处在于它们可以多次返回(yield)中间值,这是其他函数无法实现的。
生成器在每次 暂停/恢复 都提供了一个双向传递信息的功能,生成器可以返回一个值,恢复它的控制代码也可以接收一个值。
使用 function * generator()
和 yield
可以声明一个生成器函数,*
的位置随意。在生成器函数体内,可以使用 yield 表达式来暂停函数的执行,并返回一个值给生成器的调用者。
当调用一个生成器函数时,它并不立即执行函数体中的代码,而是返回一个特殊的迭代器对象,称为生成器对象。通过这个对象,你可以控制生成器函数的执行。调用的时候需要赋给iterator迭代器。
生成器对象符合迭代器协议,即它们有一个 next() 方法,用来恢复生成器函数的执行直到下一个 yield 表达式。每次调用 next() 方法时,生成器函数从上次 yield 的地方恢复执行,直到遇到下一个 yield。如果没有更多的 yield,函数执行结束,next() 返回一个 done: true 的对象。
生成器的 next() 方法还可以接受一个参数,该参数会成为生成器函数中对应 yield 表达式的返回值。
综上,就是生成器函数能实现函数执行过程中的暂停与恢复,通过function*
定义,在函数体中定义yield
来暂停执行和返回值给调用者。调用的时候它本身就是一个iterator,需要先赋值,然后使用next()函数调用,每次使用next()方法就会到一个yield地方,如果这时候给next()参数,参数值还会成为yield的返回值,这样在iterator函数内部还能接收值调整内容。最后执行结束会返回一个done: true 的对象。
13.Promise
【前端学习笔记】Javascript学习二(运算符、数组、函数)四。3
14.async与await
也在上面的那个链接里