ES6新特性

ES6 = ECMAScript 6

申明变量let和const

let

1、let申明变量不存在预解析;

1
2
3
console.log(flag);
let flag = 123;
//结果:报错

2、let声明的变量不允许重复

1
2
3
let flag = 123;
let flag = 456;
console.log(flag);

3、ES6引入了块级作用域

块内部定义的变量,在外部无法访问(PS: 只要被 { } 包裹起来,就形成块级作用域)

1
2
3
4
if (true){
let flag = 123;
}
console.log(flag);

4、let必须先声明在使用

因为用let申明的变量没有预解析

1
2
tem = 123;
let tem; //报错

const

const声明的常量不能被重新赋值,且在申明的同时就要被初始化

1
2
const n = 1;//申明的同时就要初始化
n = 2;//此处报错

变量的结构赋值

数组的解构赋值

1
2
3
// var a =1,b=2,c=3;//js中的写法
let [a,b,c] = [1,2,3];//node中 数组的解构赋值
console.log(a,b,c);// 1 2 3
1
2
3
//声明时赋初值
let [a=123,b,c] = [,456,];
console.log(a,b,c);// 123 456 undefined

利用解构赋值交换两个变量的值

1
2
3
4
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a,b);// 2 1

对象的解构赋值

1
2
let {foo,bar} = {foo : 'hello',bar : 'hi'};
console.log(foo,bar);

字符串的解构赋值

1
2
let [a,b,c,d,e] = "hello";
console.log(a,b,c,d,e);//h e l l o

字符串相关扩展

includes

include(str [,index]) str 所要匹配的字符串 ; index 从什么位置开始匹配

1
2
console.log('hello world'.includes('world');//true
console.log('hello world'.includes('world',7);//false

startsWith()

判断字符串是否特定字符串开始

1
console.log('admin/index.php'.startsWith('admin'));// true

endsWith()

判断字符串是否特定字符串结束

1
console.log('admin/index.php'.startsWith('php'));// true

模板字符串

在js中若要拼接字符串

1
2
3
4
5
6
7
var obj = {
name:'张三',
age:13,
gender:'男'
}
var str = '<div><span>'+obj.name+'</span><span>'+obj.age+'</span><span>'+obj.gender+'</span></div>';
console.log(str);//<div><span>张三</span><span>13</span><span>男</span></div>

利用模板字符串进行拼接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let obj = {
name:'张三',
age:13,
gender:'男'
}
let str = '<div>
<span>${obj.name}</span>
<span>${obj.age}</span>
<span>${obj.gender}</span>
<span>${1+1}</span>
<span>${fn('你好')}</span>
</div>';
console.log(str);
//<div>
// <span>张三</span>
// <span>13</span>
// <span>男</span>
// <span>2</span>
// <span>你好</span>
//</div>

函数的相关扩展

1、参数的默认值

2、参数的解构赋值

3、rest参数

4、…扩展运算符

5、箭头函数

参数的默认值

在js中的若要给函数参数指定默认值

1
2
3
4
5
6
function foo(param){
let p = param || 'hello';
console.log(p);
}
//foo();
//foo('nihao');

在ES6中给函数参数指定默认值

1
2
3
4
5
function foo(param = 'hello'){
console.log(p);
}
//foo();
//foo('nihao');

参数的解构赋值

默认参数的做法

1
2
3
4
5
function foo(param = 'hello' , age = 12){
console.log(param,age);
}
//foo();
//foo('nihao',18);

参数的解构赋值的做法

1
2
3
4
function foo({param,age}}){
console.log(param,age);
}
//foo({}); //注意 此时一定要传入一个对象
1
2
3
4
5
6
//添加默认参数
function foo({param = 'hello',age = 12}}){
console.log(param,age);
}
//foo({}); //注意 此时一定要传入一个对象
//foo({param = 'nihao',age = 18})

rest参数(剩余参数)

1
2
3
4
function foo(a,b,...param){ //...param会以数组的形式存储剩余的参数
console.log(param);
}
foo(1,2,3,4,5,6,7);//[3,4,5,6,7]

