ES6

全称为EcmaScript,是脚本语言的规范,JavaScript可以看作EcmaScript的一个实现,ES新特性也就是JS的新特性

ECMA:全称为欧洲计算机制造商协会

let变量声明

写法和var一样

区别:

  • let不允许多次声明同一个变量

    • let a = 3;
      // 不允许声明两次
      let a = 33;
      
  • 作用域

    • 块级作用域,仅在代码块中有效,除了代码块就无效了

      • 	{
        				var a = 333;
        			}
                  // 允许
        			console.log(a);
        
      • 	{
        				var a = 333;
        			}
                  // 不允许
        			console.log(a);
        
      • Uncaught ReferenceError: a is not defined

  • 不存在变量提升

    • 	console.log(a);
       		var a = 3;
      
      • 以上的输出结果为undefined
    • 而以下结果就是报错

    • 	console.log(a);
      	var a = 3;
      
  • 不影响作用域链

    • 例如块内变量是在块外的,不影响使用

无法使用数组下标绑定事件

例如点击div标签更换div的背景颜色

		window.onload = function() {
			let boxes = document.getElementsByClassName("box");
			for(var i = 0; i < boxes.length; i++){
				boxes[i].onclick = function() {
					boxes[i].style.background = "pink";
				}
			}
		}

此时会发现报错,并且颜色无法更换,这是因为for循环执行时,响应函数并没有执行(此时没有触发点击事件),for循环在此处的作用仅仅是给点击事件赋值,只有点击标签时才会执行响应函数,如果输出i的值,此时永远是数组的长度

如果把循环控制的var i更换成let i,此时就不会出现这个问题了,可以直接给赋值了

		window.onload = function() {
			let boxes = document.getElementsByClassName("box");
			for(let i = 0; i < boxes.length; i++){
				boxes[i].onclick = function() {
					boxes[i].style.background = "pink";
				}
			}
		}

const关键字

用来声明常量

格式const 变量名 = 值;,值只能被赋一次,必须要赋值

  • 也拥有块级作用域,即代码块中声明,代码块外不能用

  • 值可以是一个对象或者数组

    • 如果是一个数组,可以对这个数组中的值改变

    • 如果是一个对象,可以对这个对象中的属性改变值,或者增加属性

      • 允许

      • 	function Person() {
          				this.name = "";
          				this.age = 0;
          			}
          			const P = new Person();
          			P.age = 1;
          			console.log(P);
        
      • 	const A = [100, 200, 300];
          			console.log(A);
          			A.push(333);
          			console.log(A);
          			A[2] = 10000;
          			console.log(A);
        

解构赋值

按照一定的模式在数组或者对象中提取值对变量进行赋值

数组的解构赋值:

  • const A = [100, 200, 300];
    let [a, b, c] = A;
    console.log(a);
    console.log(b);
    console.log(c);
    
  • 结果为100 200 300

对象的结构赋值:

		window.onload = function () {
			const A = {
				name: "名字",
				age: 100,
				sex: true,
				fun: function () {
					console.log("hello" + age);
				}
			}
			let {name, age, sex, fun} = A;
			console.log(name);
			console.log(age);
			console.log(sex);
			console.log(fun);
			fun();
		}

对象的解构赋值中,let {变量名}要与对象中的属性一一对应

模板字符串

