ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
#### 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') // 后面正常编译打包就好 ~~~