ES6
let变量声明以及声明特性
使用let同一个作用域声明变量时不可以重复声明,使用var重复声明是可以的。使用let就可以防止变量重复或被污染。
块级作用域:
只在代码块内有效(如if、swich、for、while等)
不影响作用域链
函数内部的变量(子作用域)和循环变量(父作用域)不在同一个作用域。
(var声明的是全局变量)
不存在变量提升:即不允许在变量声明前使用该变量。(若是var则是显示undefined)
const声明常量以及特点
一定要赋初始值。
常量的值不能修改,也不可以重复声明。
块级作用域且同样不能提升。
对于数组和对象的元素修改,不算做对常量的修改,不会报错(地址没有改变)。如果想将对象冻结,应该使用Object.freeze方法。
变量的解构赋值
ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值。
1、数组的解构
const a=[1,2,3,4];
let[一,二,三,四]=a;
//此时相当于把1,2,3,4分别赋值给一、二、三、四
2、对象的解构
const xu={
name:'徐',
age:'17',
chi:function(){
console.log("123");
}
}
let{name,age,chi}=xu;
//此时分别把对象中的name,age,chi赋值给了对应的变量
模板字符串
ES6引入新的声明字符串的方式[' ']、‘ ’ 、 “ ”
特性:
- 内容中可以直接出现换行符,此前需要引号和加号连接
- 可以直接进行变量的拼接
let str1='西瓜';
let str2='很好吃!';
//最初的方式
let str2='str1'+'str2';
//直接拼接
let str2='${str1}很好吃!';
数值拓展
- Number.EPSILON是js表示的最小精度,若误差小于该值则视为相等
- ES6中二进制用0b(0B)表示,八进制用0o(0O)表示
- Number.isFinite()用来检查一个数值是否为有限的( finite )
- Number.isNaN()用来检查一个值是否为NaN
- Number.isInteger()用来判断一个值是否为整数,在js中整数和浮点数储存方法一致,被视为一个值
- 整数范围在-253到253之间(不含两个端点)是安全整数,Number.isSafeInteger()则是用来判断一个整数是否落在这个范围之内。
- Math.trunc除去小数部分,Math.sign方法用来判断一个数到底是正数、负数、还是零。
- 指数运算符(**),新的赋值运算符(**=)
对象方法的拓展(6-11)
- Object.is(,) 判断两个值是否完全相等,该方法与===在判断两个NaN是恶分别得到的是true和false
- Object.assign(对象1,对象2),如果对象1的属性对象2也有,对象2的属性就会覆盖对象1的属性,如果对象1的属性对象2没有就会显示对象1的属性。若只有一个参数直接返回,若不是对象则先转成对象再返回(undefined、null除外)
- Object.setPrototypeof设置原型对象格式Object.setPrototypeof(对象1,对象2)将对象2设置为对象1的原型,对象2的原型为Object对象。
- Object.values 返回一个给定对象自身的所有可枚举属性值的数组,Object.entries 返回一个数组,其元素是与直接在object上找到的可枚举属性键值对相对应的数组。
- Object.getOwnPropertyDescriptors 返回对象属性的描述对象。
- Object.fromEntries(),这个方法和之前的Object.entries()是两个互逆的操作,将二维数组转换为对象。
对象的简化写法
ES6允许在大括号里面,直接写入变量和函数作为对象的属性和方法。
let name='xu';
let haha=funxtion(){
console.log('hahaha');
}
const xu={
name,//实际上为name:name,但是ES6允许直接写入
haha,
import(){}//此时原本为import:function(){},但是在ES6中可以简化为前面的写法
}
箭头函数以及声明特点
ES6允许使用箭头(=>)定义函数。
特性:
- this是静态的,无论使用什么方式(直接调用或call调用)this始终指向函数声明时所在作用域下的this的值。
- 不能作为构造实例化对象(个人简单理解为var persion = new Person('xu','17')就是对象实例化)
- 不能使用arguments变量(该变量用来保存实参)
- 箭头函数的简写:当形参有且只有一个时可以省略小括号;当代码提只有一条语句时可以省略花括号(此时return必须省略,且执行结果就是返回值)。
函数参数的默认值设置
ES6允许给函数参数赋初始值。
具有默认值的参数,一般位置靠后(潜规则)。
默认值可以与解构赋值结合使用。
function connect({name='李四',age,job}){
console.log(name)
console.log(age)
console,log(job)
}
coonect({
name:'张三',
age:'20',
job:'学生'
})
//这里给name赋予初始值,如果没有传入则默认为李四
rest参数
ES6引入rest参数,用于获取函数的实参,用来替代arguments。
function data(...args){
console.log(args);
}
data('zs','ls','ww');
得到的结果是数组。
rest参数必须要放在参数的最后。
拓展运算符
拓展运算符(...)能将数组转化为逗号分隔的参数序列。
const zuhe=['张三','李四','王五'];
function haha(){
console.log(srguments);
}
haha(...zuhe);//haha('张三','李四','王五')
虽然拓展运算符和rest符号一样,但是rest是写在形参的位置,拓展运算符是写在调用的实参位置。
拓展运算符的运用:
1、数组的合并
const zuhe = ['一号','二号'];
const zuhe2 = ['三号','四号'];
const zuizhongzuhe = [...zuhe, ...zuhe2];
//最终的结果就是['一号','二号','三号','四号']
2、数组的克隆:直接运用运算符写入即可
3、将伪数组转化为真正的数组
const divs = document.querySelectorAll('div');
const divarr = [...divs]
Symbol的介绍与创建
数据类型Symbol表示独一无二的值,是一种类似于字符串的数据类型。
特性:
- Symbol的值是唯一的,用来解决命名冲突的问题
- Symbol值不能与其他数据进行运算、对比、拼接(与自身也不行)
- Symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
//创建Symbol
let s=Symbol();
let s1=Symbol('hhhhh');//此时若再创建一个s2也为Symbol('hhhhh'),要注意s1,s2是不一样的
//Symbol.for(()创建
let s3=Symbol.for('hhhhhh');//此处的Symbol是一个对象,上方的Symbol是函数
//若用此方法再创建一个s4也为Symbol.for('hhhhhh'),s3,s4是相等的
Symbol的内置值![](https://img-blog.csdnimg.cn/3fde3011dccd4597b9aee457d526454f.png)
迭代器
迭代器是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口,就可以完成遍历操作。(在JS中所说的接口其实就是对象的一个属性:Symbol.Iterator)
ES6创造了一种新的遍历命令for...of循环,Iterator接口只要供for...of消费。
原生具备Iterator接口的数据(可用for...of遍历)有Array, Arguments, Set, Map, Striing, TypedArray, NodeList。
注意:for...in循环保存的是键名,即1,2,3...,而for...of循环保存的是键值,即数据的内容。
工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
- 接下来不断调用next方法,指针一致往后移动,直到指向最后一个成员
- 每调用next方法返回一个包含value和done属性(当该属性为true时表示遍历结束)的对象
生成器
生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。
声明方式:function *go(){yield},其中yield是函数代码分隔符
function * go(){
console.log(1);
yield '我爱吃西瓜';
console.log(2);
yield '我爱吃苹果';
console.log(3);
yield '我爱吃草莓';
}
let iterator = go();
iterator.next();//控制台打印1
iterator.next();//控制台打印2
iterator.next();//控制台打印3
//若将上面三行分别打印则控制台显示的是{value:(yield后面的内容),done:true/false}
由代码输出结果可见,并不同于先前的函数直接运行全部,而是通过next方法来控制代码向下执行。
也可以使用for...of遍历,但是每次返回的结果是yield后面的内容。
生成器函数的参数传递
若直接用生成器函数传入参数则至少需要运行第一个next方法,否则不会执行。
next方法可以传入实参,第二次next方法传入的实参将作为第一个yield语句的返回结果。
Promise函数
promise是ES6引入的异步编程的新解决方案。语法上promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
构造函数:Promise(){}
const p = new Promise(function(resolve,reject){
setTimeout(functon(){
let data = '数据库中的用户数据';
resolve(data)//此时p的状态变为成功
let err = '数据读取失败';
reject(err);//此时p的状态为失败
),1000);
});
//调用promise对象的then方法
p.then(function(value){
console.log(value);//打印结果为数据库中的用户数据
},function(reason){
console.error(reason);//打印结果为数据读取失败
})
promise.prototype.then方法
该方法返回的结果实际上也是一个promise对象,其对象状态由回调函数的执行结果决定。如果回调函数中返回的结果是非promise类型的属性,状态为成功,返回值为对象的成功的值。如果是一个promise对象,则该promise对象的返回状态决定外部promise对象的返回状态,且其值就是then方法返回的值。若为抛出错误则then返回的对象的状态是失败的状态,值就是抛出的错误的值。
由于then方法返回的是promise对象,则可以实现链式调用,即在then中嵌套then。then方法的链式调用可以解决回调地狱问题(一个异步请求套着另一个异步请求,一个异步请求依赖于另一个异步请求的结果)
promise.prototype.catch()方法
catch方法只能指定发生错误时的回调函数,返回值也是promise对象
如果Promise对象状态变为resolved,则会调用then方法指定的回调函数,如果异步操作抛出错误,状态就会变成rejected,就会调用catch方法指定的回调函数,如果运行中抛出错误也会被catch捕获
由于promise的状态一旦改变就永久 保持该状态不会再改变。所以若promise状态以及变成resolved,则再抛出错误是无效的。
promise对象的错误会一直向后传递直至被捕获,即错误只会被下一个catch捕获。
promise读取文件(多个)
//引入fs模块
const fs = require('fs');
//使用promise封装读取方法
const p = new Promise(function(resolve,reject){
fs.readFile("路径1",(err,data)=>{
resolve(data)
});
});
p.then(value =>{
return new Promise(resolve,reject)=>{
fs.readFile("路径2",(err,data)=>{
resolve([value,data]);
});
}).then(value=>{
return new Promise(resolve,reject)=>{
fs.readFile("路径3",(err,data)=>{
//压入
value.push(data);
resolve(value);
});
});
}).then(value=>{
console.log(value);
});
fs模块是Node.js的一个核心模块,专门用来操作系统中的文件,常用的操作方式是对文件的读取和写入使用require('fs')载入fs模块,模块中所有方法都有同步和异步两种形式。异步方法中回调函数的第一个参数总是留给异常参数(exception),如果方法成功完成,该参数为null或undefined
pomise封装AJAX
const p = new Promise((resolve,reject)=>{
//1、创建对象
const xhr = new XMLHttpRequest();
//2、初始化
xhr.open("GET","接口地址");
//3、发送
xhr.send();
//4、绑定事件,处理响应结果
xhr.onreadystatechange = funxtion(){
if(xhr.readyState ===4)
if(xhr.status >=200 && xhr.status<300){
resolve(xhr.response);
}else{
reject(xhr.status);
}
}
}
})
//指定回调
p.then(function(value){
console.log(value);
},function(reason){
console.error(reason);
});
Set
set(集合)类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用拓展运算符和for...of进行遍历。
属性与方法:
- 返回集合的元素个数,size
- 添加一个新元素,返回当前集合,add
- 删除元素,返回boolean值,delete
- 检测集合中是否包含某个元素,返回boolean值,has
- 清空集合,clear
实践:
let arr = [1,2,3,3,2,4,5,6,4,7];
//1、数组去重
let result1 = [...new Set(arr)];
console.log(result);
//2、交集
let result2 = [...new Set(arr)].filter(item =>new Set(arr2).has(item));
//3、并集
let result3 =[...new Set([...arr, ...arr2])];
//4、差集
let result4 = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
Map
类似于对象,也是键值对的集合,但是”键“的范围不限于字符串,各种类型的值(包括对象)都可以当作键,Mapye也实现了iterator接口,所以可以使用拓展运算符和for...of遍历。
let m=new Map(); m.set('键名','键值');
属性和方法:
- Map的元素个数,size
- 新增一个新元素,返回当前Map,set
- 返回键名对象的键值,get
- 检测是否包含某个元素,返回boolean值
- 清空,返回undifined,clear
Class类
class phone{
//构造方法,默认返回实例对象
constructor(){//constructor不可更改,当执行"new+类名"时会自动执行
this.brand=brand;//this关键词代表实例对象
this.price=price;
}
//在class中必须使用下列语法,不可以使用ES5的对象完整形式,即call:function(){}
call(){
console.log("");
}
}
let iphone = new phone("iphone",6000);//类必须使用new调用
console.log(iphone);
静态方法
在方法前加上static关键字表示该方法不会被实例继承,且该方法直接通过类来调用。
静态方法中若包含了this,该this制的是类而非实例。
静态方法可以与非静态方法重名。
静态属性是class本身的属性,而不是定义在实例对象上的属性。
继承
//父类
class phone{
constructor(brand,price){
this.brand = brand;
this.price = price;
}
...
}
//子类
class smartphone extends phone{//此处语法固定,不可更改
constructor(brand,price,color,size){
super(brand,price);//此处的super就是父类的constructor方法
this.color = color;
this.size = size;
}
photo(){
console.log("拍照");
}
}
子类可以对父类方法进行重写,但是不可以直接调用父类的方法。
get和set
在类的内部可以使用set和get关键字对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
get通常对对象的动态属性做封装,而set则可以添加更多的控制和判断。
get一般是要返回的,set不用返回,set函数必须写上参数,否则会报错。