ES6学习之二

本文的学习来自技术胖大神的教程:https://jspang.com/ 

 

1扩展运算符和rest运算符

扩展运算符和rest运算符,它们都是…(三个点)。

它们有很多相似之处,甚至很多时候不用特意去区分。

它们可以很好的解决参数和对象数组未知情况下的编程,让代码更健壮和简洁。

 

1.1对象扩展运算符(…)

当编写一个方法时,允许它传入的参数是不确定的。这时候可以使用对象扩展运算符来作参数。

例:

function test(...arg){
    console.log(arg[0]);
    console.log(arg[1]);
    console.log(arg[2]);
    console.log(arg[3]);
}            
test(1,2,3);

  

说明可以传入多个值,并且就算方法中引用多了也不会报错。

 

1.2扩展运算符的用处

例1:声明两个数组arr1和arr2,然后把arr1赋值给arr2,然后改变arr2的值:

let arr1=['a','b','c'];
let arr2=arr1;
console.log(arr2);
arr2.push('d');
console.log(arr1);

 

可以看到arr1的值也改变了,因为这是对内存堆栈的引用,而不是真正的赋值。

 

利用对象扩展运算符简单的解决这个问题:

let arr1=['a','b','c'];
let arr2=[...arr1];
console.log("arr2:",arr2);
arr2.push('d');
console.log("arr1:",arr1);
console.log("arr2:",arr2);

可以看到arr1并没有改变。

 

1.3 rest运算符

例:

function test(first,...arg){
    console.log(arg.length);
}
test(1,2,3,4,5,6);

第一个参数1传给了first,剩下的参数传给了arg数组,所以arg长度为5

 

1.4循环输出rest运算符

可以用for…of循环,for…of的循环可以避免开拓内存空间,增加代码运行效率:

function test(first,...arg){
    for(let val of arg){
        console.log(val);
    }
}
test(1,2,3,4,5,6);

 

2 ES6新增的数字操作

2.1二进制声明(不是ES6特性)

二进制的英文单词是Binary,二进制的开始是0(零),然后第二个位置是b(大小写都可以实现),然后跟上二进制的值就可以了。

 

2.2八进制声明(不是ES6特性)

八进制的英文单词是Octal,也是以0(零)开始的,然后第二个位置是O,然后跟上八进制的值就可以了。 

例:

//二进制声明
let binary=0B010101;
console.log('二进制binary:',binary);

//八进制声明
let octal=0O777;
console.log('八进制octal:',octal);

 

2.3数字验证

可以用Number.isFinite( )进行数字验证,只要是数字,不论是浮点型还是整形都会返回true,其他时候会返回false

console.log(Number.isFinite(888));
console.log(Number.isFinite(11/4));
console.log(Number.isFinite('abc'));
console.log(Number.isFinite(NaN));
console.log(Number.isFinite(undefined));

 

2.4 NaN验证

NaN是特殊的非数字,可以使用Number.isNaN()来进行验证

console.log(Number.isNaN(0));
console.log(Number.isNaN(NaN));

 

2.5判断是否为整数

Number.isInteger()
console.log(Number.isInteger(100));
console.log(Number.isInteger(99.99));

 

2.6转换

整数转换Number.parseInt()

浮点型转换Number.parseFloat()

let a='9.99';
let b='aaa';
console.log(Number.parseInt(a));
console.log(Number.parseFloat(a));
console.log(Number.parseInt(b));
console.log(Number.parseFloat(b));

 

2.7整数取值范围

整数的操作是有一个取值范围的,就是-(253-1)到253-1。

在计算时会经常超出这个值,所以要进行判断,ES6提供了两个常数,就不用去计算了,直接用就可以:

//最大安全整数
console.log(Number.MAX_SAFE_INTEGER);
//最小安全整数
console.log(Number.MIN_SAFE_INTEGER);

 

安全整数判断:

let c=Math.pow(2,53);
let d=Math.pow(2,53)-1;
console.log(Number.isSafeInteger(c));
console.log(Number.isSafeInteger(d));

 

3新增的数组知识

3.1 JSON数组格式转换:Array.from()方法

JSON的数组格式就是为了前端快速的把JSON转换成数组的一种格式

例:

let json={
    0:1,
    1:2,
    2:'abc',
    length:3
}

