为什么要学es6?
公司需要,企业级开发语言
ES6新特性
- let和const命令
- es6的模板字符串
- 增强的函数
- 扩展的字符串、对象、数组功能
- 解构赋值
- Symbol
- Map和Set
- 迭代器和生成器
- Promise对象
- Proxy对象
- async的用法
- 类 class
- 模块化实现
let和const命令
//js中var关键字声明变量,会有变量提升的问题,会给开发带来问题
console.log(a);//undefined
var a = 2;
//实际过程
var a;
console.log(a);
a = 2;
所以es6提供了新的声明变量的方法 let & const,来解决这种问题。
let
用来声明变量,没有声明提升,用let声明的变量还属于块级作用域,不能重复声明。
//1.没有变量提升
console.log(a);//error,Cannot access 'a' before initialization
let a = 2;
console.log(b);// b is not defined
if(1===1){
//2.属于块级作用域
let b = 10;
}
console.log(b);// b is not defined
//3.不能重复声明
let n = 1;
let n = 2;
console.log(n);//Identifier 'n' has already been declared
const
用来声明常量,一旦声明不能改变,而且没有变量提升,属于块级,不能重复声明。
const a = 10;
a = 20;
console.log(a)//Assignment to constant variable
//对于对象
const person = {
name:'john'
}
//内部修改是可行的
person.age = 18;
//但是
person = {
age:18;
}//就会报错
作用
作用一:解决for循环问题
var arr = [];
//此处存在变量提升,var i;
for (var i = 0;i<10;i++){
arr[i] = function(){
return i
}
}
//i = 10;
console.log(arr[5]());//10
console.log(arr[4]());//10
console.log(arr[3]());//10
console.log(arr[2]());//10
//用let就可以解决
const arr = [];
for (let i = 0;i<10;i++){
arr[i] = function(){
return i
}
}
console.log(arr[5]());//5
console.log(arr[4]());//4
console.log(arr[3]());//3
console.log(arr[2]());//2
作用二:不会污染全局变量
let RegExp = 10;
console.log(RegExp);//10
console.log(window.RegExp);//ƒ RegExp() { [native code] }
建议
在默认情况下用const,只有在知道变量值需要被修改时用let。
模板字符串
语法
tab上方的反引号,插入变量时使用${变量名}
<script type="text/javascript">
const box = document.getElementById('box');
let id = 1,name = 'john';
let htmlStr =`<ul>
<li>
<p id=${id}>${name}</p>
</li>
</ul>` ;
box.innerHTML = htmlStr;
</script>
函数
带参数默认值的函数
//es5写法
function add(x,y){
x = x || 10;
y = y || 10;
return x+y;
}
add();
//es6
function add(x=10,y=20){
return x+y;
}
add();//30
add(30);//50
补充知识
JavaScript中的逻辑运算符||
运算方法:
只要“||”前面为false,不管“||”后面是true还是false,都返回“||”后面的值。
只要“||”前面为true,不管“||”后面是true还是false,都返回“||”前面的值。
默认值也可以是一个函数
function add(x,y=getVal(5)){
return x+y;
}
function getVal(val){
return val + 5;
}
add(10);//20
剩余参数
由三个点...和一个紧跟着的具名参数指定,...keys,解决了arguments问题
//es5
function pick(obj){
let res = Object.create(null);//创建空对象
for (let i = 1;i<arguments.length;i++){
res[arguments[i]] = obj[arguments[i]];
}
return res;
}
let book = {
title:'自学前端',
author:'mjj',
year:2020
}
let bookData = pick(book,'author','year');
console.log(bookData);
//es6
function pick(obj,...keys){
console.log(keys);
let res = Object.create(null);
for (let i = 0;i<keys.length;i++){
res[keys[i]] = obj[keys[i]];
}
return res;
}
扩展运算符
剩余运算符...
把多个独立的参数合并到一个数组中
扩展运算符
将一个数组分割,将每一项作为分离的参数传给函数
<script type="text/javascript">
//求最大值
const maxVal = Math.max(20,30);
console.log(maxVal);
//es5
const arr = [10,30,50,90,100,40];
console.log(Math.max.apply(null,arr));
//es6扩展运算
console.log(Math.max(...arr));
</script>
箭头函数
使用=>来定义, function(){} 等价于 ()=>{}
let add = function(a,b){
return a+b;
};
add(10,20);
//箭头函数
let add = (a,b)=>{
return a+b;
}
//简写
let add = (a,b)=>a+b;
add(10,20);
当只有一个参数时
let add = val=>{
return val+5;
}
//还可以这样写
let add= val=>val;
//和
let add= val=> val+5;
add(5);
没有参数时
let add=()=>'hello'
返回一个对象时
//不能这样写
let getObj = id =>{
id:id,
name:'john'
}
//必须带上括号
let getObj = id =>({id:id,name:'john'});
getObj(1);
闭包函数
let fn = (function(){
return function(){
console.log(1);
}
})();
fn();
//用箭头函数表示
let fn = (()=>{return()=>{console.log(1)}})();
箭头函数之this
箭头函数没有this绑定,箭头函数内部this值只能通过查找作用域链来确定,一旦使用了箭头函数,自身的作用域失效
//es5中this指向:取决于调用该函数的上下文对象
let pageHandler = {
id:123,
init:function(){
document.addEventListener('click',function(e){
console.log(this);
this.doSomeThings(e.type);
}.bind(this),false);
//可以用bind()解决
},
doSomeThings:function(type){
console.log(`事件类型:${type},当前id:${this.id}`);
}
}
pageHandler.init();
用es6来解决问题
let pageHandler = {
id:123,
init:function(){
document.addEventListener('click',(e)=>{
//此处的this为pageHandler
this.doSomeThings(e.type);
},false);
},
doSomeThings:function(type){
console.log(`事件类型:${type},当前id:${this.id}`);
}
}
pageHandler.init();
注意事项
1.使用箭头函数后,arguments失效
let getVal = (a,b)=>{
console.log(arguments);//arguments is not defined
return a+b;
}
getVal(1,3);
2.不能使用new 实例化对象
因为function函数是一个对象,而箭头函数不是一个对象,其实就是一个表达式。
let Person = ()=>{};
let p = new Person();//Person is not a constructor
解构赋值
是对赋值运算符的一种扩展,针对数组和对象进行操作。
对于对象
<script >
//老方法
let node = {
type:'index',
name:'jofn'
}
// let type = node.type;
// let name = node.name;
// 完全解构
let {type,name} = node;
console.log(type,name);
let obj = {
a:{
name:"john"
},
b:[],
c:'hello'
}
//不完全解构,可忽略一些属性
let {a} = obj;
console.log(a);
//可以使用剩余运算符
let {a,...res} = obj;
console.log(res)
//默认值
let {a,b=30}={a:20}
</script>
对于数组
<script type="text/javascript">
let arr = [1,2,3];
//完全解构
let [a,b,c] = arr;
console.log(a,b,c);
//不完全解构
let [a,b]=arr;
console.log(a,b);
//可嵌套
let [a,[b],c]=[1,[2],3];
console.log(a,[b],c);
</script>
优点:
代码上书写简单易读
扩展的对象功能
es6直接写入变量和函数,作为对象的属性和方法
const name = 'john',age = 20;
const person = {
name,
//name:name
age,
//age:age
//sayName:function(){}
sayName(){
console.log(this.name);
}
}
person.sayName();
function f(x,y){
return {x,y}
//return {x:x,y:y}
}
f(10,20);
取值与设值
let cart = {
wheels:4,
set(newVal){
if(newVal<this.wheels){
throw new Error('数量太少')
}
this.wheels = newVal;
},
get(){
return this.wheels
}
}
cart.set(6);//设值
console.log(cart.get());//取值
属性表达式
<script type="text/javascript">
/* const obj = {};
obj.isShow = true;
const name = 'a';
obj[name+'bc'] = 123;
console.log(obj);
obj['f'+'bc'] = function(){
console.log(this);
}
console.log(obj); */
//简写
const name = 'a';
const obj = {
isShow:true,
[name+'bc']:123,
['f'+'bc'](){
console.log(this);
}
}
console.log(obj);
</script>
对象的方法
- is()
- assign()
is()
等价于=== ,比较两个值是否严格相等
// === 的缺陷
console.log(NaN===NaN);//false
console.log(Object.is(NaN,NaN));//true
assign()
浅copy,用于对象的合并,返回合并之后的新对象。
Object.assign(target,obj1,obj2.....)
let o = Object.assign({},{a:1,b:2});
console.log(o);
Symbol类型
原始数据类型,它表示是独一无二的值。
最大用途:用来定义对象的私有变量
const name1 = Symbol('name');
const name2 = Symbol("name");
console.log(name1 === name2);//false
//定义私有变量
let s1 = Symbol('s1');
let obj = {};
obj[s1] = 'john';
//简写
let obj = {
[s1]:'john'
//不能这样写
//s1:'john',这样表示obj.s1
};
console.log(obj);
console.log(obj[s1]);
console.log(obj.s1);//undefined
注意:
- 如果用Symbol定义对象中的变量,取值时一定要用
[变量名],不能用.变量名 - Symbol定义的对象是不能进行遍历的
可以通过两个方法 获取Symbol声明的属性名(作为对象的key)
//方法一
let s = Object.getOwnPropertySymbols(obj);
console.log(s[0]);
//方法二
let m = Reflect.ownKeys(obj);
console.log(m);
Set类型
称为集合,表示一个无重复值的有序列表。
let set = new Set()创建
let set = new Set();
//添加元素
set.add(2);
set.add('2');
set.add('2');//重复添加会自行删除
set.add([1,2,3]);
console.log(set);
//删除元素
set.delete(2);
console.log(set);
//校验元素是否存在
console.log(set.has('2'));//true
//访问集合的长度
console.log(set.size);
//遍历,不推荐,毫无意义
set.forEach((val,key)=>{
console.log(val);
console.log(key);
});
//将set转化为数组,通过扩展运算符
let set2 = new Set([1,2,3,3,3,4]);
let arr = [...set2]
console.log(arr);//[1,2,3,4]
//了解
//1.set中对象的引用无法被释放
let set3 = new Set(),obj = {};
set3.add(obj);
//释放当前的资源
obj = null;
console.log(set3);
//用weakset,弱引用
let set3 = new WeakSet(),obj = {};
set3.add(obj);
//释放当前的资源
obj = null;
console.log(set3);
//WeakSet,不能传入非对象类型的参数,不可迭代,没有forEach,没有size
Map类型
键值对的有序列表,键和值可以是任意类型
let map = new Map() 创建
let map = new Map();
//设值
map.set('name','hello');
//取值
map.get('name');//hello
//校验
map.has('name');
//删除
map.delete('name');
//清除
map.clear();
//键值任意类型
map.set([1,2],'hello');
//初始化
let m =new Map([['a',1],['c',2]]);
console.log(m);
数组
扩展方法一
- from()
- of()
- copyWithin()
- find()
- findIndex()
from()
将伪数组转换成真正的数组
function add(){
console.log(arguments);//伪数组,不是真正的数组
//es5的做法
let arr = [].slice.call(arguments);
console.log(arr);
//es6的写法
let arr = Array.from(arguments);
console.log(arr);
//也可以通过扩展运算符
console.log([...arguments]);
}
add(1,2,3);
还可以接收第二个参数,用来对每个元素进行处理
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script type="text/javascript">
let lis = document.querySelectorAll("li");
//数据处理
let liContents = Array.from(lis, item => item.textContent);
console.log(liContents);
</script>
</body>
</html>
of()
将任意的数据类型,转换成数组
console.log(Array.of(3,11,20,'30',[1,2],{id:1}));
copyWithin()
数组内部将指定位置的元素复制到其他位置,返回当前数组
//从索引3位置往后的数值,替换从索引0往后的数值
console.log([1,2,3,8,9,10].copyWithin(0,3));//[8,9,10,8,9,10]
find() & findIndex()
常用
//find()找出第一个符合条件的数组成员
let num = [1,2,-10,-20,8,9,2].find(item=>item<0);
console.log(num);//-10
//findIndex()找出第一个符合条件的数组成员的索引
扩展方法二
- entries()
- keys()
- values()
返回一个遍历器,可以用for...of进行遍历
keys()
获取键,对键名的遍历
for (let index of ['a','b'].keys() ){
console.log(index); //0,1
}
values()
获取值,对值的遍历
for (let val of ['a','b'].values() ){
console.log(val); //a,b
}
entries()
对键值对的遍历
for (let [index,item] of ['a','b'].entries()){
console.log(index,item);
}
includes()
返回一个布尔值,表示某个数组是否包含给定的值
console.log([1,2,3].includes(2));//true
console.log([1,2,3].includes(4));//false