1.1、什么是ES6
1995年的美国,有一家名为netscape(网景)的公司打造了一款主要用于check验证的脚本语言,而恰在此时,Sun公司的java语言火的一塌糊涂,netscape公司为蹭其热度,便将该脚本语言命名为 JavaScript。不料 JavaScript居然被越来越多的人使用,后效仿大秦的货币统一政策将其提交给国际标准组织ECMA。
该组织发布的标准被称做ECMAScript。 2015年6月发布的版本称为ECMAScript2015,简称ES6。从ES6开始,该组织每年会发布一个版本,版本号比年份最后一位大1,至今最新版本为ES12。
ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年发布的正式版本的语言标准
1.2、学前必知词汇
语法糖:又称糖衣语法,指不改变语言的本质功能,只是使编程变的更加简洁。而本课程后续所学习的很多ES6的新特性大多也都是由一粒粒语法糖所构成,所以ES6的一些新特性并不是真的“新”,只是试图简化语法而已。简言之:ES6是一大盒语法糖,解决了以前ES5很多难受的地方。
Babel:Babel是一个广泛使用的ES6转码器,可以将ES6代码转为ES5代码,从而在现有环境执行。这意味着,你可以用ES6的方式编写程序,又不用担心现有环境是否支持。相信未来浏览器会逐渐对其提供原生的支持。
1.3、为什么要学习ES6
ES5语言先天不足,通过学习ES6可以将其很多丑陋的部分进行隐藏。
包含了很多超棒的新特性,可以简化很多复杂的操作,从而大大提高开发效率。
为后面学习vue、react以及小程序做好充足准备。
目前大部分公司的项目都在使用ES6,它是前端发展的趋势,就业必备技能之一。
1.4 严格模式
1.4.1 介绍
ES5 除了正常运行模式(又称为混杂模式),还添加了第二种运行模式:“严格模式”(strict mode)。
严格模式顾名思义,就
是使 JavaScript 在更严格的语法条件下运行。
1.4.2 作用
消除 JavaScript 语法的一些不合理、不严谨之处,减少一些怪异行为
消除代码运行的一些不安全之处,保证代码运行的安全
为未来新版本的 JavaScript 做好铺垫
1.4.3 使用
在全局或函数的第一条语句定义为: 'use strict'
如果浏览器不支持,只解析为一条简单的语句, 没有任何副作用
1.4.4 语法和行为改变
必须用 var 声明变量,不允许使用未声明的变量
禁止自定义的函数中的 this 指向 window
创建 eval 作用域
对象不能有重名的属性(Chrome 已经修复了这个 Bug,IE 还会出现)
函数不能有重复的形参
新增一些保留字, 如: implements interface private protected public
使用call、apply传第一个参数为null或undefined时,this值不会跳转到全局对象
var obj = {
name: "张阳",
age:18,
like:[
"早上跑步",
"晚上复习",
"人帅有腹肌"
]
}
1.5.1 Object.keys(obj)
遍历obj 对象中的键 (key)
1.5.2 Object.values(obj)
遍历obj 对象的值 (value)
1.5.3 Object.create()
Object.create 方法可以以**指定对象为原型创建新的对象,同时可以为新的对象**设置属性, 并对属性进行描述
Object.create(proto, propertiesObject)
proto 指定的对象为原型
propertiesObject 设置新的属性
o2 = Object.create({}, {
p: {
value: 42,
writable: true,
enumerable: true,
configurable: true
}
});
value : 指定值
writable : 标识当前属性值是否是可修改的, 默认为 false
configurable:标识当前属性是否可以被删除 默认为 false
enumerable:标识当前属性是否能用for in 枚举 默认为 false
get: 当获取当前属性时的回调函数
set: 当设置当前属性时
Object.defineProperty(obj,“key”,{descriptors}) 只能写一个属性
get,set与value,writable不能同时存在
Object.defineProperty(obj,"age",{
value:18,
writable:true, //可编辑,默认为false
configurable:true,//可删除,默认为false
enumerable:true, //可遍历,默认为false
});
Object.defineProperty(obj,'name',{
get:function(){
return this._name || "今麦郎";
},
set:function(v){
this._name = v;
}
})
1.5.5 Object.defineProperties()
defineProperty复数形式
直接在一个对象上定义新的属性或修改现有属性,并返回该对象。
Object.defineProperties(object, descriptors)
object 要操作的对象
descriptors 属性描述
get 作为该属性的 getter 函数,如果没有 getter 则为undefined。函数返回值将被用作属性的值。
set 作为属性的 setter 函数,如果没有 setter 则为undefined。函数将仅接受参数赋值给该属性的新值。
var obj2 = Object.defineProperties(obj,{
name:{
value:'老王'
},
age:{
value:18
},
like:{
get:function(){
// return _like || [];
// 如果不写return
// 默认return undefined;
},
set:function(v){
_like = v;
}
}
});
1.6 call、apply 和 bind
call 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数
apply 方法调用一个具有给定 this 值的函数,以及作为一个数组(或类似数组对象)提供的参数
bind 同 call 相似,不过该方法会返回一个新的函数,而不会立即执行
2.1、let和块级作用域
2.1.1、ES5没有块级作用域
在ES5中,JS 的作用域分为全局作用域和局部作用域。通常是用函数区分的,函数内部属于局部作用域。
ES5只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景
内层变量可能会覆盖外层变量。
用来计数的循环变量泄露为全局变量。
2.1.2、块级作用域
在 ES6 中新增了块级作用域的概念,使用{}扩起来的区域叫做块级作用域
let关键字声明变量,实际上为 JavaScript 新增了块级作用域。
块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。
在块内使用let声明的变量,只会在当前的块内有效。
2.1.3、let关键字
ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效,也就是增加了块级作用域。
使用块级作用域(let定义的变量属于块级作用域) 防止全局变量污染
块级作用域可以任意嵌套
for循环的计数器,就很合适使用let命令
变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量
你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算
for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域
练习1
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6]();
* 练习2
```js
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6]();
2.1.4、let关键字特点
let命令不存在变量提升
和var不同的还有,let命令不存在变量提升,所以声明前调用变量,都会报错,这就涉及到一个概念——暂时性死区。
暂时性死区即:区块中存在let或const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
不允许重复声明
let 只能声明一次而var 可以声明多次。
块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式不再必要了
let 是在代码块内有效,var 是在全局范围内有效
不影响作用域链
let与var都拥有作用域链。
作用域链: 如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。
不再是顶层全局对象的属性
使用var定义的全局变量相当于直接挂载在window对象上, 而let不会。
2.2、const 关键字
注意:
变量:数据可以变化。在执行过程当中,有一些数据会使用多次,根据条件会变化,一般定义为变量。
常量:不会变化的数据,有些时候有的数据是不允许修改的,所以需要定义常量。
1
2
3
声明一定要赋初始值:一旦声明变量,就必须立即初始化,不能留到以后赋值
const 声明一个只读变量,声明之后不允许改变。意味着,一旦声明必须初始化,否则会报错。
值不允许修改
const 其实保证的不是变量的值不变,而是保证变量指向的内存地址不允许改动。所以 使用 const 定义的对象或者数组,其实是可变的。
const只在声明所在的块级作用域内有效。(与let相同)
const命令声明的常量也是不会提升(与let相同)
const不可重复声明(与let相同)
不再是顶层全局对象的属性(与let相同)
let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
const使用的两点建议:
1、被多次使用且不允许更改的数据建议通过const定义;
2、项目全局常量建议大写,单词之间用-分隔;
3、如果不清楚要使用let还是const,那么就用const。如果后面发生值的改变,那么再将const改成let.
4、以后不允许使用var
1
2.3 、块级作用域的函数声明
函数声明一般常用的是两种,一种是function声明,一种是函数表达式。
建议函数在顶层作用域和函数作用域之中声明,尽量避免在块级作用域声明。( "use strict"下报错)
如果确实需要,也应该写成函数表达式,而不是函数声明语句。
三、变量的解构赋值(重点)
3.1、什么是变量的解构赋值
解构 → 解析,重构。
解构的目标:数组以及对象。
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。
解构赋值本质就是赋值:把结构解散重构然后赋值。
解构赋值是对赋值运算符=的一种扩展。
在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。
3.2、引入
在ES5中,开发者们为了从对象和数组中获取特定数据并赋值给变量,编写了许多看起来同质化的代码 ;
3.3、解构赋值语法
解构的目标 = 解构源;(目标指的是定义的常量或变量,解析源一般指的是数组或对象)
解构目标:定义的常量或变量
解构源:待解构的数组或对象
3.4、对象解构赋值
对象解构赋值基本语法
对象的语法形式是在一个赋值操作符= 右边放置一个对象字面量
顺序不用一一对应
= 右侧可以是一个常或变量
嵌套对象解构
解构嵌套对象仍然与对象字面量的语法相似,可以将对象拆解以获取想要的信息
可忽略部分解构源的属性
剩余运算符
不完全解构:变量名称在对象中不存在
使用解构赋值表达式时,如果指定的变量名称在对象中不存在,那么这个变量会被赋值为undefined
解构默认值(常用)
当指定的属性不存在时,可以定义一个默认值:在属性名称后添加一个等号(=)和相应的默认值即可
为非同名局部变量赋值 ,可避免命名冲突
如果希望使用不同命名的局部变量来存储对象属性的值,ES6中的一个扩展语法可以满足需求,这个语法与完整的对象字面量属性初始化程序的很像。
* 函数传参数
解构赋值表达式的值与表达式右侧(也就是=右侧)的值相等,如此一来,在任何可以使用值的地方都可以使用解构赋值表达式
1
2
3
3.5、数组解构赋值
基本使用
与对象解构的语法相比,数组解构就简单多了,它使用的是数组字面量,且解构操作全部在数组内完成,而不是像对象字面量语法一样使用对象的命名属性 。
忽略元素
在解构模式中,可以直接省略元素,只为感兴趣的元素提供变量名 。
* 变量交换
1
数组解构语法还有一个独特的用例:交换两个变量的值。在排序算法中,值交换是一个非常常见的操作,如果要在ES5中交换两个变量的值,则须引入第三个临时变量
* 添加默认值
1
也可以在数组解构赋值表达式中为数组中的任意位置添加默认值,当指定位置的属性不存在或其值为undefined时使用默认值
嵌套数组解构
嵌套数组解构与嵌套对象解构的语法类似,在原有的数组模式中插入另一个数组模式,即可将解构过程深入到下一个层级
不定元素
函数具有不定参数,而在数组解构语法中有一个相似的概念——不定元素。在数组中,可以通过…语法将数组中的其余元素赋值给一个特定的变量
数组复制
在ES5中,开发者们经常使用concat()方法来克隆数组
3.6、混合解构(复杂解构)
混合使用对象解构和数组解构来创建更多复杂的表达式,可以从任何混杂着对象和数组的数据解构中提取想要的信息
面试题:
//复杂解构
let wangfei = {
name: '王菲',
age: 18,
songs: ['红豆', '流年', '暧昧', '传奇'],
history: [
{name: '窦唯'},
{name: '李亚鹏'},
{name: '谢霆锋'}
]
};
// console.log(userName,age,one,two,three,four,name,name2,name3);// 王菲 18 红豆 流年 暧昧 传奇 窦唯 李亚鹏 谢霆锋
3.7、 解构传递参数
解构赋值可以应用在函数参数的传递过程中。
如果调用函数时不传入参数或设置默认值,被解构的参数会导致程序抛出错误
可以为解构参数指定默认值
3.8、解构返回结果
函数的多个返回值获取
3.8、字符串解构(了解)
字符串也可以解构赋值。这是因为,字符串被转换成了一个类似数组的对象
3.9、数值和布尔值解构(了解)
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
四、spread运算符与rest参数
在ES6中, 三个点(…) 有2个含义。分别表示扩展运算符(spread运算符) 和 剩余运算符(spread运算符)
4.1、spread运算符
复制、合并数组
复制、合并对象
解构数组与对象
字符串转换为数组
伪数组转为真数组
4.2、rest参数
rest 参数(形式为...变量名),rest运算符用于获取函数调用时传入的参数。
和普通参数混合使用的时候,需要放在参数的最后
函数的length属性,不包括 rest 参数
五、数组的扩展
5.1 Array.from()
Array.from() 方法对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。不影响原数组
Array.from(arrayLike, mapFn, thisArg)
arrayLike 想要转换成数组的伪数组对象或可迭代对象
mapFn 可选 如果指定了该参数,新数组中的每个元素会执行该回调函数。让你可以在最后生成的数组上再执行一次 map 方法后再返回。
thisArg 可选 可选参数,执行回调函数 mapFn 时 this 对象。
let arr = [1,2,3];
let array = Array.from(arr);
console.log(arr === array); // output: false
console.log(Array.from([1, 2, 3], x => x + x)); // output: [2,4,6]
Array.of() 方法通过可变数量的参数创建一个新的 Array 实例,而不考虑参数的数量或类型。
Array.of(element0, element1, /* … ,*/ elementN)
Array.of(7); // [7] Array.of 与 Array() 的区别
Array(7); // array of 7 empty slots 一个参数表示长度为7,但是数组为空,7个空元素
copyWithin() 方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。
const array1 = ['a', 'b', 'c', 'd', 'e'];
console.log(array1.copyWithin(0, 3, 4)); // expected output: Array ["d", "b", "c", "d", "e"]
console.log(array1.copyWithin(1, 3)); // expected output: Array ["d", "d", "e", "d", "e"]
copyWithin(target, start, end)
target 复制序列到该位置。默认为0,值大于数组长度不会发生拷贝,负数从末尾开始。
start 开始复制元素的起始位置。默认为0,负数将从末尾开始计算。
end copyWithin 将会拷贝到该位置,但不包括 end 这个位置的元素。负数从末尾开始计算。默认会复制到数组的末尾。
5.4 fill
fill() 方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。
const array1 = [1, 2, 3, 4];
console.log(array1.fill(0, 2, 4)); // expected output: [1, 2, 0, 0]
console.log(array1.fill(5, 1)); // expected output: [1, 5, 5, 5]
console.log(array1.fill(6)); // expected output: [6, 6, 6, 6]
fill(value, start, end) value:填充值 start:起始索引,默认为0 end:终止索引,默认为数组的结尾
5.5 entries()
**Object.entries()**方法返回一个给定对象自身可枚举属性的键值对数组 Object.entries(obj)
let arr = ['one','two','three','four','five'];
for(let [key,val] of arr.entries()) { // 可能由于包装类
console.log(key,val); // output: 1 'one' 2 'two' 3 'three' 4 'four' 5 'five'
}
Object.keys() 方法会返回一个由一个给定对象的自身 可枚举属性组成的 数组 , 有包装类,数组实例可以使用。
for (let key of arr.keys()) {
console.log(key);
}
Object.values() 方法会返回一个由一个给定对象的自身 可枚举属性组成的 数组 , 有包装类,数组实例可以使用。
for (let key of arr.values()) {
console.log(key);
}
find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
let arr = ['one', 'two', 'three', 'four'];
let result = arr.find(item => item === 'four');
console.log(result); // output: four
find(function(item, index, array) { /* … */ }, thisArg) item: 当前元素 index:当前索引 array:原数组 thisArg: 执行回调时用作 this 的对象。
5.9 findIndex
find() 方法返回数组中满足提供的测试函数的第一个元素的索引。没有找到相应的元素返回 -1
let arr = ['one', 'two', 'three', 'four'];
let result = arr.findIndex(item => item === 'four');
console.log(result); // output: 3
findIndex(function(item, index, array) { /* … */ }, thisArg) item: 当前元素 index:当前索引 array:原数组 thisArg: 执行回调时用作 this 的对象。
5.10 includes()
includes() 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回 false。
let arr = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5];
let array = [];
arr.forEach((item,index) => array.includes(item) ? '' : array[array.length] = item)
console.log(array); // [1,2,3,4,5]
includes ( searchElement, fromIndex ) searchElement: 需要查找的元素值。 fromIndex: 从什么位置开始查找
5.11 flat()
flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。对原数组没有影响。
const arr1 = [0, 1, 2, [3, 4]];
console.log(arr1.flat()); // expected output: [0, 1, 2, 3, 4]
const arr2 = [0, 1, 2, [[[3, 4]]]];
console.log(arr2.flat(2)); // expected output: [0, 1, 2, [3, 4]]
flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1
如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数
六、函数的扩展
6.1、 函数参数默认值
6.1.1、ES5默认参数
ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
6.1.2、ES6 默认参数
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。
6.2 箭头函数(非常重要)
6.2.1、什么是箭头函数
ES6 允许使用“箭头”(=>)定义函数。
6.2.2、箭头函数的写法
箭头函数分为以下几种情况
只有一个参数 并函数体是一句话的时候
没有参数或者多个参数的时候,参数的括号不能省略
当函数体不是一句话的时候,花括号 不可以省略
如果函数体内只有一行代码,该行代码返回的是对象的话,可以使用括号。
6.23、箭头函数的使用场景
定时器回调改写
map方法回调改写
6.2.3、箭头函数的注意事项
关于this
箭头函数没有自己的this,箭头函数内部的this并不是调用时候指向的对象,而是定义时指向的对象
箭头函数不能用于构造函数,也就是不能使用new关键字调用
箭头函数没有arguments对象
箭头函数使用call apply bind无法改变this指向
七、对象的扩展
7.1、对象的简写
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
7.2 、属性名表达式
JavaScript 定义对象的属性,有两种方法:点运算符和中括号运算符
但是,如果使用字面量方式定义对象(使用大括号),在 ES5 中只能使用标识符,而不能使用变量定义属性。
也就是说在ES5中 key/value key是固定不变的,在ES6中,支持属性表达式,支持key发生变化
7.3、 对象的扩展运算符 …(见4.1)
7.4 对象新增的方法
7.4.1、Object.is(v1,v2)
Object.is() 方法判断两个值是否为同一个值
Object.is(NaN,NaN); // true 解决了NaN不等于NaN的问题
console.log(NaN === NaN); // false
Object.is(value1, value2); 被比较的第一个值。 value2 被比较的第二个值
Object.assign() 方法将所有可枚举的自有属性从一个或多个源对象复制到目标对象,返回修改后的对象。
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target); // output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget === target); // output: true
Object.assign(target, …sources) target 拷贝后返回的新对象 sources 源对象,包含将被合并的属性。
7.4.3 Object.keys()
Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组 , 有包装类,数组实例可以使用。
let obj = {
name:'ling',
age:16
}
console.log(Object.keys(obj)) // output: [name,age]
Object.values() 方法会返回一个由一个给定对象的自身 可枚举属性组成的 数组 , 有包装类,数组实例可以使用。
let obj = {
name:'ling',
age:16
}
console.log(Object.values(obj)) // output: ['ling',16]
八、Math的扩展(了解)
8.1、指数运算符
在Math中提供了 pow的方法 用来计算一个值的n次方
ES11 提出了新的方法求一个值的n次方 那就是 ** 操作符
8.2、进制写法
ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b和0o表示。
8.3、Math的新增方法
Math.trunc()方法会将数字的小数部分去掉,只保留整数部分
Math.sign() 判断一个数字的正数还是负数 还是0 或者是NaN
Math.sqrt()平方根
Math.cbrt()立方根
Math.hypot() 求所有参数平方和的平方根
九、Number的扩展(了解)
Number.isFinite(i) : 用来检查一个数值是否为有限
Number.isNaN(i) : 判断是否是NaN
Number.isInteger(i) : 判断是否是整数
Number.parseInt(str) : 将字符串转换为对应的数值
十、新增数据类型(了解)
10.1、Symbol
10.1.1、什么是Symbol
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法,新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是ES6引入Symbol的原因。
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型
10.1.2、Symbol的使用
Symbol 值通过Symbol函数生成。
这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突
10.1.3、Symbol表示独一无二的值
>使用 `Symbol.for`("尚硅谷") 通过相同参数设置相同值
1
10.1.4、Symbol的注意事项
Symbol中传入的字符串没有任何意义,只是用来描述Symbol
Symbol不能使用New调用
类型转换的时候,不能转数字
如果把Symbol当作一个对象的属性和方法的时候,一定要用一个变量来储存,否则定义的属性和方法没有办法使用
for in 不能遍历出来,可以使用Object.getOwnPropertySymbols方法来拿;
10.2、BigInt
JavaScript 所有数字都保存成 64 位浮点数,这给数值的表示带来了两大限制。一是数值的精度只能到 53 个二进制位(相当于 16 个十进制位),大于这个范围的整数,JavaScript 是无法精确表示的,这使得 JavaScript 不适合进行科学和金融方面的精确计算。二是大于或等于2的1024次方的数值,JavaScript 无法表示,会返回Infinity。
引入了一种新的数据类型 BigInt(大整数),来解决这个问题。BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。
为了与 Number 类型区别,BigInt 类型的数据必须添加后缀n。
BigInt 与普通整数是两种值,它们之间并不全等。
typeof运算符对于 BigInt 类型的数据返回bigint。
Bigint类型与Number类型互相转换
十一、新增数据结构(了解)
11.1、Set
11.1.1、什么是Set
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成 Set 数据结构。
Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化
利用set对象,实现数组去重
11.1.2、 Set的属性及方法
size 返回Set的长度
add 添加某个值,返回 Set 结构本身。
delete 删除某个值,返回一个布尔值,表示删除是否成功。
has 返回一个布尔值,表示该值是否为Set的成员
clear 清除所有成员,没有返回值。
keys():返回键名的遍历器,由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。
values():返回键值的遍历器
entries():返回键值对的遍历器
forEach():使用回调函数遍历每个成员
11.1.3、Set的其他使用
- 求两数组去重后的交集
- 求两数组去重后的并集
- 求两数组去重后的差集
1
2
3
11.2、Map
11.2.1、什么是Map
JavaScript 的对象(Object),本质上是键值对的集合,但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
10.2.2、Map的属性和方法
size属性返回 Map 结构的成员总数。
set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。set方法返回的是当前的Map对象,因此可以采用链式写法。
get方法读取key对应的键值,如果找不到key,返回undefined。
has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
delete方法删除某个键,返回true。如果删除失败,返回false。
clear方法清除所有成员,没有返回值。
keys():返回键名的遍历器。
values():返回键值的遍历器。
entries():返回所有成员的遍历器。
forEach():遍历 Map 的所有成员。
十二、iterator(了解)
12.1、什么是iterator
JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了Map和Set。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。
遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。
12.2、iterator
在ES6中,只要一种数据结构具有了Symbol.iterator属性,那么就认为是可以迭代的
在ES6中,很多数据结构都部署了iterator接口(Array,set,Map,string)
应用场景:
解构赋值的时候默认调用iterator接口
扩展运算符使用的时候页默认调用iterator接口
for of 使用的是iterator接口
对象是没有部署Iterator接口
案例:将对象中的两个数组使用for…of进行遍历