这就是一个标准的JSON数组格式(注意key值就是0,1,2...,不能随意起别的键名),跟普通的JSON对比是在最后多了一个length属性,没有length就只是字符串,有length才是数组。

 

这种特殊的json格式可以使用ES6的语法转变成数组:

let json={
    0:1,
    1:2,
    2:'abc',
    length:3
}
let arr=Array.from(json);
console.log(arr);

 

3.2 Array.of()方法

可以把一堆文本或者变量转换成数组。(之前可以用eval来进行转换,但是eval的效率很低,会拖慢程序,所以尽量不要用)

例:

let arr=Array.of(1,2,3,4);
console.log(arr);

let arr2=Array.of('a','b','c');
console.log(arr2);

 

3.3 find()方法

find()是一个实例方法,实例方法就是必须有一个已经存在的数组来调用,而前面两个方法是用Array对象直接调用的。

(java中曾学过静态方法和实例方法,所以这里很好理解)

 

find方法是从数组中查找,需要传入一个匿名函数,函数需要传入三个参数:

         value:表示当前查找的值。

         index:表示当前查找的数组索引。

         arr:表示当前数组。

 

在函数中如果找到符合条件的数组元素就进行return,并停止查找。如果没有满足条件的,就返回undefinded。

 

例1:

let arr=[1,2,3,4,5];
console.log(arr.find(function(val,index,arr){
    return val>3;
}));

 

例2:

let arr1=['a','b','c'];
console.log(arr1.find(function(val,index,arr){
    return val=='d';
}));

 

3.4 fill()方法

fill()也是一个实例方法,它的作用是把数组进行填充,它接收三个参数,第一个参数是填充的变量,第二个是开始填充的位置,第三个是填充到的位置。

 

 

例:

let arr=[1,2,3,4,5];
arr.fill('abc',2,4);
console.log(arr);

 

3.5数组的遍历

1) for…of循环

这种形式比ES5的for循环要简单而且高效,比普通for少声明一个i,这个i用完就没意义了。

(for of就类似java中的增强for)

例:

let arr=[1,2,3,4,5];
for(let item of arr){
    console.log(item);
}

 

输出数组索引:

let arr=[1,2,3,4,5];
for(let index of arr.keys()){
    console.log(index);
}

 

同时输出数组的内容和索引:

let arr2=['你好','abc','12345'];
for(let [index,item] of arr2.entries()){
    console.log(index+':'+item);
}

 

2)forEach

forEach循环会自动省略为空的数组元素,相当于直接筛空了。

let arr=['abc','123','Hello'];
arr.forEach((val,index)=>console.log(index,val));

 

(这里用了箭头函数,先用一下,后面会再详细写)

 

3)filter

let arr=['abc','123','Hello'];
arr.filter(x=>console.log(x));

 

4)some

let arr=['abc','123','Hello'];
arr.some(x=>console.log(x));

 

5)map

map起到一个替换的作用:

let arr=['abc','123','Hello'];
console.log(arr.map(x=>'替换后的值'));

 

3.6数组转换字符串

1)join()方法

join()方法就是在数组元素中间,加了一些间隔,开发中很有用处。

let arr=['abc','123','Hello','你好'];
console.log(arr.join('-'));

 

2)toString()方法

转换时只是用逗号隔开了:

let arr=['abc','123','Hello','你好'];
console.log(arr.toString());

 

3.7 entries()方法

entries()生成的是Iterator形式的数组,这种形式的好处是可以在需要时用next()手动跳转到下一个值。Entries的意思是条目。 

例:

let arr=['abc','你好','学习es6'];
let list=arr.entries();
console.log(list);
console.log(list.next().value);

 

当想生成一些不规则的循环时,就可以用entries,这就叫手动循环。(上面的for of循环叫自动循环)

例:

let arr=['abc','你好','学习es6'];
let list=arr.entries();
console.log(list.next().value);
console.log('---------------');
console.log(list.next().value);
console.log('***************');
console.log(list.next().value);
console.log('@@@@@@@@@@@@@@@');
console.log(list.next().value);

 

3.8 in的用法

in是用来判断对象或者数组中是否存在某个值的。

例:对象判断

let obj={
    a:'你好',
    b:'你是谁'
}
console.log('a' in obj);
console.log('你好' in obj);

说明判断的是key值

 