可以使用反引号声明,即`符号

			let s = `模板字符串`;
			console.log(s);
			console.log(typeof(s));
模板字符串
string

可以有多行

			let s = `模板\n\n字
			符
			串`;
			console.log(s);
			console.log(typeof(s));

输出结果为:

模板

字
			符
			串

还可以这么写

			let s = "JavaScript";
			let ss = `${s} abcd`;
			console.log(ss);

结果为JavaScript abcd

在字符串拼接时可以这么写

对象的简化写法

允许只把变量和函数放到一个大括号中形成一个新的对象

			let name = "名字";
			let age = 100;
			let sex = true;
			let fun = function() {
				console.log("你好");
			}
			let obj = {
				name,
				age, 
				sex,
				fun
			}
			console.log(obj);

在对象中声明函数时也可以简写,可以把: function去掉

例如

	let obj = {
				fun2: function(){
					console.log("你好");
				}
			}

可以简写为

			let obj = {
				fun2() {
					console.log("你好");
				}
			}

箭头函数

=>

基本写法

			let fun = (a, b) =>{
				return a + b;
			}
			console.log(fun(3, 5));

特点:

  • 在箭头函数中this是静态的,始终指向声明时作用域下的this

  • 在普通函数中this是调用这个函数的对象,谁调用这个函数,this就是谁

  • 			window.name = "window";
    			let fun1 = function() {
    				console.log(this.name);
    			}
    			let fun2 = () => {
    				console.log(this.name);
    			}
                // 此时输出的都是window
    			fun1();
    			fun2();
    			let obj = {
    				name: "自定义"
    			}
                // fun1是被obj对象所调用的,所以输出的内容为自定义
    			fun1.call(obj);
    			// fun2是箭头函数,在window中定义,此时this是window
    			fun2.call(obj);
    
  • 箭头函数不能作为构造函数,例如以下代码会报错

    • 			let Obj = () =>{
      				this.age = 0;
      				this.sex = true;
      			}
      			let obj = new Obj();
      
  • 不能使用arguments变量保存实参

  • 还可以继续简写,分为两种情况:

    • 省略小括号

      • 当参数只有一个时可以省略小括号

      • 			let fun = n => {
        				return n + n;
        			}
        			console.log(fun(10));
        
    • 省略花(大)括号

      • 当函数体只有一条返回语句时可以省略,return也需要省略

      • 例如

        			let fun = (a, b) => a + b;
        			// 返回值为25
        			console.log(fun(10, 15));
        

函数的参数初始值

ES6允许给函数的参数赋初始值

例如

			let fun = function(a, b, c) {
				return a + b + c;
			}
			console.log(fun(1, 2));

输出结果为NaN

赋初始值后

			let fun = function(a, b, c = 100) {
				return a + b + c;
			}
			console.log(fun(1, 2));

输出结果为103,JS虽然没有要求有初始值的参数的位置必须要在最后,但一般都要往后放,否则没有意义

函数的参数可以和解构赋值结合:

		window.onload = function () {
			let connect = {
				url: "localhost",
				username: "root",
				password: "123456",
				port: "3306"
			}
			let get = function({username, password, port}) {
				console.log(`username: ${username}`);
				console.log(`password: ${password}`);
				console.log(`port: ${port}`);
			}
			get(connect);
		}

结果为:

username: root
password: 123456
port: 3306

解构赋值可以赋一个默认值:

		window.onload = function () {
			let connect = {
				url: "localhost",
				username: "root",
				password: "123456",
				port: "3306"
			}
			let get = function({username, password, count = -1, port}) {
				console.log(`username: ${username}`);
				console.log(`password: ${password}`);
				console.log(`port: ${port}`);
				console.log(`count: ${count}`);
			}
			get(connect);
		}

此时count-1

变长参数

在参数前添加...

			let fun = function(... args) {
				for(let i in args){
					console.log(i);
				}
			}
			fun(13, 252, 62, 562, 62, 52);

变长参数必须放到最后,否则报错

数组中的元素拆分

使用...可以将数组中的元素的值挨个拆分开

例如

			let fun = function(a, b, c) {
				return a + b + c;
			}
			let a = [1, 2, 3];
			// 等价于fun(1, 2, 3)
			console.log(fun(...a));

合并两个数组

使用...还可以合并多个数组

格式:let 变量 = [...数组1, ..., ...数组n]

			let a = [1, 2, 3];
			let b = [4, 5, 6];
			let d = [7, 8, 9];
			let c = [...a, ...b, ...d];
			console.log(c);

c的结果为[1, 2, 3, 4, 5, 6, 7, 8, 9]

...称为扩展运算符

也可以用来克隆数组

let a = [...b]代表将数组b中的所有值复制到a中,如果数组中有引用类型的值,那么此时也是浅拷贝

Symbol数据类型

是JS的第7种数组类型

可以使用Symbol()函数返回并创建一个Symbol

创建方式:

  • let 变量名 = Symbol()
  • let 变量名 = Symbol("字符串")
  • let 变量名 = Symbol.for("字符串")
    • 通过这种方式创建的Symbol唯一
    • image-20220204134351215

使用场景

给对象添加独一无二的属性或者方法

定义方法的方式

			let sy = Symbol("fun");
			let obj = {
				name: "good",
				[sy](){
					console.log("good");
				}
			}
            // 调用
			obj[sy]();

迭代器

image-20220204165339275

iterator接口就是对象中的一个属性

使用for...of...,此时会将数组中的内容一一输出

			let arr = ["abc", 342, 6543, "狗"];
			for(let i of arr){
				console.log(i);
			}

for...in...如果遍历数组,此时循环变量遍历的是下标

自定义实现迭代器:

  • 在自己的对象中添加[Symbol.iterator](){}

  • 使其返回一个对象,返回的对象中的内容中必须包含next()方法

  • next()方法中返回的对象必须包含{value: 值, done: bool值}

  • 总体:

    • [Symbol.iterator](){
          return {
              next: function() {
                  return {
                      value: 值,
                      done: true/false
                  }
              }
          }
      }
      
    • 例子

      • 			let obj = {
        				arr: [1, 3, "你好", "迭代器", "数组", 1000],
        				name: "good",
        				[Symbol.iterator](){
        					let index = 0;
        					return {
        						next: () => {
        							if(index < this.arr.length){
        								return {
        									value: this.arr[index++],
        									done: false
        								}
        							}else{
        								return {
        									value: undefined,
        									done: true
        								}
        							}
        						}
        					}
        				}
        			}
        			// 自定义迭代器,实现对这个对象进行迭代时返回数组中的值
        			for(let i of obj){
        				console.log(i);
        			}
        		}
        

生成器

生成器是一个特殊的函数

定义方式

let 变量名 = function* () {
    xxx
}
			let fun = function* () {
				console.log("你好");
			}
			let a = fun();
			// 返回的是迭代器,只有这样才会执行
			a.next();

也可以使用yield分割,每个next会使代码往下执行一个yield

			let fun = function* () {
				console.log("你好");
				yield
				console.log("世界");
				yield
				console.log("大小");
			}
			let a = fun();
			// 使用yield分割的,每执行一次都会跑到下一个yield
			a.next();
			a.next();
			a.next();

返回的对象的next()方法中可以传递参数,使用变量名 = yield;可以获取到

			let fun = function* () {
				console.log("你好");
				let a = yield;
				console.log(a);
				a = yield;
				console.log(a);
			}
			let a = fun();
			a.next();
			a.next("gogo");
			a.next("传递参数");

应用场景

异步调用:

		window.onload = function () {
			let fun = function* () {
				console.log("11111");
				yield;
				console.log("22222");
				yield;
				console.log("33333");
				yield;
				console.log("44444");
			}
			var f = fun();
			// 应用场景:异步调用,例如隔两秒使这个函数往下执行一次
			setTimeout(() => {
				f.next();
				setTimeout(() => {
					f.next();
					setTimeout(() => {
						f.next();
						setTimeout(() => {
							f.next();
						}, 2000);
					}, 2000);
				}, 2000);
			}, 2000);
		}

此时发现,如果调用的层级过多,此时称为回调地狱

Set集合

集合中的元素是互异的

构造方式1:

let s = new Set();

构造方式2:

let s = new Set([1, 3, 45, 425, 53, 6, 5633]);

Set是一个对象

方法含义
.size()取集合的大小
.add(值)添加值
.delete(值)删除某个值
.has(值)是否存在某个值
.clear()清空全部内容

Set集合也实现了迭代器,因此可以使用for...of...遍历

可以转换为数组

			let s = new Set([1, 1, 1, 3, 45, 425, 53, 6, 5633]);
			s.add(44);
			s.add(44);
			s.add(44);
			s.add(44);
			s.add(44);
			console.log(s, typeof s)
			// 转换为数组
			let a = [...s];
			console.log(a);

Map

image-20220204184343160

.set(键, 值)

class 类

在ES6中引入的,可以看作是语法糖

写法如下

			class Person{
                // 定义成员变量
                a = 1;
                b;
				constructor(){
					this.name = "名字";
					this.age = 100;
					this.sex = true;
				}
				method(){
					console.log("这是一个方法,必须要这么写,没有其他的格式");
				}
			}
			let a = new Person();
			console.log(a);
			a.method();

静态成员

在之前的JavaScript中实现静态成员是在prototype中放入成员变量的

			class Person {
				arr = [1, 3, 5, 4, 246, 53];
				static variable = "静态成员变量只能通过类名.的形式访问到"
				constructor() {
					this.name = "名字";
					this.age = 100;
					this.sex = true;
				}
				method() {
					console.log("这是一个方法,必须要这么写,没有其他的格式");
				}
			}
			let a = new Person();
			console.log(Person.variable);

静态成员变量只能通过类名.属性/方法的形式访问到,无法通过实例变量访问到

继承

写法如下

			class GoodPerson extends Person {
				constructor() {
					// 调用父类的构造方法
					super();
				}
				method(){
					super.method();
					console.log("子类");
				}
			}

也可以重写父类中同名的方法

ES6的模块化

export出口、输出,用于暴露

  • 在需要暴露的变量的最前边添加这个关键字

import进口、输入、表明

  • 在需要的地方引入,写法为import * as 变量名 from "路径文件名"
  • 引入后,可以通过变量名.xxx进行访问其他的变量

module 中文为模块、组件,读音为ˈmɑːdʒuːl

例如

	<script type="module">
		import * as module1 from "./js/main.js";
		console.log(module1);
		console.log(module1.p);
		console.log(module1.set);
	</script>

/js/main.js

class Person {
    age = 10
    name = "名字"
}

export let p = new Person();
export let set = new Set([1, 45425, 36, 53, 6, 53, "go", 463, 6]);

暴露方式

方式1:分别暴露,以上的方式就是分别暴露

  • 即在需要暴露的变量前添加export

方式2:统一暴露

  • js文件的最后使用export{变量1, ..., 变量n}

  • main.js

  • class Person {
        age = 10
        name = "名字"
    }
    
    let p = new Person();
    let set = new Set([1, 45425, 36, 53, 6, 53, "go", 463, 6]);
    
    // 统一暴露
    export{p, set}
    

方式3:默认暴露

  • 写法

    • export default{
          对象...
      }
      
    • 如果想要在外部使用,此时默认暴露的对象都在default对象中,若想使用,则必须在default对象中调用

      • 	<script type="module">
        		import * as module1 from "./js/main.js";
        		console.log(module1);
        		console.log(module1.default.p);
        		console.log(module1.default.set);
        	</script>
        

导入方式

方式1:通用方式,即之前导入方式

  • 写法为import * as 变量名 from "路径文件名"

方式2:解构赋值方式(针对的分别暴露)

  • 写法为import {要暴露的名称1, ..., 名称n},这个时候可以直接使用相关的变量

  • 	<script type="module">
    		import {p, set} from "./js/main.js";
    		console.log(p);
    		console.log(set);
    	</script>
    
  • class Person {
        age = 10
        name = "名字"
    }
    
    export let p = new Person();
    export let set = new Set([1, 45425, 36, 53, 6, 53, "go", 463, 6]);
    
  • 如果有多个文件使用解构赋值方式时可能产生重名问题,因此可以采用别名

  • 别名方式import {要暴露的名称1 as 别名, ..., 名称n}

    • 例如

    • 	<script type="module">
      		import {p as ppp, set} from "./js/main.js";
      		console.log(ppp);
      		console.log(set);
      	</script>
      
  • 对于默认暴露也可以采用别名方式进行暴露

    • import {default as 别名} from "xxx"

    • 	<script type="module">
      		import {default as mmm} from "./js/main.js";
      		console.log(mmm.p);
      		console.log(mmm.set);
      	</script>
      
    • class Person {
          age = 10
          name = "名字"
      }
      
      export default {
          p: new Person(),
          set: new Set([1, 45425, 36, 53, 6, 53, "go", 463, 6])
      }
      

方式3:简便形式 仅针对默认暴露

  • import 变量名 form "路径"

  • 		import v from "./js/main.js";
    		console.log(v.p);
    		console.log(v.set);
    

可以新建一个入口文件,这个文件只作为引入其他js文件使用

Q.E.D.


念念不忘,必有回响。