ES6(上)

151 阅读4分钟

为什么要学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

注意

  1. 如果用Symbol定义对象中的变量,取值时一定要用[变量名],不能用.变量名
  2. 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