目录
重点:Promise对象进行异步解决时,会线程阻塞,直到调用了resolve()或者reject()才会继续执行
重点:子类需要先调用父类的构造方法,将父类构建出来,才能实例化自己
简介
es6是js的规范,而js是es6的实现
名称详解
ECMAScript 6(以下简称 ES6)是 JavaScript 语言的标准,在 2015 年 6 月发布。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
版本 | 官方名称 | 发布日期 |
ES1 | ECMAScript 1 | 1997 |
ES2 | ECMAScript 2 | 1998 |
ES3 | ECMAScript 3 | 1999 |
ES4 | ECMAScript 4 | 从未发布过 |
ES5 | ECMAScript 5 | 2009 |
ES5.1 | ECMAScript 5.1 | 2011 |
ES6 | ECMAScript 2015(ECMAScript 6) | 2015 |
ES7 | ECMAScript 2016 | 2016 |
ES8 | ECMAScript 2017 | 2017 |
... | ... | ... |
因此,ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等
node.js安装
Nodejs诞生于2009年,主攻服务器方向,使得利用JavaScript也可以完成服务器代码的编写
Nodejs官网
Nodejs的安装与一般软件一样
大量的库
在安装Nodejs的同时,会附带一个npm命令,npm 是Node的包管理工具,这样正是接下来我们要用到的
npm 的简单结构有助于 Node.js 生态系统的激增,现在 npm 仓库托管了超过 1,000,000 个可以自由使用的开源库包
npm镜像安装(使用国内的镜像命令式CNPM)
由于服务器在国外,所以下载速度比较慢,我们可以用国内的 镜像
阿里镜像地址
在命令行运行如下命令即可
npm install -g cnpm --registry=https://registry.npmmirror.com
看到如下信息,代表安装成功
babel转码器
Babel 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码,从而在老版本的浏览器执行。这意味着,你可以用 ES6 的方式编写程序,又不用担心现有环境是否支持
浏览器支持性查看
https://caniuse.com/
Babel官网
https://babeljs.io/
转码示例
原始代码用了箭头函数,Babel 将其转为普通函数,就能在不支持箭头函数的 JavaScript 环境执行了
// 转码前
input.map(item => item + 1);
// 转码后
input.map(function (item) {
return item + 1;
});
Babel安装流程
第一步:安装 Babel
npm install --save-dev @babel/core第二步:配置文件.babelrc
Babel 的配置文件是.babelrc,存放在项目的根目录下。使用 Babel 的第一步,就是配置这个文件。
该文件用来设置转码规则和插件,基本格式如下
{
"presets": [],
"plugins": []
}第三步:安装转码规则集
presets字段设定转码规则,官方提供以下的规则集,你可以根据需要安装
npm install --save-dev @babel/preset-env第四步:将规则加入.babelrc
{
"presets": [
"@babel/env"
],
"plugins": []
}安装Babel命令行转码工具
Babel 提供命令行工具@babel/cli,用于命令行转码
npm install --save-dev @babel/cli
基本用法如下
# 转码结果输出到标准输出
$ npx babel 被转码文件路径
# 转码结果写入一个文件
# --out-file 或 -o 参数指定输出文件
$ npx babel 被转码文件路径 --out-file 转码成的文件名
# 或者
$ npx babel 被转码文件路径 -o 转码成的文件名
# 整个目录转码
# --out-dir 或 -d 参数指定输出目录
$ npx babel src --out-dir lib
# 或者
$ npx babel src -d lib
let命令
let是一种声明变量的关键字,用法类似于var,但是其所声明的变量具有块级作用域。
let块级作用域
<script> { let h1 = "hello"; var h2 = "world"; } console.log(h2); console.log(h1); </script>
let不存在变量提升
<script> console.log(h2); console.log(h1); let h1 = "hello"; var h2 = "world"; </script>
let不能重复声明
<script> var a = 1; var a = "1"; let b = 1; let b = 2; </script>
const命令
const命令用于修饰常量,const修饰的常量在定义时需要初始化,并且不能修改值
const和let一样,具有块级作用域,不存在变量提升,不能重复定义
定义时必须初始化
<script> const a; </script>
不能修改值
<script> const a = 1; a = 2; </script>
解构对象
就是将对象中的指定key进行解析出来,这样我们就可以直接使用该key获得对应的value,
而不需要使用对象.key取值
<script> let {name,age} = {name:"zhangsan",age:16}; console.log(name); console.log(age); </script>
字符串扩展
字符串遍历的方式
of左边定义变量,右边代表被遍历的字符串
<script> for(let i of "hello world"){ console.log(i); } </script>
模板字符串
以往我们在标签中嵌入变量需要通过拼接的方式,而模板字符串可以很轻松的为我们解决,只需要通过反引号(` `)标识,然后在里面正常写标签,需要嵌入变量时只需要通过
${变量名}即可嵌入变量
<script> var s1 = "url"; console.log("<a href='"+ s1 +"'></a>"); console.log(`<a href="${s1}"></a>`); </script>
新增方法:
includes(),startsWith(),endsWith()
<script> //includes(),判断字符串中是否包含子字符串 console.log("----------includes()----------"); console.log("hello world".includes("wor")); //startsWith(),判断字符串是否以子字符串开头 console.log("----------startsWith(),endsWith()----------"); console.log("hello world".startsWith("wor")); console.log("hello world".startsWith("hel")); //endsWith(),判断字符串是否以子字符串结尾 console.log("hello world".endsWith("wor")); console.log("hello world".endsWith("ld")); </script>
trimStart(),trimEnd()
<script> console.log("----------trimStart(),trimEnd()----------"); //trimStart(),去除字符串头部的空格 console.log(" ni hao shi jie ".trimStart()); //trimEnd(),去除字符串尾部的空格 console.log(" ni hao shi jie ".trimEnd()); </script>
repeat()
<script> //repeat(),重复字符串n次 console.log("----------repeat()----------"); console.log("abc|".repeat(2));//2,代表重复两次 </script>
padSstart(),padEnd()
<script> console.log("----------padStart(),padEnd()----------"); //padStart(),补全长度,如果长度不足指定长度,用指定字符串在原字符串头部补全 console.log("ni hao shi jie".padStart(20,"-")); //padEnd(),补全长度,如果长度不足指定长度,用指定字符串在原字符串尾部补全 console.log("ni hao shi jie".padEnd(20,"-")); </script>
数组扩展
扩展运算符
通过在数组名前面添加(...),即可将数组转为用逗号分隔参数序列
打印时比较特殊,以空格分隔
<script> var arr = [1,2,3,4,5,6]; console.log(...arr); </script>
通过扩展运算符我们可以实现,两个数组的合并以及判断数组的最大值
<script> var arr = [1,2,3]; var arr1 = [10,20,30] console.log([...arr,...arr1]);//数组合并 console.log(Math.max(...arr));//数组最大值 </script>
伪数组
伪数组类似数组,但是他并不是数组,他可以使用数组的引用方式和length属性,但是不能使用数组的方法
伪数组有三种:
- arguments
- 元素集合
- 类似数组的对象
arguments
<script> function add(){ console.log(arguments); console.log(arguments[0]); console.log(arguments[1]); console.log(arguments[2]); } add(1,2,3) </script>
元素集合
<body> <div class="1"> <div class="2"></div> </div> </body> <script> let div = document.querySelectorAll("div"); console.log(div[0]); console.log(div[1]); </script>
类似数组的对象
<script> var user = { '0':"a", '1':"b", '2':"c", length:3 } console.log(user[0]); console.log(user[1]); console.log(user[2]); </script>
Array.from()
该方法的作用是将伪数组转为真正的数组
<body> <div class="1"> <div class="2"></div> </div> </body> <script> // arguments function add(){ console.log(Array.from(arguments)); } add(1,2,3) // 元素集合 let div = document.querySelectorAll("div"); console.log(Array.from(div)); // 类似数组的对象 var user = { '0':"a", '1':"b", '2':"c", length:3 } console.log(Array.from(user)); </script>
对象扩展
属性的简介表示法
当属性名和变量名相同时,即可不需要使用key:value的方式进行赋值,具体如下:
<script> var name = "zhangsan"; var user = { name, age:16 } console.log(user); </script>
属性名表达式
通过[表达式]的方式定义属性名,方括号中可以使用表达式
<script> var name = "zhangsan"; var user = { ["a"+"b"+name]:name, age:16 } console.log(user); </script>
对象的扩展运算符
通过(...对象名)的方式将对象转为key:value,key:value...的序列
<script> var name = "zhangsan"; var user = { name, age:16 } var user2 = { ...user } console.log(user2); </script>
函数扩展
箭头函数
在es6中新增了一种函数的表达方式,就是箭头函数,如果你学过java应该可以很轻松的理解,箭头函数就像java中lambda表达式一样只是把->变为了=>,如果你没有学过java也没有关系我们可以通过案例来了解:
<script> //语法: //(参数) => { function code... } //注意:如果只有一个参数可以省略小括号,但是如果有多个参数,括号不允许省略 //箭头右侧的大括号也是一样的原理,只有一条语句可以直接省略 var fun = function(){ console.log("这是一个普通函数!"); } var fun2 = () => {console.log("这是一个箭头函数!")}; var fun3 = a => console.log("只有一个参数,且只有一条语句!"+a); fun(); fun2(); fun3("\thello world!"); </script>
通过以上图片我们可以发现,箭头函数其实也就是将function变成了一个=>,通过参数=>{}的方式实现函数的定义
使用注意
对于普通函数来说,内部的this指向的是执行该方法的对象,但是箭头函数没有这一点,它没有自己的this对象,内部的this就是定义时上层作用域的this
<script> var user = { name:"zhangsan", age:16, getName:function(){ console.log(this.age); }, getName2:() => console.log(this.age) } user.getName(); user.getName2(); </script>
Set数据结构
Set结构类似Java中的Set集合,该结构中存储的数据有序不可重复
基本用法
1、新增数据
<script> var set = new Set(); set.add(1); set.add(2); console.log(set); </script>
2、数组去重
<script> var set = new Set([1,2,2,3,4,4]); console.log([...set]); </script>
3、字符串去重
<script> var set = new Set("hello world!!!"); var str = [...set].join(""); console.log(str); </script>
size属性
该属性可以获得该对象中存放的元素个数
<script> var set = new Set("hello world!!!"); console.log(set.size); </script>
特有方法
add()
set 添加方法
var mySet = new Set(); mySet.add("5") console.log(mySet);
delete()
删除某个值,返回一个布尔值,表示删除是否
var mySet = new Set(); mySet.add("5") var flag = mySet.delete("5"); console.log(flag); // true
has()
返回一个布尔值,表示该值是否为Set的成员
var mySet = new Set(); mySet.add("5") var flag = mySet.has("5"); console.log(flag); // true
clear()
清除所有成员,没有返回值
var mySet = new Set(); mySet.add("5") mySet.clear(); console.log(mySet); // Set(0){size: 0}
Promise对象
promise对象时异步编程的一种解决方案,以往的异步编程往往需要用到回调函数,如果回调函数中又用到了回调函数此时就会有回调函数的层级嵌套,如果回调函数过多,就会导致代码可读性差
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理
有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易
基本用法
ES6 规定,Promise对象是一个构造函数,用来生成Promise实例
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署
const promise = new Promise(function(resolve, reject) { //参数名不允许更改,必须叫这个名字 // ... some code if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } });
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
promise.then(function(value) { // success }, function(error) { // failure });
异步加载图片资源
<body> <div id="img"> </div> </body> <script src="../Promise对象/jquery-3.6.1.min.js"></script><!-- 引入jquery --> <script> function loadImageByUrl(url){ const image = new Image(); const promise = new Promise(function(resolve,reject){ image.src = url;//设置图片路径 image.onload = function(){ resolve(image);//成功调用resolve(),并将image对象传进去 }; image.onerror = function(){ reject(new Error('Could not load image at'+url)); //失败调用reject,并传入错误信息 }; }); return promise;//返回promise对象 } loadImageByUrl("https://images.pexels.com/photos/13324150/pexels-photo-13324150.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2") .then(function(data){ $("#img").append(data);//成功显示图片 },function(error){ console.log(error);//失败显示失败信息 })
重点:Promise对象进行异步解决时,会线程阻塞,直到调用了resolve()或者reject()才会继续执行
Async和await
异步编程的时候,我们通常都是有一个执行链的,也就是说a1()执行完返回一个数据,然后a2()拿着a1()返回的执行,返回一条数据,a3()再拿着a2()返回的数据执行()......
但是因为这是异步编程,所以不能保证方法的顺序执行,所以此时就需要使用到Async,通过Async修饰函数,await关键字修饰语句,即可实现异步操作变为同步操作
没有加async和await
<script> function timemout(ms){ return new Promise(function(resolve,reject){ setTimeout(function(){ console.log("你好世界!"); resolve(); },ms); }) } timemout(500); console.log("hello world!"); </script>
加了async和await
<script> function timemout(ms){ return new Promise(function(resolve,reject){ setTimeout(function(){ console.log("你好世界!"); resolve(); },ms); }) } async function testTimeout(){ await timemout(500); await console.log("hello world!"); } testTimeout(); </script>
Class
类的由来
JavaScript 语言中,生成实例对象的传统方法是通过构造函数
function Point(x, y) { this.x = x; this.y = y; } Point.prototype.toString = function () { return '(' + this.x + ', ' + this.y + ')'; }; var p = new Point(1, 2);
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类
基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已
基本语法
constructor()构造方法
constructor()方法是创建类时默认调用的方法,一个类必须有constructor(),如果没有定义则会默认添加无参构造方法
class Point { } // 等同于 class Point { constructor() {} }
类的实例
<script> class Point{ constructor(x,y){ this.x=x; this.y=y; } getPoint(){ console.log(`x:${this.x},y:${this.y}`); } } var point = new Point(1,2); point.getPoint(); </script>
属性与方法
实例方法
通过类的实例对象调用方法
class People{ say(){ console.log("Hello"); } } var p = new People(); p.say()
实例属性
实例属性指的是类的实例对象可调用的属性
class People{ constructor(name,age){ this.name = name; this.age = age; } say(){ console.log(this.name,this.age); } } var p = new People("iwen",20); p.say() console.log(p.name,p.age);
静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”
class Person { static classMethod() { console.log("Hello"); } } Person.classMethod() // Hello var p = new Person(); p.classMethod() // p.classMethod is not a function
温馨提示
注意,如果静态方法包含this关键字,这个this指的是类,而不是实例。
class People { static getSay() { this.say(); } static say() { console.log('hello'); } say() { console.log('world'); } } People.getSay() // hello
静态属性
静态属性指的是 Class 本身的属性,即Class.propName
class People{} People.status = "等待" console.log(People.status);
Class的继承
基础用法
Class 可以通过extends关键字实现继承,让子类继承父类的属性和方法。extends 的写法比 ES5 的原型链继承,要清晰和方便很多
class Point { } class ColorPoint extends Point { }
ES6 规定,子类必须在constructor()方法中手动调用super(),否则就会报错,这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,添加子类自己的实例属性和方法。如果不调用super()方法,子类就得不到自己的this对象
class Point { constructor(x,y){ this.x = x; this.y = y; } getPoint(){ console.log(this.x,this.y); } } class ColorPoint extends Point { constructor(x,y,z){ super(x,y) this.z = z; } } let cp = new ColorPoint(10,20,30) cp.getPoint();