例:数组判断:

以前会使用length属性进行判断,其存在弊端:

let arr=[,,,];
console.log(arr.length); 

数组中其实全是空值,却输出了长度为3,这是不准确的。

 

用ES6的in就可以解决这个问题:

let arr=[,,,];
console.log(0 in arr); 

let arr2=[1,2,3,];
console.log(0 in arr2);

注意:这里的0指的是数组下标位置是否为空。

 

4新增的函数知识

4.1参数的默认值 

function fun1(a,b=1){
    return a+b;
}
console.log(fun1(2));

 

4.2主动抛出错误

function fun2(a){
    if(a==1){
        throw new Error("这里报错了!");
    }
    return a+b;
}
console.log(fun2(1));

 

4.3严谨模式

之前严谨模式必须写在代码最上边,相当于全局使用,在ES6中可以写在函数体中,相当于针对函数来使用。

例:

function fun3(a,b=2){
    'use strict'
    return a+b;
}
console.log(fun3(1));

说明使用了默认值,再使用严谨模式的话,就会有冲突。

 

把默认值去掉:

function fun3(a,b){
    'use strict'
    return a+b;
}
console.log(fun3(1,2));

 

4.4获得需要传递的参数个数

function fun4(a,b){
    return a+b;
}
console.log(fun4.length);

 

如果加上默认值:

function fun4(a,b=1){
    return a+b;
}
console.log(fun4.length);

这说明length表示必须传入的参数个数。

 

4.5对象的函数解构

实际作用:后端经常返回来JSON格式的数据,直接把这个JSON格式数据当作参数,传递到函数内部进行处理。

例:

let json={
    a:'abc',
    b:'123'
}
function fun({a,b}){
    console.log(a,b);
}
fun(json);

这样方便了很多,不用一个个传递参数了。

 

4.6数组的函数解构

let arr=['abc','123','哈哈'];
function test(a,b,c){
    console.log(a,b,c);
}
test(...arr);

 

4.7最后的参数可以带逗号

之前是不能有,有了报错,现在没关系了

function show(a,b,c,){
    console.log(a,b,c);
}
show(1,2,3,);

这个在实际开发中会带来方便。

 

4.8箭头函数

箭头函数使用频率非常高,所以单独总结了:

https://www.cnblogs.com/hzhjxx/p/12046043.html

 

5 ES6中对象

5.1对象赋值

原来怎么赋值的:

let name='小笼包';
let age=18;

let obj={
    name:name,
    age:age
}
console.log(obj);

 

ES6允许把声明的变量直接赋值给对象。不用写key值了,直接把变量放进去,这样就大大简化了:

let name='小笼包';
let age=18;

let obj={name,age}
console.log(obj);

 

5.2对象Key值构建

有时候前台不知道key值的名称,是要从后台取的,这时可以用[ ] 的形式,进行对象的构建:

let key='name';
let obj={
    [key]:'前台定义的值'
}
console.log(obj);

 

5.3 is()方法

把两个对象进行比较。

之前可以用===来比较:

let obj1={name:'名字'};
let obj2={name:'名字'};
console.log(obj1.name===obj2.name);

 

现在可以用is方法:

let obj1={name:'名字'};
let obj2={name:'名字'};
console.log(Object.is(obj1.name,obj2.name));

 

 

这两种比较的区别:

===为同值相等,is()为严格相等

console.log(+0===-0);
console.log(Object.is(+0,-0));

 

console.log(NaN===NaN);
console.log(Object.is(NaN,NaN));

 

5.4 assign()合并对象

let a={
    name:'名字'
}
let b={
    age:20
}
let c={
    like:'web'
}
let d=Object.assign(a,b,c);
console.log(d);

 

如果有重复的key值,后面的会覆盖前面的:

let a={
    name:'名字'
}
let b={
    age:20,
    name:'名字2'
}
let c={
    like:'web',
    age:22,
}
let d=Object.assign(a,b,c);
console.log(d);

 

6 Symbol在对象中的应用

6.1用Symbol构建对象的Key

let sy=Symbol();
let obj={
    [sy]:'sy的值'
}
console.log(obj[sy]);
obj[sy]='新值';
console.log(obj[sy]);

 

6.2 Symbol对象元素的保护作用

在对象中有很多值,但是循环输出时,并不希望全部输出,就可以使用Symbol进行保护