扩展运算符 …

使用 … 将数组拆撒后入参

1
2
3
4
5
6
7
8
9
function foo(a,b,c,d){
console.log(a + b + c + d);
}
//foo(1,2,3,4);//传统调用方式

//当要传入一个数组时 arr = [1,2,3,4]
//方法一 使用foo.apply(null,arr);
//方法二 使用 ... 将数组拆散
foo(...arr); //10

使用 … 合并数组

1
2
3
4
let arr1 = [1,2,3];
let arr2 = [4,5,6];
let arr3 = [...arr1,...arr2];
console.log(arr3);//[1,2,3,4,5,6]

箭头函数

1
2
3
4
5
//传统函数声明以及调用
function foo(参数列表){
函数体
}
foo();
1
2
3
//ES6 中新增的函数申明以及调用  =>
let foo = (形参参数列表) => {函数体};
foo(实参列表);
1
2
3
4
5
6
7
//用处 例子
var arr = [1,2,3,4];
//arr.forEach(function(e,index){
// console.log(e);
// console.log(index);
//});
arr.forEach((e,index) => {console.log(e);console.log(index)});

箭头函数的注意事项

1、箭头函数中this取决于函数的定义,而不是函数的调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//不使用箭头函数时 this取决于调用者  此时是window
var obj = {
name:"张三",
doSomething: function(){
setTimeout(function(){
console.log(this);
},1000);
}
}
obj.doSomething();//window

//使用箭头函数中的this 取决函数声明的环境 此时是在obj中声明的 则this指向obj
var obj = {
name:"张三",
doSomething: function(){
setTimeout(()=>{
console.log(this);
},1000);
}
}
obj.doSomething();//obj{name:"张三"}

2、箭头参数不可以new

3、箭头函数不可以使用arguments获取参数列表,可以使用rest代替

1
2
let foo = (...param) => console.log(param);
foo(1,2,3,4);

数组的扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let a = ["a","b","c"].keys(); //Array.keys()  返回数组的所有下标[0,1,2]
console.log(a.next()); //迭代返回当前位置的下标 0
console.log(a.next()); //1
console.log(a.next()); //2

let b = ["a","b","c"].values(); //Array.values() 返回数组的所有值
console.log(b.next()); //迭代返回当前位置的值 a
console.log(b.next()); //b
console.log(b.next()); //c

//数组查找
{
console.log([1,2,3,4,5,6].find((item)=>{ //find 返回满足条件的第一个元素值
return item>3;
}));

console.log([1,2,3,4,5,6].filter((item)=>{ //filter 返回满足条件的所有元素值
return item>3;
}));

console.log([1,2,3,4,5,6].findIndex((item)=>{ //findIndex 返回满条件的第一个元素下标
return item>3;
}));
}

//数组包含
{
let arr = [123,456,7,8,9,NaN];
console.log(arr.includes(456));//Array.includes(item);在数组中查询有无item元素 返回boolean

//也可以查询有无非数字
console.log([1,2,NaN].includes(1));
console.log([1,2,NaN].includes(NaN));
}

Symbol

ES6新增数据类型 属于基本数据类型,Symbol不可以new

Symbol声明的变量是唯一的,意义在于减少命名冲突;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
//Symbol的变量是唯一的,所以a1和a2永远不相等
let a1 = Symbol();
let a2 = Symbol();
console.log(a1 === a2);

//Symbol.for(key)
//在使用Symbol时 会生成一个全局注册表,其中的数据以键值对的形式存在;能根据key来拿到对应的value
//若 a3 a4的key是相同的 那么a3 a4是相同的
let a3 = Symbol.for("a3");
let a4 = Symbol.for("a3");
console.log(a3 === a4); //true

//问题 若改变a3的值 a4的值会改变吗?
//是值复制 还是指针

}

ES6中涉及到的数据结构

数组Array

数组中的元素可以重复,且数组中元素的排列是有序的(因此可以通过下标访问)

集合Set

