#### let相关
##### 不能重复声明
~~~javascript
// 不能重复声明,var可以
let a = 'a'
let a = 'A'
// Uncaught SyntaxError: Identifier 'star' has already been declared
~~~
##### 块级作用域
> es5中的作用域:全局、函数、eval(严格模式下才会有,虽然我不懂严格模式是啥子)
>
> let声明的是块级作用域,块外不能访问
~~~JavaScript
{
let a = '333'
console.log(a, '1')
}
console.log(a, '2') // Uncaught ReferenceError: a is not defined
~~~
##### 不存在变量提升
> 变量提升:<https://www.jianshu.com/p/24973b9db51a>
>
> ~~~JavaScript
> console.log(a); //undefined,不会报错
> var a = 123;
> ~~~
~~~js
console.log(a) // Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 'aaa'
~~~
##### 不影响作用域链
![image-20210125143858874](https://image.mdashen.com/pic/image-20210125143858874.png)
##### 小案例-for循环使用let
~~~JavaScript
let items = 'items是三个div的dom'
// 遍历并绑定事件
for(let i=0;i<items.length;i++){
items[i].onclick = functionn(){
this.style.background = 'pink'
items[i].style.background = 'pink' // var下回报错(报错原因i=3超出边界)
}
}
~~~
* 原理说明--参考链接:<https://www.cnblogs.com/echolun/p/10584703.html>
~~~JavaScript
//使用var声明,得到3个3
var a = [];
for (var i = 0; i < 3; i++) {
a[i] = function () {
console.log(i);
};
}
a[0](); //3
a[1](); //3
a[2](); //3
//使用let声明,得到0,1,2
var a = [];
for (let i = 0; i < 3; i++) {
a[i] = function () {
console.log(i);
};
}
a[0](); //0
a[1](); //1
a[2](); //2
~~~
#### const--声明常量
* 一定要赋初始值
* 常量的值不能修改(引用地址不能修改)
* 块级作用域
* 对于数组和对象的元素修改,不算对常量的修改(引用地址没有修改)
* 常使用const声明数组、对象
~~~javascript
const a = 1
a = 2 // Uncaught TypeError: Assignment to constant variable
const a = ['1','2','3']
a.push('4') // 虽然对改变了数组a,但是a的地址并没有改变,所以没有问题
~~~
> 参考链接:[https://www.cnblogs.com/minigrasshopper/p/9144223.html](https://www.cnblogs.com/minigrasshopper/p/9144223.html),[MDN说明](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/const)
>
> `const`实际上保证的,并**不是变量的值不得改动**,而是**变量指向的那个内存地址不得改动**。
>
> 对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。
>
> 但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针;
>
> `const`只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。
>
> 因此,将一个对象声明为常量必须非常小心。
#### 数组解构和对象解构
* 解构赋值:ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值
~~~javascript
// 数组的解构赋值
const aaaa = ['一','二','三','四']
let [a,b,c,d] = aaaa // a='一',b='二'……
// 对象的解构赋值
const aa = {name:'yishen',age:18,school:'qinghua'}
let {name} = aa // yishen
let {age} = aa // 18
let {school} = aa // qinghua
~~~
#### 模板字符串 ``
* 内容中可以直接出现换行符号、'单引号'、"双引号"不行
* 变量拼接
~~~javascript
let love = '爱'
let str = `${love}你哦!`
console.log(str) // 爱你哦!
~~~
#### 简化对象写法
> ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法,书写更简洁
~~~JavaScript
let name = 'yishen'
let change = function(){
console.log('yishen')
}
const school = {
name:name,
change:chage,
improve:function(){
console.log('提升')
}
}
// 等价于
const school = {
name,
change,
improve(){
console.log('提升')
}
}
~~~
#### 箭头函数 =>
~~~javascript
let fn = function(a,b){
return a+b
}
let fn = (a,b) => { // 当参数有且只有一个参数,小括号可以省略
return a+b
}
~~~
参考链接:[MDN-箭头函数](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions),[this指向问题](https://www.jianshu.com/p/fcfda0868ec2),[this指向问题](https://www.imooc.com/article/288214?block_id=tuijian_wz)
* 箭头函数和普通函数区别
* this是静态的(this始终指向函数声明时所在作用域下的this值)
* ~~~javascript
function getName(){
console.log(this.name)
}
// 函数体内部只有一句,可以省略函数的花括号
// 如果是return ,return必须省略,语句的执行结果就是函数的返回值
let getName2 = () => console.log(this.name)
// 设置window对象
window.name = 'yishen'
const school = {
name:'qinghua'
}
// 直接调用
getName() // yishen
getName2() // yishen
// call 方法调用 call方法可以改变this的指向
getName.call(school) // qinghua,this指向了school对象
getName2.call(school) // yishen ,this执行依然是window(函数声明时所在作用域下的this)
~~~
* 不能作为构造实例化对象
![image-20200714212647614](http://image.mdashen.com/pic/image-20200714212647614.png)
`Uncaught TypeError:Person is not a constructor`
* 不能使用 arguments 变量
* 箭头函数适用范围
* 箭头函数**适合**与this无关的回调。定时器,数组的方法回调
* 箭头函数**不适合**于this无关的回调。事件回调,对象的方法
#### 给函数参数赋初始值
##### 形参初始值
~~~JavaScript
// 形参初始值,一般位置要靠后
const add = (a,b,c=100)=> a+b+c
add(1,2) // 103
~~~
##### 与解构赋值结合
~~~JavaScript
function connect({host='127.0.0.1',username,password,port=3306}){
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
connect({
host:'mdashen.com',
username:'yishen',
password:'yishen'
})
~~~
#### rest参数
> 用于获取函数的实参,代替[arguments](https://www.bilibili.com/video/BV1YW411T7GX?p=80)
* 传统arguments的使用
~~~javascript
function date(){
console.log(arguments)
}
date('2','3','4') // arguments返回的是一个类数组对象,可以arguments[0]这样用
~~~
* ES6新增,rest参数
~~~javascript
// rest参数必须放到最后
function fu (a,b,...args){
console.log(a)
console.log(b)
console.log(args)
}
fn(1,2,3,4,5,6,7) // a=1,b=2,args=[3,4,5,6,7]
~~~
#### 扩展运算符
> **...** 扩展运算符能将 **数组或对象** 转换为逗号分隔的 **参数序列**
* 数组合并
~~~javascript
const a = [1,3,5]
const b = [2,4,6]
const c = a.concat(b) //[1, 3, 5, 2, 4, 6]
const d = [...a,...b] // [1, 3, 5, 2, 4, 6]
~~~
#### 数据类型 Symbol
##### 基本概念
> ES6引入一种新的原始数组类型Symbol,**表示独一无二的值**。
>
> 它是javascript语言的第七种数据类型,是一种类似于字符串的数组类型
>
> * Symbol特点
> * Symbol 的值是唯一的,用来解决命名冲容的问题
> * ymbol 值不能与其他数据进行运算
> * Symbol 定义的对象属性不能使用for.in 循环遍历,但是可以使用 Reflect. owners 来获取对象的所有键名
~~~JavaScript
// 创建Symbol
let s = Symbol()
let s2 = Symbol('描述文字,相当于对这个变量的注释')
console.log(s, typeof s) // Symbol() "symbol"
console.log(s, typeof s2) // Symbol() "symbol"
console.log(Symbol('ddd')===Symbol('ddd')) // false
// Symbol.for创建
let s3 = Symbol.for('yishen')
let s4 = Symbol.for('yishen')
console.log(s3===s4) // true
~~~
* 补充js中数据类型,7中基本数据类型+复杂数据类型object
> USONB you are so niubility
>
> u undefined
>
> s string symbol
>
> o object
>
> n null number
>
> b boolean [BigInt](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
##### 使用场景
* 向对象中添加方法
~~~JavaScript
// 方法一
let game = {
name:'俄罗斯方块',
up:function(){console.log('我是up方法')},
down:function(){console.log('我是down方法')}
}
let methods = {
up:Symbol(),
down:Symbol()
}
game[methods.up] = function(){
console.log('我也是up方法')
}
game[methods.down] = function(){
console.log('我也是down方法')
}
console.log(game) // 如下图
~~~
![image-20200715123141141](http://image.mdashen.com/pic/image-20200715123141141.png)
* 给对象添加方法-------方法二
![image-20200715123622490](http://image.mdashen.com/pic/image-20200715123622490.png)
##### Symbol内置值
> 除了定义自己使用的Symbol值以外,ES6还提供了内置的Symbol值,执行语言内部使用的方法。
>
> 可以称这些方法为魔术方法,因为它们会在特定的场 景下自动执行。
| Symbol.hasInstance | 当其他对象使用 instanceof 运算符,判断是否为该对 象的实例时,会调用这个方法 |
| :------------------------ | ------------------------------------------------------------ |
| Symbol.isConcatSpreadable | 对象的 Symbol.isConcatSpreadable 属性等于的是一个 布尔值,表示该对象用于 Array.prototype.concat()时,是否可以展开 |
| Symbol.species | 创建衍生对象时,会使用该属性 |
| Symbol.match | 当执行 str.match(myObject) 时,如果该属性存在,会 调用它,返回该方法的返回值 |
| Symbol.replace | 当该对象被 str.replace(myObject)方法调用时,会返回 该方法的返回值 |
| Symbol.search | 当该对象被 str. search (myObject)方法调用时,会返回 该方法的返回值。 |
| Symbol.split | 当该对象被 str. split (myObject)方法调用时,会返回该 方法的返回值 |
| Symbol.iterator | 对象进行 for...of 循环时,会调用 Symbol.iterator 方法, 返回该对象的默认遍历器 |
| Symbol.toPrimitive | 该对象被转为原始类型的值时,会调用这个方法,返 回该对象对应的原始类型值 |
| Symbol. toStringTag | 在该对象上面调用 toString 方法时,返回该方法的返 回值 |
| Symbol. unscopables | 该对象指定了使用with关键字时,哪些属性会被with 环境排除。 |
* 当o instanceof Person时,hasInstance方法会自动被调用
![image-20200715140644214](http://image.mdashen.com/pic/image-20200715140644214.png)
* 可自定义返回结果
![image-20200715140751747](http://image.mdashen.com/pic/image-20200715140751747.png)
![image-20200715141049908](http://image.mdashen.com/pic/image-20200715141049908.png)
#### 迭代器
> 迭代器(iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。
>
> 任何数据结构只要部署iterator接口(对象里面的一个属性Symbol.iterator),就可以完成遍历操作
>
> * ES6创造了一种新的遍历命令 for ... of 循环,iterator接口主要供 for ... of消费
> * 原生具备iterator接口的数据(可用for of 遍历)
> * Array、Arguments、Set、Map、String、TypedArray、NodeList
> * 工作原理
> * 创建一个指针对象,指向当前数据结构的起始位置
> * 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
> * 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
> * 每调用 next 方法返回一个包含 value 和 done 属性的对象
> * ![image-20200716074822000](http://image.mdashen.com/pic/image-20200716074822000.png)
> * **需要自定义遍历数据的时候,要想到迭代器**
~~~javascript
// 迭代器应用
const beijing = {
name: '终极一班',
stus: [
'xiaoming',
'xiaoning',
'xiaotian',
'knight'
],
[Symbol.iterator]() {
let index = 0
let _this = this
return {
next: function () {
if (index < _this.stus.length) {
const result = {value: _this.stus[index],done: false}
index++
return result
} else {
return { value: undefined,done: true}
}
}
}
}
}
for (const v of beijing) {
console.log(v) //xiaoming xiaoning xiaotian knight
}
~~~
#### 生成器
> 生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同
>
> js的异步是单线程的
##### 生成器的声明与调用
~~~JavaScript
function * gen(){
console.log(111)
yield 'yiele是代码的分割符1'
console.log(222)
yield 'yiele是代码的分割符2'
console.log(333)
yield 'yiele是代码的分割符3'
console.log(444)
}
let iterator = gen()
iterator.next() // 111
iterator.next() // 222
console.log(iterator.next()) // {value:'yiele是代码的分割符1',done:false}
console.log(iterator.next()) // {value:'yiele是代码的分割符2',done:false}
~~~
##### 生成器的参数传递
![image-20200716115523299](http://image.mdashen.com/pic/image-20200716115523299.png)
* 生成器函数实例
![image-20200716120633112](http://image.mdashen.com/pic/image-20200716120633112.png)
#### Promise
> [参考链接](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise),
>
> Promise是ES6引入的异步编程的新解决方案。
>
> 语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果
>
> * Promise构造函数:Promise(excutor){}
> * Promise.prototype.then()
> * Promise.prototype.catch()
> .then()返回的结果也是Promise对象,对象状态有回调函数的执行结果决定
>
> .then().then()可以链式调用
#### 数组结构 Set&Map
[参考链接-菜鸟教程](https://www.runoob.com/w3cnote/es6-map-set.html)
##### Set
> ES6提供了新的数据结构 Set(集合)。类似于数组,成员的值都是唯一的。
>
> set实现了iterator接口,可以使用 **扩展运算符** 和 **for...of**进行遍历
>
> set的属性和方法
>
> | size | 返回集合的元素个数 |
> | ------ | ----------------------------------------- |
> | add | 增加一个新元素,返回当前集合 |
> | delete | 删除元素,返回boolean值 |
> | has | 检测集合中是否包含某个元素,返回boolean值 |
> | clear | 清空集合,返回undefined |
~~~javascript
// 声明集合set
let s = new Set(['1', 'er', 'san', 'si', 'san'])
console.log(s, typeof (s)) // Set(4){"1", "er", "san", "si"}"object"
// 集合会自动去重,可以利用这点做数组快速去重[...new Set(array)]
s.size() // ->4
s.add('wu') // ->{"1","er","san","si","wu"}
~~~
##### Map
> 它类似于对象,也是键值对的结合。“键”的范围不限于字符串,各种类型的(包含对象)都可以当做键
>
> Map也实现了iterator接口,可以使用扩展运算符和for...of遍历。
>
> Map的属性和方法
>
> | size | 返回Map的元素个数 |
> | ----- | ---------------------------------------- |
> | set | 增加一个新元素,返回当前Map |
> | get | 返回键名对象的键值 |
> | has | 检测Map中是否包含某个元素,返回boolean值 |
> | clear | 清空集合,返回undefined |
#### class类
> ES6提供了更接近传统语言的写法,引入Class 概念。
>
> 基本上ES6的class可以看做是一个[语法糖](https://baike.baidu.com/item/语法糖/5247005),其绝大多数ES5够可以做到。
>
> 新的class写法只是让对象原型的写法更加清晰,更像面向对象编程的语法
>
> 主要知识点
>
> * class声明类
> * constructor定义构造函数初始化
> * extends继承父类
> * super调用父级构造方法
> * static定义静态方法和属性(静态方法属于类,不属于实例化对象)
> * 父类方法可以重写
* ES5写法
~~~JavaScript
function Phone(brand,price){
this.brand = brand // brand:品牌
this.price = price
}
Phone.prototype.call = function(){ // 添加方法
console.log("打电话")
}
let Huawei = new Phone('华为',4999) // 实例化对象
Huawei.call()
~~~
* ES6写法
~~~JavaScript
class Phone{
constructor(brand,price){ // 构造方法,名字不能修改
this.brand = brand
this.price = price
}
call(){ // 方法必须使用该语法,不能使用ES5的对象完整形式
console.log('打电话')
}
}
let onePlus = new Phone("1+",4999)
onePlus.call()
~~~
* 深入研究:[链接](http://caibaojian.com/es6/class.html)
#### 数值扩展&对象方法扩展
##### 数值扩展
* Number.EPSION
> Number.EPSION 是 JavaScript 表示的最小精度
>
> EPSILON属性的值接近于2.220446049250313e-16
>
> 引入一个这么小的量的目的,在于为浮点数计算,设置一个误差范围。我们知道浮点数计算是不精确的
~~~JavaScript
0.1+0.2 // 0.30000000000000004
function equal(a, b) {
return Math.abs(a - b) < Number.EPSILON
}
console.log(equal(0.1 + 0.1, 0.2))
console.log(0.1 + 0.2 === 0.3)
~~~
* 二进制、八进制、十进制、十六进制
~~~javascript
let b = 0b1010 // 10
let o = 0o777 // 511
let d = 100 // 100
let x = 0xff // 255
~~~
> 下面这些,在Es5中可能是单独的方法,ES6中将其放到,对象下
>
> 举例:ES5中 `isFinite(Infinity)` ES6中 ``Number.isFinite(Infinity)``
| Number.isFinite | 检测一个数值是否为有限数 |
| ----------------- | -------------------------------------- |
| Number.isNan | 检测一个数是否为NaN |
| Number.parseInt | 字符串转数组-整数Int |
| Number.parseFloat | 字符串转数组-浮点数Float |
| Number.isInteger | 判断一个数是否为整数 |
| Math.trunc | 将数字的小数部分抹掉 |
| Math.sign | 检测一个数,正数(返回1) 负数(0) 零(-1) |
##### 对象方法扩展
| Object.is | 判断两个值是否完全相等 |
| --------------------- | ---------------------- |
| Object.assign | 对象的合并(重复的覆盖) |
| Object.setPrototypeOf | 设置原型对象 |
| Object.getPrototypeOf | 获取原型对象 |
#### 模块化
##### 基本的暴露于导入
> 模块化值指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来
>
> 模块功能命令主要由两个命令构成:
>
> * export:规定模块的对外接口
> * import:输入其他模块提供的功能
* 三种暴露方式
~~~JavaScript
// 分别暴露
export let school = 'string'
export function teach(){
cosole.log('我可以教你知识')
}
// 统一暴露
let school = 'string'
function teach(){
cosole.log('我可以教你知识')
}
export {school,teach}
// 默认暴露
export default {
school:'qinghua',
change: function(){
console.log('大学期间的学识,可以改变你的一生')
}
}
~~~
* 导入方式
~~~javascript
// 通用导入方式
import * as m1 from "./m1.js"
console.log(m1.school) // string
// 解构赋值形式
import {school,teach} from "./m1.js"
console.log(school)
import {school as xuexiao } from "./m2.js" // 导入的不同模块重名,可以使用呢as起别名
console.log(xuexiao)
import {default as m3} from './m3.js'
console.log(m3.school) // qinghua
// 简便形式 针对默认暴露
import m3 from './m3.js'
~~~
##### babel转化ES
> [Babel](https://www.babeljs.cn/docs/) 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中
>
> 编译打包为es5过程,局部安装用npx 全局安装不需要
>
> * 安装工具 `babel-cli babel-preset-env browserify(webpack)`
> * npx babel src/js -d dist/js | 原路径,编译后路径
> * 打包 npx browserify dist/app.js -o dist/bundle.js
* 使用npm
~~~javascript
import $ from 'jquery' // const $ = require('jquery')
$('body').css('background','pink')
// 后面正常编译打包就好
~~~