let obj={
    name:'名字',
    like:'吃'    
}
let age=Symbol();
obj[age]=18;
console.log(obj);
for(let item in obj){
    console.log(obj[item]);
}

可以看到,age被保护了。

 

7 Set和WeakSet数据结构

Set的定义和一些常用方法可以看这里:https://www.cnblogs.com/hzhjxx/p/11460420.html

 

7.1set的遍历

1)用for...of

let setArr=new Set(['abc','Hello','123']);
for(let item of setArr){
    console.log(item);
}

 

2)forEach:

let setArr=new Set(['abc','Hello','123']);
setArr.forEach((val)=>console.log(val));

 

7.2 WeakSet

注意不能直接在new 的时候放入值,会报错,要先把对象定义好,再用add方法添进去。

let weakObj=new WeakSet();
let obj={
    name:'大美女',
    age:'18'
}
weakObj.add(obj);
console.log(weakObj);

 

WeakSet里边的值不允许有重复的对象:

let weakObj=new WeakSet();
let obj={
    name:'大美女',
    age:'18'
}
let obj2={
    name:'大美女',
    age:'18'
}
weakObj.add(obj);
weakObj.add(obj2);
console.log(weakObj);

因为obj和obj2不是同一个对象。

 

如果是同一个:

let weakObj=new WeakSet();
let obj={
    name:'大美女',
    age:'18'
}
let obj2=obj;
weakObj.add(obj);
weakObj.add(obj2);
console.log(weakObj);

 

8 Map数据结构

先看一个json对象的取值:

let json={
    name:'大美女',
    age:18
}
console.log(json.name);

这种方法其实是需要遍历整个对象进行寻找的,所以效率要比数组低。

 

8.1声明Map

let map=new Map();

 

用set方法添加值:

let json={
    name:'大美女',
    age:18
}
let map=new Map();
map.set(json,'me');
console.log(map);

map的灵活性就在此,key值和value值可以没规律,可以是任意类型。

 

8.2方法和属性

let json={
    name:'大美女',
    age:18
}
let map=new Map();

//添加值
map.set(json,'me');
map.set('me2',json);

//长度
console.log(map.size);

//取值
console.log(map.get(json));
console.log(map.get('me2'));

//查找
console.log(map.has(json));

//删除
map.delete(json);
console.log(map);

//清空
map.clear();
console.log(map);

Map应用广泛,因为他更灵活,更高效。

 

9用Proxy进行预处理

当操作一个对象或者方法时会有几种动作,例如在运行函数前初始化一些数据,在改变对象值后做一些善后处理。这些都算钩子函数。

Proxy的存在就可以给函数加上这样的钩子函数,可以理解为在执行方法前预处理一些代码。也可以简单的理解为是函数或者对象的生命周期。

Proxy的应用可以使函数更加强大,业务逻辑更加清楚,而且在编写自己的框架或者通用组件时非常好用。

 

9.1声明Proxy

new Proxy({},{});

第一个花括号相当于方法的主体,后边的花括号就是Proxy代理处理区域,相当于写钩子函数的地方。

 

9.2 get属性

get属性是在得到某对象属性值时预处理的方法,它接收三个参数:

target:得到的目标值

key:目标的key值,相当于对象的属性

property:这个不太常用

 

9.3 set属性

set属性是要改变Proxy属性值时,进行的预先处理。它接收四个参数:

target:目标值。

key:目标的Key值。

value:要改变的值。

receiver:改变前的原始值。

 

例:

let pro=new Proxy({
    add:function(val){
        return val+10;
    },
    name:'这是我的名字'
},{
    get:function(target,key,property){
        console.log('运行get');
        return target[key];
    },
    set:function(target,key,value,receiver){
        console.log('运行set');
        return target[key]=value;
    }
});
console.log(pro.name);
pro.name='新名字';
console.log(pro.name);

 

9.4 apply

apply是对方法的预处理

let target = function () {
    return 'Hello';
};
var handler = {
    apply(target, ctx, args) {
        console.log('apply运行了');
        return Reflect.apply(...arguments);
    }
} 
var pro = new Proxy(target, handler); 
console.log(pro());

 

10 promise对象的使用

promise很好的解决了回调地狱的问题。

ES5的时候,在多层嵌套回调时,代码层次过多,很难进行维护和二次开发。

