ES6+知识点总结
前言
本文主要介绍的是ES6以及更新的JavaScript脚本语言标准规范的使用。主要是对相关知识点的自我认知和理解,如有不对的地方,望指出并探讨
一、变量的声明
1.let关键字
通过let关键字声明变量
let dzw = "大张伟";
let关键字声明的变量的特点:
- 没有声明提前(无建立阶段),不存在变量提升
- 有区域性,形成块级作用域
- 自动形成闭包
- 同一个作用域内,不能定义重复变量
- 不影响作用域链
- 存在暂时性死区:不能在声明之前,使用该变量(使用let声明的变量名,在let声明之前的使用,都是暂时性死区)
- 不会挂载到全局对象
- 相对const而言,let可以不用必须赋初始值
var关键字声明的变量特点
- 声明提前(有建立阶段),存在变量提升,(即是定义之前可以使用)
- 没有区域性,无法形成块级作用域
- 可以重估声明变量
- window环境下,使用var,会将该变量挂载到window对象上
1.let经典应用理解
- 循环中使用异步函数
var关键字
for (var i = 1; i <= 10; i++) {
console.log(i, "outer"); // 1 - 10
setTimeout(function () {
console.log(i, "inner"); // 10 个 11
}, i * 500);
}
分析:
var i = 1,首先是不会形成局部作用域的,而且会将i变量的声明提升至for循环体的外面,这里会挂载到window对象下,同步逻辑代码for循环执行完后 ,再执行 setTimeout异步代码,此时在setTimeout异步里面,存在变量i,但没有声明,所以会向父级作用域链查找,找到了window.i = 10++; 所以会打印10个11
使用IIFE,立即执行函数解决这个问题
for (var i = 1; i <= 10; i++) {
setTimeout((function (j) {
return function() {
console.log(j);
}
})(i), i * 500);
}
分析:
这里会把每次循环的变量i,传到setTimeout的回调函数里,使用闭包的方式,进行变量的保存,当然会存在闭包的缺点,比如变量无法销毁,导致内存的泄露
使用let关键字解决这个问题
for (let i = 1; i <= 10; i++) {
console.log(i, "outer"); // 1 - 10
setTimeout(function () {
console.log(i, "inner"); // 1-10
}, i * 500);
}
分析:
let i = 1; 不存在变量声明提升,而且会形成局部作用域{},将当前循环的变量保存到当前的作用域下;每次迭代都形成一个具有新的初始化let i的局部作用域,且每个let i 互不影响。之后的每一个初始化的i值,都是上一次迭代的i的结果,因此在同步for代码执行完后,再执行setTimeout,会在当前局部作用域下,找到之前保存的初始化的i变量值。 因为变量i的持久保存(遇到每个作用域的 } ,let销毁,作用域销毁),所以let会自动形成闭包
二、常量的声明
1.const关键字
通过const关键字声明常量
const DZW = "大张伟";
const定义的常量的特点:
- 有区域性,会形成局部作用域/ 块级作用于
- 常量的栈值不能修改 【只能锁住基本数据类型】
- 无建立阶段,(不存在声明提前)
- 必须赋初始值,(与let的不同)
- 锁栈不锁堆,(基本类型不能更改,但是引用类型的属性还是可以更改的`
- 常量名一般的 需要全部大写
锁栈不锁堆的扩展:
使用Object.freeze(obj); 可以锁住对象(锁堆)
const DZW = {
age : 18
};
Object.freeze(DZW);
DZW.age = 35; // DZW 这个对象被冻结,其内部属性更改失败
console.log(DAW.age) // 18
三、扩展运算符:…
… 扩展运算符将数组转化为 逗号分隔的实参参数序列: test(…arr)
应用一:使用扩展运算符实现数组的合并
let xing = ["大"];
let ming = ["张伟"];
let dzw = [...xing, ...ming]; // ["大","张伟"]
应用二:数组克隆: 浅拷贝
let dzw = ["大","张伟"];
let _dzw = [...dzw];
console.log(_dzw);
应用三:类数组转数组
function add() {
// 类数组 Array.isArray(arguments)
console.log(arguments, Array.isArray(arguments)); // [Arguments] { '0': 1, '1': 2, '2': 3 } false
let _argu = [...arguments];
console.log(_argu, Array.isArray(_argu)); // [ 1, 2, 3 ] true
}
add(1, 2, 3);
应用三:求数组中的最大值
var arr = [1,3,5,7,2,9,8];
// var max = Math.max(1, 3, 5, 7, 2, 9, 8);
// var max = Math.max.apply(Math,arr); //apply所接收的参数是一个数组
var max = Math.max(...arr);
四、解构赋值
1、数组的解构赋值
let arr = ['篮球', 'music'];
let [ball, other] = arr; // ball = '篮球' other = 'music'
2、对象的解构赋值
let zhw = {
name: 'zhw'
age: 18,
say(){
console.log('hello')
}
}
let { say } = zhw;
say() // 'hello’
五、模板字符串
模板字符串使用 `` 反引号
特性:
- 字符串内容可以直接换行
- 可以使用${}拼接变量
六、箭头函数
const test = (a, b) => {
return a + b
}
const sum = test(1, 2)
console.log(sum) // 3
特性:
- this是静态的。 this始终指向函数声明时, 所在作用域下的this。即箭头函数的this指向箭头函数的外层。静态的是指: call、apply、bind不能改变箭头函数的this指向
- 不能作为构造函数实例化对象【无构造器】
- 不能使用保存实参的 arguments 变量
- 简写:形参有且只有一个,省略形参的() ; 代码体只有一条语句,省略代码体的{} 和return 关键字
使用场景:箭头函数适合与this无关的回调,比如
- 定时器
- 数组的方法回调
不适用场景:箭头函数不适合与this有关的回调,比如
- DOM等事件回调 【dom事件如果使用箭头函数,那么this指向的不再是DOM事件源】
- 对象的方法
七、rest参数【ES6只针对数组,ES9中rest和…可以处理对象了】
ES6引入rest参数, 用于获取函数的实参,用来代替 arguments
1. es5中收集实参
function test() {
// arguments收集到的实参是一个包裹了1, 2, 3, 4, 5的类数组,本质是一个对象
console.log(arguments)
}
test(1, 2, 3, 4, 5)
可以通过以下方法将类数组arguments 转化为数组
- const array = Array.from(arguments);
- const array = Array.prototype.slice.call(arguments)
- const array = […arguments];
2. es6中收集实参
function test(...args) {
// 收集的实参args是一个数组
console.log(args);
}
注意:rest参数必须放在所有形参的最后, 否则会报语法错误
function test(a, b, ...args) {
console.log(a); // 1
console.log(b); // 2
// 收集的实参args是一个数组
console.log(args); // [3, 4, 5]
}
test(1, 2, 3, 4, 5)
3、ES9:rest参数和…针对对象
function test(a, b, {...args}) {
console.log(a); // 1
console.log(b); // 2
// 收集的实参args是一个数组
console.log(args); // [3, 4, 5]
}
test(1, 2, {name: 'zhw'})
八、Symbol
一种新的基本数据类型
1. 特点
- Symbol的值是唯一的,且不可见。
- Symbol的值不能与其他数据进行运算
- Symbol定义的对象属性不能使用for…in,但可以使用Reflect.ownKeys获取所有键名
2. symbol类型的数据创建
let s = Symbol();
// let s2 = Symbol('当前symbol的描述信息')
let s2 = Symbol('desc')
let s3 = Symbol('desc')
console.log(s2 === s3) // false
// 对象方法创建symbol类型
let s4 = Symbol.for('desc')
let s5 = Symbol.for('desc')
console.log(s4 === s5) // true
3. symbol类型数据的作用:
用来解决命名冲突的问题,
4. 应用
给对象添加属性和方法, 避免别人覆盖属性
痛点:
// 假设这是别人写的对象, 我们并不知道对象里具体有哪些属性
let zhw = {
name: '呵呵'
}
// 需要给对象zhw添加name属性
zhw.name = xxx // 这样给对象添加属性是不安全的
解决: 使用Symbol()定义需要添加的属性
let needAddProps = {
name: Symbol()
}
// 这样使用不会破坏原对象的数据结构
zhw[needAddProps.name] = xxx
其他方法向对象添加Symbol类型的属性
let zhw = {
name: '呵呵',
[Symbol('say')]: function() {
console.log('hello')
}
}
5. Symbol的内置属性
Symbol有自己的一些内置属性, 这些属性都是用来控制 对象在特定情况下的表现, 例如
Sysbol.isConcatSpreadable
控制数组是否可以展开
let arr = [1, 2, 3]
let arr2 = [4, 5, 6]
console.log(arr.concat(arr2)) // [1, 2, 3, 4, 5, 6]
// 禁止arr2数组展开
arr2[Sysbol.isConcatSpreadable] = false
console.log(arr.concat(arr2)) // [1, 2, 3, [4, 5, 6]]
6、description: 获取Symbol的描述信息
let s = Symbol('zhw')
console.log(s.description);
九、迭代器
迭代器(Iterator)是一种接口,为不同的数据结构提供统一的访问机制。
js中,迭代器的本质是 对象属性
1、原生js具备Iterator接口的数据
- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
注意:只要部署了Iterator接口,就可以使用ES6提供的for…of命令遍历
2、迭代器的工作原理
- 创建了一个指针对象iterator,指向了数据结构的起始位置 【let iterator = objSymbol.iterator】
- 第一次调用对象的next方法,指针自动指向数据结构的第一个成员 【iterator.next()】
- 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
- 每次调用next方法,都会返回一个包含value和done属性的对象
3、迭代器的应用:自定义遍历数据
let zhw = {
name: '呵呵'
hobbies: [
'篮球',
'rap'
]
}
// 报错: zhw对象无iterator
for(let item of zhw) {
}
给对象加入迭代器
let zhw = {
name: '呵呵'
hobbies: [
'篮球',
'rap'
],
[Symbol.iterator]() {
let index = 0
// 返回一个指针对象
return {
next: () => {
if(index < this.hobbies.length) {
const result = {value: this.hobbies[index], done: false)
index++
return result
} else {
return {value: undefined, done: true}
}
}
}
}
}
十、生成器: ES6的异步编程解决方案1
生成器本质是一个函数。 生成器的返回结果其实是一个迭代器对象,因为具有next方法
1、作用
- 一种异步编程的解决方法: 解决原生js的纯回调函数,造成的回调地狱问题
2、语法
- 迭代器函数的声明
// * 位置可左可右可中间
function * gen() {
console.log('hello')
}
- 迭代器函数的调用
let iterator = gen();
// 迭代器函数的调用语句,执行生成器函数体的语句
iterator.next() // 返回结果是yield对应的值
3、yield
生成器函数代码体的分隔符
n个yield,将代码体分割成n + 1块
function * gen() {
console.log(111)
yield '分隔符1';
console.log(222)
yield '分隔符2';
console.log(333)
yield '分隔符3';
console.log(444)
}
for (const iterator of gen()) {
console.log(iterator);
console.log('======')
}
4、生成器函数的参数
- 生成器函数的参数
function * gen(arg) {
console.log(arg)
}
let iterator = gen('生成器函数的参数')
iterator.next() // 执行了 console.log(arg)
- 生成器返回的迭代器对象的next方法参数
第n个yield的返回值,保存着第n + 1个的next方法参数
function * gen() {
console.log('代码块1')
let one = yield 111;
console.log(one, 'zhw');
console.log('代码块2')
}
let iterator = gen()
iterator.next()
iterator.next('第2个next的参数')
next传多个参数 用数组: Generator<number, void, unknown>.next(…args: [] | [unknown]): IteratorResult<number, void>
function * gen() {
console.log('代码块1')
let one = yield 111;
console.log(one);
console.log('代码块2')
}
let iterator = gen()
iterator.next()
iterator.next(['第2个next的参数', 'zhw'])
5、生成器函数的应用:
例如: 1s后打印111,2秒后打印222, 3秒后打印333
- 原生js的实现
setTimeout(function(){
console.log(111)
setTimeout(function(){
console.log(222)
setTimeout(function(){
console.log(333)
}, 3000)
}, 2000)
}, 1000)
缺点:多层回调嵌套造成了 地狱回调【一种回调现象】,不便于阅读和维护代码
- 生成器解决回调地狱问题
function one(timer, num) {
setTimeout(() => {
console.log(num);
// 第二次调用next 可以通过第一个yield获取参数数据
iterator.next('one')
}, timer);
}
function two(timer, num) {
setTimeout(() => {
console.log(num);
// 第三次next 此时会调用: yield three(3000, 333)
// 不过第三次的next参数 是传递给第二个yield的返回值的
iterator.next('two')
}, timer);
}
function three(timer, num) {
setTimeout(() => {
console.log(num);
iterator.next('three')
}, timer);
}
function * gen() {
let resOne = yield one(1000, 111);
console.log(resOne);
let resTwo = yield two(2000, 222);
// 第三次yield的参数
console.log(resTwo);
const resThree = yield three(3000, 333);
console.log(resThree);
}
let iterator = gen()
// 第一次调用next
iterator.next()
十一、Promise: ES6的异步编程解决方案2
Promise本质是一个构造函数。 是ES6引入的异步编程的一种解决方案,主要是用来解决原生js造成的回调地狱现象
1、基本语法
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('111')
// reject('err')
}, 500)
})
p.then((res)=>{
console.log(res); // 111
}, (err)=>{
console.log(err); // err
})
p,catch(err=>{
console.log(err); // err
})
p.then(成功的回到, 失败的回调)
2、关于then的返回值
p.then()的返回值始终是一个Promise。具体状态(PromiseState),由回调参数的返回值决定,规则如下
- 1、没有return(即是返回undefined) / 返回非Promise的值 状态为:fulfilled
- 2、return返回Promise对象: 状态和返回的Promise状态保持一致
let p = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('111')
reject('err')
}, 500)
})
// p.then()的返回值始终是一个Promise。具体状态(PromiseState),由回调参数的返回值决定,规则如下
// 1、没有return(即是返回undefined) / 返回非Promise的值 状态为:fulfilled
// 2、return返回Promise对象: 状态和返回的Promise状态保持一致
let res = p.then((res)=>{
console.log(res); // 111
// resolve('111') 触发return
}, (err)=>{
console.log(err); // err
// reject('err') 触发return
return new Promise((resolve, reject) => {
resolve('res')
})
})
console.log(res, 'res'); // PromiseState: fulfilled, PromiseResult: 'eee'
3、解决异步回调
需求: 1s后打印111,2秒后打印222, 3秒后打印333
- 通过then方法的链式语法
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 1000)
})
p.then((res)=>{ // 这个res是p对象的Promise的执行结果
console.log(res);
return new Promise((resolve, reject) => {
setTimeout(()=>{
resolve(222)
}, 2000)
})
}).then(res=>{ // 这个res是上一个回调参数的 promise执行结果
console.log(res);
return new Promise((resolve, reject) => {
setTimeout(()=>{
resolve(333)
}, 3000)
})
}).then(res => { // 这个res是上一个回调参数的 promise执行结果
console.log(res);
})
4、处理Promise对象数组
- Promise.allSettled: 每个Promise都能得到结果时
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('111')
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('222')
}, 2000)
})
// PromiseState: 始终是fulfilled
// PromiseResult[]:
// [{status: 'fulfilled', reason: '111'} , {status: 'rejected', reason: '111'}]
const res = Promise.allSettled([p1, p2])
console.log(res);
- Promise.all: 每个Promise都能得到resolve结果时, 如果一个是resolve,另一个是reject,则是在pending中;如果两个都是reject,则结果状态时rejected,值是第一个Promise元素的值
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('111')
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('222')
}, 2000)
})
// PromiseState: fulfilled
// PromiseResult[]:
// ['111', '222']
const res = Promise.all([p1, p2])
console.log(res);
ES8之async和 await: 【第三种异步解决方案】
async 和 await 结合可以让异步代码 像同步一样执行
1、async函数
- async函数的返回值为promise对象, 返回值promise的具体状态,如下:
async function fn() {
// 1. 返回 非 Promise对象时, fn()的返回状态为: fulfilled
// return 'zhw'
// 2. 抛出一个错误时, fn()的返回状态为: rejected
// throw new Error('error')
// 3. 返回一个Promise对象时, fn()的返回状态 由 return 的 Promise状态决定
return new Promise((resolve, reject) => {
// resolve('data')
reject('error')
})
}
// res为一个Promise对象, 所以可以使用then()
let res = fn()
console.log(res);
- async函数可以没有await 表达式
2、await 表达式
- await 必须写在async函数中
- await 右侧的表达式一般为 promise对象
- await始终返回promise成功的值
- await的promise失败了, 需要使用try…catch 捕获处理异常
3、第三种异步解决案例,【async + await】
1s后打印111,2秒后打印222, 3秒后打印333
function one() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 1000)
})
}
function two() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222);
}, 2000)
})
}
function three() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(333);
}, 3000)
})
}
async function test() {
let _one = await one();
console.log(_one)
let _two = await two();
console.log(_two)
let _three = await three();
console.log(_three)
}
test()
十二、Set集合
集合:ES6提供的一种数据集合。类似于数组,但不是数组。本质是一个对象【typeof new Set === ‘object’】。成员都是唯一的。Set实现了迭代器接口,所以可以使用扩展运算符…和for…of
1、Set集合对象的属性和方法
- size: 集合元素的个数
- add() 增加一个新元素,返回当前集合
- delete() 删除元素 返回boolean值
- has() 检测集合中是否包含某个元素, 返回boolean
- clear() 清空当前集合对象
let arr = [1, 2, 3, 4, 2, 1]
let s = new Set(arr)
console.log(typeof s); // 'object'
console.log(s.size); // Set对象个数
// let s2 = s.add(5)
// console.log(s === s2); // true: Set(5) {1, 2, 3, 4, 5}
// let flag = s.delete(1)
// console.log(s); // Set(5) {2, 3, 4}
console.log(s.has(1));
s.clear()
console.log(s);
let arr = [1, 2, 3, 4, 2, 1]
let s = new Set(arr)
for (const item of s) {
console.log(item); // 1, 2, 3, 4
}
2、Set集合的应用
- 数组去重
let arr = [1, 2, 3, 4, 2, 1]
let s = new Set(arr) // 类数组 Set自带去重
let sArr = [...s] // 类数组转数组
console.log(sArr);
十三、Map
ES6提供的新的数据结构。Map数据结构是一种用于存储键值对的数据结构,是一种升级版的对象,即对象的key不限于字符串,key可以是各种类型,Map中的键是唯一的。实现了迭代器接口,可以用扩展运算符…和for…of进行遍历
1、Map的属性和方法
- size: 返回Map的元素个数
- set: 新增一个新的元素,放回当前Map
- get: 根据键名获取键值
- has: 检测Map是否包含某个元素
- clear: 清空集合, 返回undefined
let obj = {name: 'zhw'}
let m = new Map()
m.set('name', 'zhw')
m.set('age', 18) // 被覆盖
m.set('age', 22) // Map的键是唯一的 下面会覆盖上面的
m.set('say', () => {console.log('i say');})
m.set(obj, 'zhw?')
// console.log(m); // 0: {"name" => "zhw"}
// for (const item of m) {
// // 每一项是一个数组[key, value]
// console.log(item); // ['name', 'zhw']
// }
let arr = [...m]
console.log(arr); // [Array(2), Array(2), Array(2)] ['name', 'zhw']
console.log(m.get('name'));
console.log(m.get(obj));
console.log(m.has('age'))
// m.clear()
console.log(m.clear()) // undefined
2、Map转对象
// 二维数组 转对象
const result = Object.fromEntries([
['name', 'zhw'],
['age', 18]
])
console.log(result);
const m = new Map()
m.set('name', 'zhw')
// Map就是一个二维数组
const result2 = Object.fromEntries(m)
console.log(result2);
十四、class类
这里的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法
1、实例化一个基本对象
- 原生js
function Person(name, age) {
// new Person() 就会执行这里的代码体
this.name = name || 'zhw';
this.age = age;
// console.log(this);
}
Person.prototype.say = function() {
console.log('i say');
}
// 构造函数的静态属性
Person.p = 'Peron对象上的属性p' // Peron对象上的属性:会挂载到实例化对象的原型上
Person.prototype.test = 'Person原型上的属性test' // Person原型上的属性, 会呗实例化对象直接访问到
let zhw = new Person('zhw', 22)
// zhw.__proto__.constructor === Person
// console.log(zhw.__proto__.constructor === Person); // true
console.log(zhw.test);
console.log(zhw.__proto__ === Person.prototype); // true
- class类
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
// 类似原生的Person.p
// 静态属性属于类/或者构造函数, 不属于实例对象
static p = 'Peron对象上的静态属性p'
// 类的非静态属性
test = 'Person原型上的属性test' // 和构造方法里面的属性同级
// Person.prototype.say的简化
// 这块必须是ES6的简介方法,不能出现function关键字的完整写法
say() {
console.log('i say');
}
}
let zhw = new Person('zhw', 19)
// zhw.say()
// console.log(zhw, 'zhw');
// 访问类的静态属性
// console.log(zhw.__proto__.constructor === Person); // true
// console.log(Person.p);
console.log(zhw.test);
2、关于继承
ES5原生 构造函数实现继承
// 父构造方法
// 手机
function Phone(color, price) {
this.color = color;
this.price = price;
}
Phone.prototype.call = function() {
console.log('打电话');
}
// 子构造方法
// 智能手机
function SmartPhone(color, price, size) {
// this指向SmartPhone
Phone.call(this, color, price); // 类似super()
this.size = size
}
// 设置子构造函数的原型
// SmartPhone的原型指向了父构造函数 无参构造实例对象
SmartPhone.prototype = new Phone();
// 还原SmartPhone的构造函数指向
SmartPhone.prototype.constructor = SmartPhone;
// 声明子构造函数的方法
SmartPhone.prototype.playGame = function() {
console.log('玩游戏');
}
const HuaWei = new SmartPhone('黑色', 3999, '15px')
console.log(HuaWei, 'xx');
ES6 class类实现继承
// 父类
// 手机
class Phone {
constructor(color, price) {
this.color = color;
this.price = price;
}
call() {
console.log('打电话');
}
}
// 子类智能手机
class SmartPhone extends Phone{
constructor(color, price,size) {
// 调用父类的构造函数
super(color, price);
this.size = size;
}
playGame() {
console.log('打游戏');
}
}
let huaWei = new SmartPhone('黑色', 1000, '大得很');
console.log(huaWei);
3、私有属性
class Person {
// 公有属性
name;
// 私有属性
#sex;
constructor(name, sex) {
this.name = name;
this.#sex = sex;
}
// 只有在类里面才可以访问私有属性
}
十五、数值的扩展
- Number.SPSILON: 表示最小精度
- Number.isFinite : 是否为有限数
- Number.isNaN: 是否为NaN
- Number.parseInt : 字符串转整数
- Number.isInteger: 是否为整数
- Math.trunc: 将数字的小数部分去掉
- Math.sign 是否为正数、负数、还是零
十六、对象的扩展
- Object.is() : Object.is(NaN,NaN) = true
- Object.assign() 合并对象
- Object.entries({}) 对象转二维数组
- Object.fromEntries([[]]) 二维数组/Map 转 对象
1、ES8对象方法的扩展
- Object.values() 返回可以枚举属性的属性值数组
- Object.entries() 返回可遍历属性的 [key, valuie] 的数组, 【用于转Map对象】
- Object.getOwnPropertyDescriptors(): 返回指定对象所有属性的描述对象【描述对象指:是否可枚举;是否可更改等】
const zhw = {
name: 'zhw',
age: 18,
hobbies: ['篮球', 'rap'],
other: {
desc: '待定'
},
}
// 获取对象所有的key
// console.log(Object.keys(zhw)); // ['name', 'age', 'hobbies', 'other']
// 获取对象所有的值
// console.log(Object.values(zhw)); // ['zhw', 18, ['篮球', 'rap'], {desc: '待定'}]
// 将对象的键值用二维数组包裹起来
// [
// ['name', 'zhw']
// ]
// 将对象转Map数据结构
// let m = new Map(Object.entries(zhw))
// console.log(m.get('name'));
// Object.getOwnPropertyDescriptors(): 获取对象属性的描述对象
// 自定义创建对象
// zhw将挂载在other_zhw的原型上
const other_zhw = Object.create(zhw, {
// 属性名: 描述对象
errorDesc: {
value: "另一个我。 错了",
writable: true,
configurable: true,
enumerable: true
}
})
// 不会获取原型上zhw对象的属性描述对象
// 仅仅打印errorDesc属性的描述对象
console.log(Object.getOwnPropertyDescriptors(other_zhw))
数组的扩展
1、数组的扁平化
- arr.flat()
// 将n维数组 转化为 n - 1维数组
// const arr = [1, 2, 3, [4, 5]]
// console.log(arr.flat()); // [1, 2, 3, 4, 5]
// const arr = [1, 2, 3, [4, 5, [6, 7]]]
// console.log(arr.flat()); // [1, 2, 3, 4, 5, [6, 7]]
const arr = [1, 2, 3, [4, 5, [6, 7]]]
// 参数: 扁平化的深度 默认是1
console.log(arr.flat(2)); // [1, 2, 3, 4, 5, 6, 7]
- arr.flatMap()
// 需求:一维数组的每个元素 * 10
const arr = [1, 2, 3, 4]
// 结果是二维是数组
// const res = arr.map(item => [item * 10]) // [[10], [20], [30], [40]]
// 此时需要使用flatMap
const res = arr.flatMap(item => [item * 10]) // [10, 20, 30, 40]
console.log(res);
十七、ES6模块化
模块化:是指将一个大的程序文件,拆分成许多个小的文件,然后将小文件组合起来
1、模块化的好处
- 防止命名冲突
- 代码复用
- 高维护性
2、模块化规范的产品
- CommonJS: NodeJS、Browserify
- AMD: requireJS
- CMD: seaJS
- Import:ES6
3、ES6模块化的语法
导出语句
- 第一种
export const a = 1;
export const b = {};
export const c = () => {}
- 第二种
const a = 1;
const b = {};
const c = () => {}
export {
a,
b,
c
}
- 第三种:默认导出
export default {
const a = 1;
const b = {};
const c = () => {}
}
导入语句
- 三种导出方式,通用的导入语句
// m1 文件别名; as: 取别名关键字
import * as m1 from './src/js/m1.js
- 第二种:解构赋值导入
import {a, b, c} from './src/js/m1.js'
// 当 当前文件import解构的变量重名时, 可以给重名的变量取别名
import {a as m2_a } from './src/js/m2.js'
// 解构赋值的方法 导入默认导出的文件 也是默认导出文件的
import {default as m3 } from './src/js/m3.js'
- 第三种:默认导出的简便导入
// m3: 自定义的
import m3 from './src/js/m3.js'
十八、ES7的新特性
1、数组的includes()
判断数组中, 是否包含某个元素。替代原生的 indexOf
2、** 指数运算符
** 指数运算符 替代 原生的 Math.pow(2, 10)
console.log(2 ** 10)
console.log(Math.pow(2, 10))
十九、bigint大整形
又一个新的基本类型
let n = 521n;
console.log(n, typeof n); // 521n 'bigint'
1、BigInt函数
let n = 521;
console.log(BigInt(n)); // 521n
// 参数只能是整数
console.log(BigInt(1.2)); // error
2、应用
- 大数值运算
let max = Number.MAX_SAFE_INTEGER;
// console.log(max); // 9007199254740991
// console.log(max + 1); // 9007199254740992
// // 再 + 1 大数值未变
// console.log(max + 2); // 9007199254740992
// 希望大数值变化
console.log(BigInt(max)); // 9007199254740991n
console.log(BigInt(max) + BigInt(1)); // 9007199254740992n
// bigint 只能和bigint类型运算
// 所以这里的2 也需要转换为bigint再运算
console.log(BigInt(max) + BigInt(2)); // 9007199254740993n