集合的元素是唯一的,不可以重复出现,且集合中的元素是无序的(因此无法通过下标访问集合中的元素)

Set中的方法

set.add(ele) 向set集合中追加ele元素
set.has(ele) 判断set集合中是否存在ele元素
set.delete(ele) 从集合中删除ele元素
set.clear() 清空set集合
set.forEach( (ele) =>{} ) 遍历集和

set对象的创建:

1
let set = new set();

数组与集合的互相转换

数组==>集合

1
2
let arr = [1,2,3];
let set = new set(arr);

集合==>数组

1
2
let set = new set();
let arr = [...set];

weakSet

WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有下面区别。

​ 1.WeakSet 的成员只能是对象,而不能是其他类型的值。

​ 2.WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不 再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。

​ 3.WeakSet 只有add/delete/clear/has三个方法,不能遍历,没有size属性等

Map

Map也是由键值对构成的,和对象的区别在于Map的key也可以是一个对象,Object只可以是字符串

代理和反射

代理Proxy

代理:通过代理对象访问目标对象

作用:

​ 1、控制目标对象的访问权限

​ 2、扩展目标对象方法

创建目标对象

1
2
3
4
5
6
7
let targetObject = {
name:"target",
type:"object",
fun:function(){
console.log('目标对象的fun');
}
}

创建代理对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
var p = new Proxy(targetObject,{
//target 就是目标的对象
//key 就是目标对象中的每一个属性和方法
//当代理对象直接获取属性和方法的等信息的时候都会来调用get方法
get(target,key){
if(key === 'fun'){
console.log("代理对象调用目标对象的fun");
}
return target[key];
},
//当给对象的属性和方法赋值的时候调用set方法
//target 就是目标的对象
//key 就是目标对象中的每一个属性和方法
//value 属性值
set(target,key,value){
//如果key为type的时候就不给目标对象赋值
if(key === 'type'){
return target[type];
}
else{
target[key] = value;
}
},
//当通过 xx in obj 的时候调用has方法
has(target,key){
if(key === 'type'){
return false;
}
else{
return true;
}
},
//当删除对象的属性时 调用此方法
deleteProperty(target,key){
if(key === 'age'){
delete target[key];
return true;
}
else{
return false;
}
}
});
1
2
3
4
5
6
7
8
9
10
11
12
p.fun(); //代理对象调用目标对象的fun     目标对象的fun
p.name = 'temp'; //修改无效 当使用点的方式来访问属性时 会调用set函数 而set函数中设置了对name的修改权限
console.log(p); //{ name: 'target', type: 'object', fun: [Function: fun] }
p.type = 'temp'; //修改成功 set中没有对type的权限要求
console.log(p); //{ name: 'target', type: 'temp', fun: [Function: fun] }

console.log('type' in p); //true 当使用in判断对象中是否有某属性时 会调用has函数 而我们在has中对type设置了权限 则无法访问
console.log('name' in p); //true 未对name设置 则访问成功

delete p.name; //删除失败 当使用点的方式来删除某属性时会默认调用deleteProperty方法 而我们在deleteProperty中限制了对name的删除权限 则删除失败
delete p.type; //删除成功
console.log(p); //{ name: 'target', fun: [Function: fun] }

反射Reflect

​ 反射机制是指程序在运行的时候访问、检测和修改它本身状态或行为的一种能力,例如一个对象能够在运行时知道自己有哪些方法和属性。

​ 反射的概念在编译型的编程语言中比较明显,比如java、C#、Object-c等。对于 JavaScript来说,反射就是获取对象的内部结构的信息,所以JS中的反射随处可见,比如for…in方式遍历对象。

​ 从ECMAScript6开始,JS引入Reflect这个API专门用于操作反射。

​ ES6中的反射,将抛出异常,异常捕获简化为返回一个boolean值来表示其是否正常运行

1
2


最后更新: 2019年09月02日 11:08

原始链接: https://HowlCN.github.io/2018/07/19/ES6语法/

× 请我吃糖~
打赏二维码