promise可以完美解决这个问题。

promise这个单词是“承诺”,当它成功时执行一些代码,当它失败时执行一些代码。它更符合人类的行为思考习惯。

 

promise执行多步操作非常好用。模仿一个多步操作的过程:

let state=1;
function step1(resolve,reject){
    console.log('第一步:做饭');
    if(state==1){
        resolve('做饭完成');
    }else{
        reject('做饭失败');
    }
}
function step2(resolve,reject){
    console.log('第二步:吃饭');
    if(state==1){
        resolve('吃饭完成');
    }else{
        reject('吃饭失败');
    }
}
function step3(resolve,reject){
    console.log('第三步:洗碗');
    if(state==1){
        resolve('洗碗完成');
    }else{
        reject('洗碗失败');
    }
}

new Promise(step1).
then(function(val){
    console.log(val);
    return new Promise(step2);
}).
then(function(val){
    console.log(val);
    return new Promise(step3);
}).
then(function(val){
    console.log(val);
    return val
});

 

如果某一步出错:

 

promise可以让代码更加的结构化。在现在的开发中使用率算是最高的。

 

11 class类的使用

11.1类的声明

class Coder{
    name(val){
        console.log(val);
    }
}
let me=new Coder;
me.name('你的名字');

 

当有多个方法时:

class Coder{
    name(val){        
        return val;
    }
    skill(val){
        console.log(this.name('张三')+'的技能是'+val);
    }
}
let me=new Coder;
me.skill('web开发');

 

注意方法和方法中间不要写逗号,this指类本身。

 

11.2类的传参

用constructor( )进行传参。传递参数后可以直接使用this.xxx进行调用。

class Coder{    
    constructor(a,b){
        this.a=a;
        this.b=b;
    }
    add(){
        return this.a+this.b;
    }
}
let me=new Coder(1,2);
console.log(me.add());

 

11.3 class的继承

class Coder{
    name(val){        
        console.log(val);
    }    
}
class Htmler extends Coder{
    
}
let me=new Htmler;
me.name('我是一个切图人员');

 

注意在写类的时候和ES5中的对象和构造函数要区分开,不要学混了。

 

12模块化操作

模块化操作主要包括两个方面:

export:模块的输出。

import:模块的引入。

 

谷歌浏览器地址栏中输入:

chrome://flags/,然后搜索javascript,把Experimental JavaScript设为启用:

 

引入js文件时,要加上type="module"

这样就可以直接预览效果了。

 

12.1 export的用法

export可以把变量,函数,对象进行模块化,提供外部调用接口,让外部进行引用。

 

12.1.1把一个变量模块化

temp.js:

export var a='abc';

 

index.js:

import {a} from './temp.js';
console.log(a);

 

index.html:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <script type="module" src="index.js"></script>
    </body>
</html>

 

12.1.2多变量的输出

temp.js:

var a='aaa';
var b='bbb';
var c='ccc';

export {a,b,c}

 

index.js:

import {a,b,c} from './temp.js';
console.log(a,b,c);

 

12.1.3函数的模块化输出

temp.js:

export function test(a,b){
    return a+b;
}

 

index.js:

import {test} from './temp.js';
console.log(test(10,20));

 

12.1.4 as的用法

有时候不想暴露模块里的变量名称,而给模块起一个更语义化的名称,可以使用as来操作。

temp.js:

var a='张三';
var b=18;
export {
    a as name,
    b as age
}

 

index.js:

import {name,age} from './temp.js';
console.log(name,age);

 

12.2 export和export default的区别

加上default相当于是一个默认的入口。在一个文件里export default只能有一个。

例1:写两个export:

temp.js:

export var a ='aaa'; 
export function add(a,b){
    return a+b;
}

 

index.js:

import {a,add} from './temp.js';
console.log(a,add(10,20));

 

例2:export default

export default var a=12345';
import str from './temp';

这时import可以不写{},而且可以自定义命名。

(这里在chrome预览时报错,以后还是找个方式打包一下,等学完webpack再修改这里。)

 

总结

开发时尽量使用ES6语法,多用才熟练。如果生产环境不兼容,可以写完再用babel等工具转换。

posted @ 2019-12-23 13:49  后知后觉0107  阅读(243)  评论(0编辑  收藏  举报