重开ES6

一、ES6的开发环境搭建

现在的Chrome浏览器已经支持ES6了,但是有些低版本的浏览器还是不支持ES6的语法,这就需要我们把ES6的语法自动的转变成ES5的语法。

1、建立工程目录:

先建立一个项目的工程目录,并在目录下边建立两个文件夹:src和dist

  • src:书写ES6代码的文件夹,写的js程序都放在这里。
  • dist:利用Babel编译成的ES5代码的文件夹,在HTML页面需要引入的时这里的js文件。

编写index.html:

文件夹建立好后,我们新建一个index.html文件。

<!DOCTYPE html>
<html lang="en">
    <head>
        <title></title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="./dist/index.js"></script>
    </head>
    <body>
        Hello ECMA Script 6
    </body>
</html>

需要注意的是在引入js文件时,引入的是dist目录下的文件。

编写index.js

在src目录下,新建index.js文件。这个文件很简单,我们只作一个a变量的声明,并用console.log()打印出来。

let a=1;
console.log(a);

我们用了let声明,这里let是ES6的一种声明方式,接下来我们需要把这个ES6的语法文件自动编程成ES5的语法文件。

初始化项目

在安装Babel之前,需要用npm init先初始化我们的项目。打开终端或者通过cmd打开命令行工具,进入项目目录,输入下边的命令:

npm init -y

-y代表全部默认同意,就不用一次次按回车了。命令执行完成后,会在项目根目录下生产package.json文件。

{
  "name": "es6",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

可以根据自己的需要进行修改,比如我们修改name的值。

全局安装Babel-cli

在终端中输入以下命令,如果你安装很慢的话,可以使用淘宝镜像的cnpm来进行安装。安装cnpm的方法,大家自己百度吧。

npm install -g babel-cli

 

虽然已经安装了babel-cli,只是这样还不能成功进行转换,如果你不相信可以输入下边的命令试一下。

babel src/index.js -o dist/index.js

 

你会发现,在dist目录下确实生产了index.js文件,但是文件并没有变化,还是使用了ES6的语法。因为我们还需要安装转换包才能成功转换,继续往下看吧。

本地安装babel-preset-es2015 和 babel-cli

npm install --save-dev babel-preset-es2015 babel-cli

 

安装完成后,我们可以看一下我们的package.json文件,已经多了devDependencies选项。

"devDependencies": {
    "babel-cli": "^6.24.1",
    "babel-preset-es2015": "^6.24.1"
  }

新建.babelrc

在根目录下新建.babelrc文件,并打开录入下面的代码(mac系统需要通过创建完毕普通文件后通过Cli方式在终端里通过mv 原来文件 .新文件方式创建

{
    "presets":[
        "es2015"
    ],
    "plugins":[]
}

这个文件我们建立完成后,现在可以在终端输入的转换命令了,这次ES6成功转化为ES5的语法。

babel src/index.js -o dist/index.js

简化转化命令:

在学习vue 的时候,可以使用npm run build 直接利用webpack进行打包,在这里也希望利用这种方式完成转换。打开package.json文件,把文件修改成下面的样子。

{
  "name": "es6",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "babel src/index.js -o dist/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-cli": "^6.24.1",
    "babel-preset-es2015": "^6.24.1"
  }
}

修改好后,以后我们就可以使用 npm run build 来进行转换了。

 

二、新的声明方式

以前我们在声明时只有一种方法,就是使用var来进行声明,ES6对声明的进行了扩展,现在可以有三种声明方式了。

字面理解ES6的三种声明方式:

  1. var:它是variable的简写,可以理解成变量的意思。
  2. let:它在英文中是“让”的意思,也可以理解为一种声明的意思。
  3. const:它在英文中也是常量的意思,在ES6也是用来声明常量的,常量你可以简单理解为不变的量。

var声明:

var在ES6里是用来声明全局变量的,我们可以先作一个最简单的实例,用var声明一个变量a,然后用console.log进行输出。

var a="Gavin"
console.log(a)

可以看到结果是Gavin,如果在全局与局部都声明a,可以发现全局声明的结果会被局部声明覆盖

var a="Gavin"
{
    var a="Tom"
}
console.log(a)

let局部声明

通过两个简单的例子,我们对var的全局声明有了一定了解。那跟var对应的是let,它是局部变量声明。还是上面的例子,我们试着在区块里用let声明:

var a="Gavin"
{
    let a="Tom";
    console.log(a);
}
console.log(a);

这个例子中可以看到局部使用let声明不会影响到var原来的声明值

使用let的好处是使用let声明,不会污染到外部的数据

{
    for(let a=0;a<4;a++){
        console.log('循环体内'+a);
    }
}
console.log("循环体外" + a);

对比之下,如果使用var声明,会发现循环体外的值也跟着改变了

 

const声明常量

在程序开发中,有些变量是希望声明后在业务层就不再发生变化了,简单来说就是从声明开始,这个变量始终不变,就需要用const进行声明。

我们来一段用const声明错误的代码,在错误中学习const的特性也是非常好的。

const a="Gavin";
var a="xiaopi";
console.log(a);

在编译这段代码的过程中,你就会发现已经报错,无法编译了,原因就是我们const声明的变量是不可以改变的。

 

三、变量的解构赋值

ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。解构赋值在实际开发中可以大量减少我们的代码量,并且让我们的程序结构更清晰

数组的解构赋值:

简单的数组解构:

以前,为变量赋值,我们只能直接指定值。比如下面的代码:

let a=0;
let b=1;
let c=2;

而现在我们可以用数组解构的方式来进行赋值。

let [a,b,c]=[1,2,3];

上面的代码表示,可以从数组中提取值,按照位置的对象关系对变量赋值。

数组模式和赋值模式统一:

可以简单的理解为等号左边和等号右边的形式要统一,如果不统一解构将失败。

let [a,[b,c],d]=[1,[2,3],4];

如果等号两边形式不一样,很可能获得undefined或者直接报错。

解构的默认值:

解构赋值是允许你使用默认值的,先看一个最简单的默认是的例子。

let [foo = true] =[];
console.log(foo); //控制台打印出true
let [a,b="Gavin"]=['小皮']
console.log(a+b); //控制台显示“小皮Gavin”

 

  现在我们对默认值有所了解,需要注意的是undefined和null的区别。

let [a,b="gavin"]=["xiaopi",undefined];
console.log(a+b)

undefined相当于什么都没有,b是默认值。

let [a,b="gavin"]=['xiaopi',null];
console.log(a+b)

null相当于有值,但值为null。所以b并没有取默认值,而是解构成了null。

 

对象的解构赋值

解构不仅可以用于数组,还可以用于对象。

let {foo,bar}={bar:"gavin",foo:'xiaopi'}
console.log(foo,bar)

注意:对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

圆括号的使用

如果在解构之前就定义了变量,这时候你再解构会出现问题。下面是错误的代码,编译会报错。

let a;
{a} = {a:'gavin'};
console.log(a)

要解决报错,使程序正常,我们这时候只要在解构的语句外边加一个圆括号就可以了。

let a,b;
({a,b="kk"} = {a:'gavin'});
console.log(a+b)

字符串解构

字符串也可以解构,这是因为,此时字符串被转换成了一个类似数组的对象。

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

 

四、扩展运算符与rest运算符

对象扩展运算符(…):

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

function abc(...arg) {

    console.log(arg[0]);
    console.log(arg[1]);
    console.log(arg[2]);
    console.log(arg[3]);
}
abc(1,2,3);

这时我们看到控制台输出了 1,2,3,undefined,这说明是可以传入多个值,并且就算方法中引用多了也不会报错。

扩展运算符的用处:

我们先用一个例子说明,我们声明两个数组arr1和arr2,然后我们把arr1赋值给arr2,然后我们改变arr2的值,你会发现arr1的值也改变了,因为我们这是对内存堆栈的引用,而不是真正的赋值,这个类似于python的浅拷贝,两个变量指向同样的变量值内存地址空间

let arr1=['aaa','bbb','ccc'];
let arr2=arr1;
console.log(arr2);
arr2.push('dddd');
console.log(arr1);

这是我们不想看到的,可以利用对象扩展运算符简单的解决这个问题,现在我们对代码进行改造。

let arr1=['aaa','bbb','ccc'];
let arr2=[...arr1];
arr2.push('dddd');
console.log(arr2);
console.log(arr1);

现在控制台预览时,你可以看到我们的arr1并没有改变,简单的扩展运算符就解决了这个问题。

rest运算符

如果你已经很好的掌握了对象扩展运算符,那么理解rest运算符并不困难,它们有很多相似之处,甚至很多时候你不用特意去区分。它也用…(三个点)来表示,我们先来看一个例子。

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

这时候控制台打印出了7,说明我们arg里有7个数组元素,这就是rest运算符的最简单用法。

如何循环输出rest运算符

这里我们用for…of循环来进行打印出arg的值,我们这里只是简单使用一下,以后我们会专门讲解for…of循环。

function abc(first,...arg) {
    for(let val of arg){
        console.log(val);
    }


};
abc(0,1,2,3,4,5,6,7);

for…of的循环可以避免我们开拓内存空间,增加代码运行效率,所以建议大家在以后的工作中使用for…of循环。有的小伙伴会说了,反正最后要转换成ES5,没有什么差别,但是至少从代码量上我们少打了一些单词,这就是开发效率的提高。

 

五、字符串模板

在开启新旅程前,先使用live-server来简化我们的调试模式,首先,新建一个目录,然后执行npm init -y 再,创建index.html与index.js,安装live-server(cnpm install live-server -g)如果以前安装了这里就无需安装了,执行live-server让它自动协助编译

字符串模版

先来看一个在ES5下我们的字符串拼接案例:

var x='Gavin';
var str='这是一个字符串模板,让我们增加一个变量进来'+x+'..可以看到它增加进来了'
document.write(str);

ES6新增了字符串模版,可以很好的解决这个问题。字符串模版不再使用‘xxx’这样的单引号,而是换成了xxx这种形式,也叫连接号。

var x='Gavin';
var str=`这是一个字符串模板,让我们增加一个变量进来${x}..可以看到它增加进来了`
document.write(str);

使用${x} 还可以在里面增加标签或者换行

对运算的支持:

let [a,b]=[2,8];
document.write(`${a+b}`);

强大的字符串模版,在实际开发中,我们可以让后台写一个活动页面,然后轻松的输出给用户。

字符串查找

ES6还增加了字符串的查找功能,而且支持中文哦,小伙伴是不是很兴奋。还是拿上边的文字作例子,进行操作。

查找是否存在:

先来看一下ES5的写法,其实这种方法并不实用,给我们的索引位置,我们自己还要确定位置。

var x='Gavin';
var str='这是一个字符串模板,让我们增加一个变量进来---Gavin..可以看到它增加进来了'
document.write(str.indexOf(x));

这种方式需要自己判断是否存在,如果不存在为0,需要自己判断

ES6直接用includes就可以判断,不再返回索引值,这样的结果我们更喜欢,更直接。

var x='Gavin';
var str='这是一个字符串模板,让我们增加一个变量进来---Gavin..可以看到它增加进来了'
document.write(str.includes(x));

这种方式可以直接返回true或false

 

判断开头是否存在:

let x='Gavin';
let str='Gavin这是一个字符串模板,让我们增加一个变量进来---Gavin..可以看到它增加进来了'
document.write(str.startsWith(x));

判断结尾是否存在:

let x='Gavin';
let str='Gavin这是一个字符串模板,让我们增加一个变量进来---Gavin..可以看到它增加进来了'
document.write(str.endsWith(x));

 

复制字符串

我们有时候是需要字符串重复的,比如分隔符和特殊符号,这时候复制字符串就派上用场了,语法很简单。

let a='Gavin <br/>|';
document.write(a.repeat(20));

 

字符串补白功能

在ES7中可以使用,需要增加babel-polyfill来解析

console.log('1'.padStart(5,'0'))  //长度为2,如果长度不够在前面补0   这样显示为01  这个在日期显示十分有用
console.log('1'.padStart(5,'0'))//向后补白
 

 

标签模板:

let    User1={
        'name':'gavin',
        'skill':'python'
    };

    console.log(kkk`i am ${User1.name}: ${User1.skill}`);
    function kkk(a,b,c) {
        console.log(a+b+c);
        return a+b+c
    }

 

raw方法:raw会在\n前面再加一个\

console.log(String.raw`Hi\n you`);
    console.log(`Hi\n you`);

 

六、数字操作

二进制和八进制

二进制和八进制数字的声明并不是ES6的特性,我们只是做一个常识性的回顾,因为很多新人小伙伴会把他们当成字符串或者不知道是什么,所以这算是赠送的知识点

二进制声明:

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

let binary=0B101010
console.log(binary);

八进制声明:

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

let octal=0O3424;
document.write(octal);

数字判断和转换

数字验证Number.isFinite( xx )

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

let a=1/4;
console.log(Number.isFinite(a));
console.log(Number.isFinite('Gavin'));
console.log(Number.isFinite(NaN));
console.log(Number.isFinite(undefined));

 

NaN验证

NaN是特殊的非数字,可以使用Number.isNaN()来进行验证。下边的代码控制台返回了true。

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

 

判断是否为整数Number.isInteger(xx)

let a=123;
console.log(Number.isInteger(a));

 

整数转换Number.parseInt(xxx)和浮点型转换Number.parseFloat(xxx)

let a = 19.8302;
console.log(Number.parseInt(a));
console.log(Number.parseFloat(a));

 

整数取值范围操作

整数的操作是有一个取值范围的,它的取值范围就是2的53次方。我们先用程序来看一下这个数字是什么.

let a=Math.pow(2,53)-1;
console.log(a);

 

在我们计算时会经常超出这个值,所以我们要进行判断,ES6提供了一个常数,叫做最大安全整数,以后就不需要我们计算了。

最大安全整数

console.log(Number.MAX_SAFE_INTEGER);

 

最小安全整数

console.log(Number.MIN_SAFE_INTEGER);

安全整数判断isSafeInteger( )

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

 

数字取整

无论小数部分是否大于5,都只取整数

{
    console.log(4.1, Math.trunc(4.1));
    console.log(4.1, Math.trunc(4.9));
}

sgin方法

{
    console.log(-5,Math.sign(-5));//负数返回-1
    console.log(0,Math.sign(0));//零返回0
    console.log(5,Math.sign(5));//正数返回+1
    console.log('50',Math.sign('50'));//数字型字符串返回字符串转换的数,所以返回1
    console.log('-50',Math.sign('-50'));//数字型字符串返回字符串转换的数,返回-1
    console.log('foo',Math.sign('foo'));//非数字型字符串返回NaN
}

 

{
    console.log(8,Math.cbrt(8));//求立方根
}

 

 

七、ES6新增的数组知识

JSON数组格式转换

JSON的数组格式就是为了前端快速的把JSON转换成数组的一种格式,我们先来看一下JSON的数组格式怎么写。

let json={
    '0': 'xiaopi',
    '1': '皮皮',
    '2': 'Gavin',
    length:3
};

 

这就是一个标准的JSON数组格式,跟普通的JSON对比是在最后多了一个length属性。只要是这种特殊的json格式都可以轻松使用ES6的语法转变成数组。在ES6中绝大部分的Array操作都存在于Array对象里。我们就用Array.from(xxx)来进行转换。我们把上边的JSON代码转换成数组,并打印在控制台。

console.log(Array.from(json));

 

Array.of()方法:

它负责把一堆文本或者变量转换成数组。在开发中我们经常拿到了一个类似数组的字符串,需要使用eval来进行转换,如果你一个老手程序员都知道eval的效率是很低的,它会拖慢我们的程序。这时候我们就可以使用Array.of方法。我们看下边的代码把一堆数字转换成数组并打印在控制台上:

let arr=Array.of(3,4,5,6);
console.log(arr);

当然它不仅可以转换数字,字符串也是可以转换的,看下边的代码:

let arr2=Array.of('gavin','xiaopi','kk');
console.log(arr2);

 

{
    let arr=Array.of();//定义一个空数组
    console.log('arr=',arr);
}

 

Array.from方法:

Array.from()可以把集合或者伪数组变为真正的数组

{
    let p=document.querySelectorAll('p');
    let pArr=Array.from(p);
    pArr.forEach((item)=>{
        console.log(item.textContent)
    })

}
View Code

在转换数组的同时也可以充当map的功能

console.log(Array.from([1,3,5,6],function (item) {
        return item*3;
    }))

 

find( )实例方法:

所谓的实例方法就是并不是以Array对象开始的,而是必须有一个已经存在的数组,然后使用的方法,这就是实例方法(不理解请看下边的代码,再和上边的代码进行比对,你会有所顿悟)。这里的find方法是从数组中查找。在find方法中我们需要传入一个匿名函数,函数需要传入三个参数:

  • value:表示当前查找的值。
  • index:表示当前查找的数组索引。
  • arr:表示当前数组。

在函数中如果找到符合条件的数组元素就进行return,并停止查找。你可以拷贝下边的代码进行测试,就会知道find作用。

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

如果找不到也不会报错,而是返回undefined

{
    console.log([1,2,3,4,5,6].find((item)=>{
        return item>4;
    }))
}
{
    console.log([1,2,3,4,5,6].findIndex((item)=>{
        return item>4;
}))
}

 

includes方法:

通过includes方法可以很容易找到数组中是否包含某个数值,就算是NaN也可以

{
    console.log([1,2,NaN].includes(1));
    console.log([1,2,NaN].includes(NaN));
}

 

 

 数组的实例方法: copyWithin()

arry.copyWithin(val,index1,index2)  其中第一个val是从哪个位置开始替换,第二个index1和第三个index2表示从哪个位置要替换前面的val,替换到index2个位置

{
    console.log(['aaa','bbbb','cccc',666,'jajfa','akdkak','ajdfa',1010].copyWithin(0,2,6))
}

 

fill( )实例方法:

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

let arr=[0,1,2,3,4,5,6,7];
arr.fill('gavin',2,5);//2表示从index未2开始,到5-1结束,表示吧从idnex2到4的元素全部替换为gavin
console.log(arr);

 

{
    console.log('fill-7',[1,'a',undefined].fill(7));//全部被7替换
    console.log('fill, pos',[1,3,4,6,2,1].fill(7,1,3));//从第一个位置开始到第三个位置被替换为7,也就是第一个第二个位置被替换为7
}

 

数组的遍历

for…of循环:

这种形式比ES5的for循环要简单而且高效。先来看一个最简单的for…of循环。

let arr=['gavin', 'xiaopi','kkblue'];
for (let item of arr){
    console.log(item);
}

 

for…of数组索引:有时候开发中是需要数组的索引的,那我们可以使用下面的代码输出数组索引。

let arr=['gavin', 'xiaopi','kkblue'];
for(let key of arr.keys()){
    console.log(key)
}

可以看到这时的控制台就输出了0,1,2,也就是数组的索引。

同时输出数组的内容和索引:我们用entries()这个实例方法,配合我们的for…of循环就可以同时输出内容和索引了。

let arr=['gavin', 'xiaopi','kkblue'];
for(let[index,val] of arr.entries()){
    console.log(`${index}:  ${val}`)
}

 

entries( )实例方法:

entries()实例方式生成的是Iterator形式的数组,那这种形式的好处就是可以让我们在需要时用next()手动跳转到下一个值。我们来看下面的代码:

let arr=['gavin', 'xiaopi','kkblue'];

let list=arr.entries();
console.log(list.next().value);
console.log('-'.repeat(20));
console.log(list.next().value);
console.log('#'.repeat(20));
console.log(list.next().value);
console.log('*'.repeat(20));

 

九、ES6中的箭头函数与扩展

默认值

在ES6中给我们增加了默认值的操作,我们修改上边的代码,可以看到现在只需要传递一个参数也是可以正常运行的。

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

 

主动抛出错误

在使用Vue的框架中,可以经常看到框架主动抛出一些错误,ES6中我们直接用throw new Error( xxxx ),就可以抛出错误。

function add(a,b=1) {
    if(a==0){
        throw new Error('this is a error');
    }else{
        return a+b;
    }
}
console.log(add(0));

 

函数中的严谨模式

我们在ES中就经常使用严谨模式来进行编程,但是必须写在代码最上边,相当于全局使用。在ES6中我们可以写在函数体中,相当于针对函数来使用。

function add(a,b=1) {
    'use strict'
    if(a==0){
        throw new Error('this is a error');
    }else{
        return a+b;
    }
}
console.log(add(1));

上边的代码如果运行的话,你会发现浏览器控制台报错,这是ES6中的一个坑,如果没人指导的话,可能你会陷进去一会。这个错误的原因就是如果你使用了默认值,再使用严谨模式的话,就会有冲突,所以我们要取消默认值的操作,这时候你在运行就正常了。

function add(a,b) {
    'use strict'
    if(a==0){
        throw new Error('this is a error');
    }else{
        return a+b;
    }
}
console.log(add(1));

 

获得需要传递的参数个数

如果你在使用别人的框架时,不知道别人的函数需要传递几个参数怎么办?ES6为我们提供了得到参数的方法(xxx.length).我们用上边的代码看一下需要传递的参数个数。

function add(a,b) {
    'use strict'
    if(a==0){
        throw new Error('this is a error');
    }else{
        return a+b;
    }
}
console.log(add.length);

这时控制台打印出了2,但是如果我们去掉严谨模式,并给第二个参数加上默认值的话,这时候add.length的值就变成了1, 也就是说它得到的是必须传入的参数。

 

箭头函数

在学习Vue的时候,我已经大量的使用了箭头函数,因为箭头函数真的很好用,我们来看一个最简单的箭头函数。也就是上边我们写的add函数,进行一个改变,写成箭头函数。

let add=(a,b=1)=> a+b;
console.log(add(1))

 

{}的使用

在箭头函数中,方法体内如果是两句话,那就需要在方法体外边加上{}括号。例如下边的代码就必须使用{}.

var add=(a,b=1) => {
    console.log('gavin');
    return a+b;
}

console.log(add(1));

箭头函数中不可加new,也就是说箭头函数不能当构造函数进行使用。

 

对象中存在方法的简介写法

 

{
    let es6_method={
        hello(){
            console.log('hello')
        }
    }
    es6_method.hello()
}

 

 

十、ES6中的函数与数组

对象的函数解构

我们在前后端分离时,后端经常返回来JSON格式的数据,前端的美好愿望是直接把这个JSON格式数据当作参数,传递到函数内部进行处理。ES6就为我们提供了这样的解构赋值。

let json={
    a: 'xiaopi',
    b: 'gavin',
    c: 'pipi'
};
var fun =({a,b,c="web"})=>{
    console.log(a,b,c);
};
fun(json);

 

数组的函数解构

函数能解构JSON,那解构我们的数组就更不在话下了,我们看下边的代码。我们声明一个数组,然后写一个方法,最后用…进行解构赋值。

let arr=['gavin','kkblue','xiaopi'];
var fun=(...arg)=>{
    console.log(arg[0],arg[1],arg[2])
}

fun(...arr);

 

in的用法

in是用来判断对象或者数组中是否存在某个值的。我们先来看一下用in如何判断对象里是否有某个值。(主要判断该位置是否为空)

对象判断

let obj={
    a:'gavin',
    b:'xiaopi'
};
console.log('c' in obj);

 

数组判断

先来看一下ES5判断的弊端,以前会使用length属性进行判断,为0表示没有数组元素。但是这并不准确,或者说真实开发中有弊端。

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

上边的代码输出了5,但是数组中其实全是空值,这就是一个坑啊。那用ES6的in就可以解决这个问题。

let arr=[,,,,,];
console.log(0 in arr);
let arr1=['gavin','xiaopi','kk'];
console.log(0 in arr1);

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

 

数组的遍历方法

1.forEach

let arr=['gavin','xiaopi','kk'];
arr.forEach((val,index)=>{console.log(index,val)});

注意:val在前面,index在后面,forEach循环的特点是会自动省略为空的数组元素,相当于直接给我们筛空了。

 

2.filter

let arr=['gavin','xiaopi','kk'];
arr.filter(x=>console.log(x));

 

3.some

let arr=['gavin','xiaopi','kk'];
arr.some(x=>console.log(x));

 

4.map

let arr=['gavin','xiaopi','kk'];
console.log(arr.map(x=>'web'));

 

数组转换字符串

在开发中我们经常会碰到把数组输出成字符串的形式,我们今天学两种方法,你要注意两种方法的区别。

join()方法

let arr=['gavin','xiaopi','kk'];
console.log(arr.join('  |  '));

 

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

toString()方法

let arr=['gavin','xiaopi','kk'];
console.log(arr.toString());

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

 

十一、ES6中对象

对象赋值

ES6允许把声明的变量直接赋值给对象,我们看下面的例子。

let name='gavin';
let skill='python';
var obj={name,skill};
console.log(obj);

 

对象Key值构建

有时候我们会在后台取出key值,而不是我们前台定义好的,这时候我们如何构建我们的key值那。比如我们在后台取了一个key值,然后可以用[ ] 的形式,进行对象的构建。

let key='skill';
var obj={
    [key]: 'web'
};
console.log(obj);

 

自定义对象方法

对象方法就是把兑现中的属性,用匿名函数的形式编程方法。这个在以前就有应用,我们这里只是简单的复习一下。

var obj={
    add:function(a,b){
        return a+b;
    }
}
console.log(obj.add(1,2)); 

 

Object.is(  ) 对象比较

对象的比较方法,以前进行对象值的比较,经常使用===来判断,ES6提供了新的方式进行比较:

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

 

区分=== 和 is方法的区别是什么,看下面的代码输出结果。

console.log(+0 === -0);  //true
console.log(NaN === NaN ); //false
console.log(Object.is(+0,-0)); //false
console.log(Object.is(NaN,NaN)); //true

这太诡异了,我要怎么记忆,那技术胖在这里告诉你一个小妙招,===为同值相等,is()为严格相等。

 

Object.assign(  )合并对象

操作数组时我们经常使用数组合并,那对象也有合并方法,那就是assgin(  )。看一下啊具体的用法。

let a={name: 'gavin'}
let b={skill: 'web'}
let c={alias: 'xiaopi'}
let d=Object.assign(a,b,c)
console.log(d);


console.log('拷贝',Object.assign({a:'a'},{b:'b'}));//浅拷贝
 

 

Object.entries()

{
    let test={
        a:456,
        b:789
    }
    for(let [i,v] of Object.entries(test)){
        console.log(`${i} : ${v}`)
    }

 

十二、Symbol在对象中的作用

首先来说,Symbol能提供独一无二的值,不重复 不相等,保证唯一。

声明Symbol

我们先来回顾一下我们的数据类型,在最后在看看Symbol如何声明,并进行一个数据类型的判断。

var a = new String;
var b = new Number;
var c = new Boolean;
var d = new Array;
var e = new Object; 
var f= Symbol();
console.log(typeof(d));
{
    let a1=Symbol();
    let a2=Symbol();
    console.log(a1===a2);
}

Symbol声明变量的第二种方法:

{
    let a3=Symbol.for('key3');//key3是一个key值,在用Symbol.for声明时会先检查这个key是否注册过
    //如果注册过,就返回这个值,如果没注册过会调用Symbol去生成这个独一无二的值
    let a4=Symbol.for('key3');
    console.log(a3===a4);
}
//在生成a4时会检查,如果发现它的key值以前调用过,会使用a3的值来为a4赋值

 

Symbol的打印

我们先声明一个Symbol,然后我们在控制台输出一下。

let g=Symbol('gavin')
console.log(g)
console.log(g.toString())

这时候我们仔细看控制台是有区别的,没有toString的是红字,toString的是黑字。

Symbol在对象中的应用

看一下如何用Symbol构建对象的Key,并调用和赋值。

let gavin=Symbol();
let obj={
    [gavin]: 'web'
};
console.log(obj[gavin]);
obj[gavin]= 'python';
console.log(obj[gavin]);

Symbol对象元素的保护作用

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

没有进行保护的写法:

let obj={name:'gavin', skill: 'web',gae: 22};
for(let item in obj){
    console.log(item)
};

现在我不想别人知道我的年龄,这时候我就可以使用Symbol来进行循环保护。

let obj={name:'gavin', skill: 'web'};
let age=Symbol();
obj[age] = 28;
for(let item in obj){
    console.log(item)
};
console.log(obj[age]);

 在这里再次强调,如果对象中用Symbol做key值,在for。。in和for 。。of中是拿不到对应的值的

{
    let a1=Symbol.for('abc');
    let obj={
        [a1]:'123',
        'abc':456,
        'c': 789
    };
    for(let [index,value] of Object.entries(obj)){
        console.log(`${index}: ${value}`)
    }//这种情况下,Symbol声明的value不会打印
}

如果想单纯的打印出Symbo作为key的value可以采用:

let a1=Symbol.for('abc');
    let obj={
        [a1]:'123',
        'abc':456,
        'c': 789 };

Object.getOwnPropertySymbols(obj).forEach((item)=>{ console.log(obj[item]); });

如果想全部显示出来,可以使用:

{
    let a1=Symbol.for('abc');
    let obj={
        [a1]:'123',
        'abc':456,
        'c': 789
    };
    Reflect.ownKeys(obj).forEach((item)=>{
        console.log('ownkeys',item,obj[item])
    })
}

 

 

十三、Set和WeakSet数据结构

Set的声明

let setAttr = new Set(['gavin','yaoming','xiao','kkblue']);
console.log(setAttr);

Set的两种定义类型

{
    let list=new Set();
    list.add(5);
    list.add(7);
    console.log('sie',list.size);
}
{//set的另外一种定义方式,在定义时传入数组
    let arr=[1,2,3,4,5];
    let list=new Set(arr);
    console.log('size',list.size);
}

 

Set和Array 的区别是Set不允许内部有重复的值,如果有只显示一个,相当于去重。虽然Set很像数组,但是他不是数组。

 

{
    let arr=[1,2,3,1,2];
    let list=new Set(arr);
    console.log(list);
}

但是注意,set在去重时,不会转换元素的类型,也就是2与'2'是不相等的,也就是不会去重

{
    let arr=[1,2,3,1,'2'];
    let list=new Set(arr);
    console.log(list);
}

 

Set值的增删查

追加add:

在使用Array的时候,可以用push进行追加值,那Set稍有不同,它用更语义化的add进行追加。

let setAttr = new Set(['gavin','yaoming','xiao','kkblue']);
setAttr.add('xiaoxiao')
console.log(setAttr);

 

删除delete:

setAttr.delete('gavin');
console.log(setAttr);
{
    let arr=['add','delete','clear','has'];
    let list=new Set(arr);
    console.log('has',list.has('add'));//如果有has就返回true
    console.log('delete',list.delete('delete'),list);//delete如果有返回true
}

 

查找has:

用has进行值的查找,返回的是true或者false。

console.log(setAttr.has('yaoming'));

 

{
    let arr=['add','delete','clear','has'];
    let list=new Set(arr);
    console.log('has',list.has('add'));//如果有has就返回true
    
}

 

删除clear:

setAttr.clear();
console.log('clear',list.clear(),list);

set的循环

for…of…循环:

let setAttr = new Set(['gavin','yaoming','xiao','kkblue']);
for(let item of setAttr){
    console.log(item)
}
setAttr.forEach((val)=>console.log(val));

 key与value都一样:

{
    let arr=['add','delete','clear','has'];
    let list=new Set(arr);
    for(let item of list.keys()){
        console.log('keys',item);
    }
}
for(let item of list.values()){
        console.log('value',item);
    }
for(let item of list.entries()){
        console.log('value',item);
    }

 

size属性

size属性可以获得Set值的数量。

let setAttr = new Set(['gavin','yaoming','xiao','kkblue']);
console.log(setAttr.size)

 

WeakSet的声明

let weakObj=new WeakSet();
let obj={
    a:'gavin',
    b: 'skill',
    c: 'xiaopi',
    d: 'gavin'
};
weakObj.add(obj);
console.log(weakObj);

这里需要注意的是,如果你直接在new 的时候就放入值,将报错。

WeakSet里边的值也是不允许重复的,我们来测试一下。

let weakObj=new WeakSet();
let obj={
    a:'gavin',
    b: 'skill',
    c: 'xiaopi',
    d: 'gavin'
};
weakObj.add(obj);
let obj1=obj;
weakObj.add(obj1);
console.log(weakObj);

 

十四、map数据结构

Json和map格式的对比

map的效率和灵活性更好

先来写一个JSON,这里我们用对象进行模拟操作。

let json={
    name: 'gavin',
    skill: 'web'
};
console.log(json);

 

{
    let map = new Map();
    let arr = ['123'];
    map.set(arr,456);
    console.log('map',map,map.get(arr));
}

第二种定义方式

{
    let map = new Map([['a',123],['b',456]]);
    console.log('map1',map)
}

 

但是这种反应的速度要低于数组和map结构。而且Map的灵活性要更好,你可以把它看成一种特殊的键值对,但你的key可以设置成数组,值也可以设置成字符串,让它不规律对应起来。

let json={
    name: 'gavin',
    skill: 'web'
};

console.log(json.name);

let map= new Map();
map.set(json,'kkblue');
console.log(map);

 

当然也可key字符串,value是对象。我们调换一下位置,依然是符合map的数据结构规范的。

map.set('xiaopi',json);

map的增删查

上边我们已经会为map增加值了,就是用我们的set方法,这里我就不重复讲解了。直接看如何取出我们的值。

取值get

现在取json对应的值。

console.log(map.get(json));

 

删除delete

删除delete的特定值:

map.delete(json);
{
    let map = new Map([['a',123],['b',456]]);
    console.log('map1',map);
    console.log('size',map.size);
    console.log('delete',map.delete('a'),map);
}

 

size属性

console.log(map.size);

查找是否存在has

console.log(map.has(json));

清除所有元素clear

map.clear()

 

 

附加章节-set  map 对象  数组数据结构对比 

1、map与数组对比 

{
    // 数据结构横向对比,增删改查
    let map = new Map();
    let array=[];
    //
    map.set('t',1);
    array.push({t:1});
    console.info('map-array',map,array);
    //
    let map_exist = map.has('t');
    let array_exist = array.find(item=>item.t);
    console.info('map-array',map_exist,array_exist);
    //
    map.set('t',2);
    array.forEach(item=>item.t?item.t=2:'');
    console.info('map-array',map,array);
    //删除
    map.delete('t');
    let index=array.findIndex(item=>item.t);
    array.splice(index,1);
    console.info('map-array-empty',map,array);
}

2、set与数组对比

{
    // set和array对比
    let item={t:1};
    let set=new Set();
    let array=[];
    //
    set.add(item);
    array.push({t:1});
    console.info('set-array:',set,array);
    //
    let set_exist=set.has(item);
    let array_exist=array.find(item=>item.t);
    console.info('set-array:',set_exist,array_exist);
    //改 对比set可以使用
    // item={t:2};
    // set.add(item)
    set.forEach(item=>item.t?item.t=2:'');
    array.forEach(item=>item.t?item.t=2:'');
    console.info('set-array-modify:',set,array);
    //
    set.forEach(item=>item.t?set.delete(item):'');
    let index=array.findIndex(item=>item.t);
    array.splice(index,1);
    console.info('set-array-delete:',set,array);
}

3、map set  object对比

{
    let item={t:1};
    let map = new Map();
    let set = new Set();
    let obj = {};
    //
    map.set('t',1);
    set.add(item);
    obj['t']=1;
    console.log('map-set-array',map,set,obj);
    //
    let map_exist = map.has('t');
    let set_exist = set.has(item);
    let obj_exist = 't' in obj;
    console.log('exist:',map_exist,set_exist,obj_exist);
    //
    map.set('t',2);
    item.t=2;
    obj['t']=2;
    console.log('map-set-array',map,set,obj);
    //
    map.delete('t');
    set.delete(item);
    delete obj['t'];
    console.log('map-set-array',map,set,obj);

}

总结:

数据结构要最优使用map,如果对数据要求比较高,需要唯一性,考虑set

 

十五、用proxy进行预处理

Proxy的应用可以使函数更加强大,业务逻辑更加清楚,而且在编写自己的框架或者通用组件时非常好用。Proxy涉及的内容非常多,那这里我就带你入门并且介绍给你后续的学习方法。

在学习新知识之前,先来回顾一下定义对象的方法。

var obj={
    add:function(val){
        return val+100;
    },
    name: 'I\'m OK!!!'
}
console.log(obj.add(100));
console.log(obj.name);

声明了一个obj对象,增加了一个对象方法add和一个对象属性name,然后在控制台进行了打印

声明Proxy

我们用new的方法对Proxy进行声明。可以看一下声明Proxy的基本形式。

new Proxy({},{});

需要注意的是这里是两个花括号,第一个花括号就相当于我们方法的主体,后边的花括号就是Proxy代理处理区域,相当于我们写钩子函数的地方。

现在把上边的obj对象改成我们的Proxy形式。

let pro=new Proxy({
    add:function (val) {
        return val+100;
    },
    name: 'I\'m OK!!!'
},{
    get:function (target,key,property) {
        console.log('begin GET!');
        console.log(`${target}:  ${key}`);
        return target[key];// target 表示的对象名,key表示变量名
    }
});

console.log(pro.name);

可以在控制台看到结果,先输出了come in Get。相当于在方法调用前的钩子函数。

get属性

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

  • target:得到的目标值
  • key:目标的key值,相当于对象的属性
  • property:这个不太常用,用法还在研究中,还请大神指教。

set属性

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

  • target:目标值。
  • key:目标的Key值。
  • value:要改变的值。
  • receiver:改变前的原始值。
let pro=new Proxy({
    add:function (val) {
        return val+100;
    },
    name: 'I\'m OK!!!'
},{
    get:function (target,key,property) {
        console.log('begin GET!');
        console.log(`${target}:  ${key}`);
        return target[key];// target 表示的对象名,key表示变量名
    },
    set:function (target,key,value,receiver) {
        console.log(`setting ${key}=${value}`);
        return target[key]= value;
    }
});

// console.log(pro.name);
pro.name='这是小皮';
console.log(pro.name);

apply的使用

apply的作用是调用内部的方法,它使用在方法体是一个匿名函数时。看下边的代码。

let target=()=>{
    return 'I\'m OK!!!'
}
var handler={
    apply(target,ctx,args){
        console.log('do apply');
        return Reflect.apply(...arguments);
    }
}

let pro=new Proxy(target,handler);
console.log(pro());

 

Proxy实例演示:

 

{
    let obj={
        time:'2018-01-10',
        name: 'net',
        _r:123

    };
    let monitor= new Proxy(obj,{
        //拦截对象属性的读取
        get(target,key){
            return target[key].replace('2018','2019')
        },
        //拦截对象设置属性
        set(target,key,value){
            //只允许修改name属性,其他属性都不允许修改
            return key==='name'?target[key]=value:target[key];
        },
        // 拦截对象key in object操作
        has(target,key){
            // 只暴露name属性,其他都不允许暴露
            return key==='name'?target[key]:false;
        },
        // 拦截delete
        deleteProperty(target,key){
            if(key.indexOf('_')>-1){
                delete target[key];
                return true;
            }else{
                return target[key];
            }
        },
        // 拦截Object.keys,Object.getOwnPropertySymbols,Object.getOwnPropertyNames
        ownKeys(target){
            return Object.keys(target).filter(item=>item!='time')
        }
    });
    //obj对用户不可见,用户需要操作monitor
    console.log('get操作:',monitor.time);
    monitor.time = '2020';
    console.log('set操作:',monitor.time);
    monitor.name = 'kkblue';
    console.log('set:',monitor.name);

    console.log('has', 'name' in monitor);
    console.log('has', 'time' in monitor);//只暴露name属性,其他属性都不允许暴露


    // delete monitor.time;
    // console.log('delete操作:',monitor);
    // delete monitor._r;
    // console.log('delete操作:',monitor);

    console.log('ownKeys:',Object.keys(monitor));
}

 Reflect与Proxy用法一样,所以Proxy的方法Reflect都可以使用:

{
    let obj={
        time:'2018-01-10',
        name: 'net',
        _r:123

    };



    console.log('Reflect get:',Reflect.get(obj,'time'));//读取obj里的time属性
    Reflect.set(obj, 'name','gavin');
    console.log(obj);

    console.log('has:',Reflect.has(obj,'name'));
}

举例说明如何使用这些特性:

{
    function validator(target,validator) {
        return new Proxy(target,{
            _validator:validator,
            set(target,key,value,proxy){
                if(target.hasOwnProperty(key)){
                    let va=this._validator[key];
                    if(!!va(value)){
                        return Reflect.set(target,key,value,proxy)
                    }else{
                        throw Error(`不能设置${key}到${value}`)
                    }
                }else{
                    throw Error(`${key}不存在`)
                }
            }
        })
    }

    const personValidators={
        name(val){
            return typeof val==='string'
        },
        age(val){
            return typeof val==='number'&& val >18;
        }
    }

    class Person{
      constructor(name,age){
          this.name = name;
          this.age = age;
          return validator(this,personValidators)
      }
    }
    const person = new Person('gavin',30);
    console.info(person);
    person.name = 48;
    

}

 

 

 

十六、promise对象的使用

ES6中的promise的出现给我们很好的解决了回调地狱的问题,在使用ES5的时候,在多层嵌套回调时,写完的代码层次过多,很难进行维护和二次开发,ES6认识到了这点问题,现在promise的使用,完美解决了这个问题。那我们如何理解promise这个单词在ES5中的作用那,你可以想象他是一种承诺,当它成功时执行一些代码,当它失败时执行一些代码。它更符合人类的行为思考习惯,而不在是晦涩难懂的冰冷语言。

promise的基本用法

promise执行多步操作非常好用,那我们就来模仿一个多步操作的过程,那就以吃饭为例吧。要想在家吃顿饭,是要经过三个步骤的。

  1. 洗菜做饭。
  2. 坐下来吃饭。
  3. 收拾桌子洗碗。

这个过程是有一定的顺序的,你必须保证上一步完成,才能顺利进行下一步。我们可以在脑海里先想想这样一个简单的过程在ES5写起来就要有多层的嵌套。那我们现在用promise来实现。

let state=1;
function step1(resolve,reject) {
    console.log('1.开始-洗菜做饭');
    if(state==1){
        resolve('洗菜做饭-完成');
    }else{
        reject('洗菜做饭-失败');
    }
}
function step2(resolve,reject) {
    console.log('2.开始-吃饭');
    if(state==1){
        resolve('吃饭-完成');
    }else{
        reject('吃饭-失败');
    }
}
function step3(resolve,reject) {
    console.log('3.开始-收拾桌子');
    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;
})

 

十七、class的使用

我们在ES5中经常使用方法或者对象去模拟类的使用,虽然可以实现功能,但是代码并不优雅,ES6为我们提供了类的使用。需要注意的是我们在写类的时候和ES5中的对象和构造函数要区分开来,不要学混了

类的声明

先声明一个最简单的coder类,类里只有一个name方法,方法中打印出传递的参数。

class coder{
    name(val){
        console.log(val);
    }
};

类的使用

我们已经声明了一个类,并在类里声明了name方法,现在要实例化类,并使用类中的方法。

let gavin= new coder;
console.log(gavin.name('xiaopi'));

类的多方法声明

class coder{
    name(val){
        console.log(val);
        return val;
    }
    skill(val){
        console.log(this.name('gavin')+':'+'Skill'+':'+val);
    }

};

let gavin= new coder;
console.log(gavin.skill('python'));

这里需要注意的是两个方法中间不要写逗号了,还有这里的this指类本身,还有要注意return 的用法。

类的传参

在类的参数传递中我们用constructor( )进行传参。传递参数后可以直接使用this.xxx进行调用。

class coder{
    name(val){
        console.log(val);
        return val;
    }
    skill(val){
        console.log(this.name('gavin')+':'+'Skill'+':'+val);
    }
    constructor(a,b){
        this.a = a;
        this.b = b;
    }
    add(){
        return parseInt(this.a)+parseInt(this.b);
    }

};

let gavin= new coder(1,4);
console.log(gavin.skill('python'));
console.log(gavin.add());

我们用constructor来约定了传递参数,然后用作了一个add方法,把参数相加。这和以前我们的传递方法有些不一样,所以需要小伙伴们多注意下。

class的继承

如果你学过java,一定知道类的一大特点就是继承。ES6中也就继承,在这里我们简单的看看继承的用法。

class Htmler extends Coder{

}



let htmlera = new Htmler;
console.log(htmlera.name('xiaopi'));

 声明一个htmler的新类并继承Coder类,htmler新类里边为空,这时候我们实例化新类,并调用里边的name方法。结果也是可以调用到的。

 

{
    // 继承传递参数
    class Parent{
        constructor(name='gavin'){
            this.name = name;
        }
    }
    
    class Child extends Parent{
        constructor(name,age){
            super(name);//如果super()表示继承Parent的所有参数
            this.age = age;
        }
    }
}

 

setter与getter属性操作

{
    // getter   setter操作
    class Parent{
        constructor(name='gavin'){
            this.name = name;
        }
        // get表示getter  set表示setter  这里的get 与set不是方法,只是属性
        get longName(){
            return `mk: ${this.name}`
        }
        set longName(value){
            this.name = value;
        }
    }
    const v = new Parent('gavin');
    console.log('getter', v.longName);
    v.longName= 'xiaopi';
    console.log('setter', v.longName);
}

静态方法与静态属性:

{
    //static静态方法
    class Parent {
        constructor(name = 'gavin') {
            this.name = name;
        }
      static tell(){
            console.log('tell');
      }
      Parent.type = 'static属性就是如此定义,不需要new一个实例化方式即可调用'
    }
    Parent.tell();//调用静态方法
    console.log('静态属性:', Parent.type);
}

 

十八、模块化操作

在ES5中我们要进行模块华操作需要引入第三方类库,随着前后端分离,前端的业务日渐复杂,ES6为我们增加了模块话操作。模块化操作主要包括两个方面。

  • export :负责进行模块化,也是模块的输出。
  • import : 负责把模块引,也是模块的引入操作。

export的用法:

export可以让我们把变量,函数,对象进行模块话,提供外部调用接口,让外部进行引用。先来看个最简单的例子,把一个变量模块化。我们新建一个temp.js文件,然后在文件中输出一个模块变量。

export var a = 'xiaopi';

然后可以在index.js中以import的形式引入。

import {a} from './temp.js';//其中temp.js后面的.js可以省略
 
console.log(a);

这就是一个最简单的模块的输出和引入。

如果想将一个模块中函数都引入,可以使用:

import * as lesson from './class/lesson18'; //*代表所有的东西  as 为别名

console.log(lesson.A);

 

多变量的输出

这里声明了3个变量,需要把这3个变量都进行模块化输出,这时候我们给他们包装成对象就可以了。

var a ='gavin';
var b ='xiaopi';
var c = 'web';
 
export {a,b,c}

函数的模块化输出

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

as的用法

有些时候我们并不想暴露模块里边的变量名称,而给模块起一个更语义话的名称,这时候我们就可以使用as来操作。

var a ='xiaopi';
var b =‘gavin';
var c = 'web';
 
export {
    x as a,
    y as b,
    z as c
}

export default的使用

加上default相当是一个默认的入口。在一个文件里export default只能有一个。我们来对比一下export和export   default的区别

1.export

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

对应的导入方式

import {a,add} form './temp';//也可以分开写

2.export defalut

export default var a='gavin';

对应的引入方式

import str from './temp';

 最常用的方式:

lesson18.js文件 进行export default:

export let A=123;
export function test() {
    console.log('test')
}

export class Hello{
    test(){
        console.log('class');
    }
}


export default{
    A,
    test,
    Hello
}

index.js导入

import Lesson18 from './class/lesson18';
console.log(lesson18.A);

 

十九、Iterator和for of循环

Iterator的使用

{
    let arr=['hello','world'];
    let map=arr[Symbol.iterator]();
    // map中有一个实例方法next,通过调用next()来完成实例的数据调用
    console.log(map.next());
    console.log(map.next());
    console.log(map.next());
}

自定义Iterator接口

let obj={
        start:[1,3,2],
        end:[7,9,9],
        [Symbol.iterator](){
            let self=this;
            let index=0;
            let arr=self.start.concat(self.end);
            let len=arr.length;
            return {
                next(){
                    if(index<len){
                        return{
                            value:arr[index++],
                            done:false
                        }
                    }else{
                        return{
                            value:arr[index++],
                            done:true
                        }
                    }
                }
            }

        }



    }

for(let key of obj) {
    console.log(key);
}

 

总结:

无论如何调用Iterator接口,都必须首先定义:

[Symbol.iterator](){

  return {

    next(){

      return{
        value:
        done:
      }     } } }

 

二十、Generator

就是异步编程的一种解决方案

// 基本用法
    let tell = function* () {
        yield 'a';
        yield 'b';
        return 'c'
    };

    let k = tell();

    console.log(k.next());
    console.log(k.next());
    console.log(k.next());

Generator实现对象的for of输出

{
 let obj={};
 obj[Symbol.iterator]=function* () {
     yield 1;
     yield 2;
     yield 3;
 }
 for(let key of obj){
     console.log(key);
 }
}

实例一:抽奖

{
    // 具体实例:抽奖的剩余次数
    let draw = function (count) {
        // 具体抽奖逻辑
        console.info(`剩余${count}次`);
    }

    let residue=function* (count) {
        while(count>0){
            count--;
            yield draw(count);
        }
    }

    let start=residue(5);
    let btn=document.createElement('button');
    btn.id='start';
    btn.textContent='抽奖';
    document.body.appendChild(btn);
    document.getElementById('start').addEventListener('click',function () {
        start.next();

    },false)
}

 

二十一、Decorator装饰器

装饰器就是用来修改类的行为的函数

首先需要安装  

cnpm i babel-plugin-transform-decorators-legacy --save-dev

其次修改babelrc文件

{
  "presets": ['es2015'],
  "plugins": ["transform-decorators-legacy"]
}

装饰器的两种用法:

{
    // 用法一
    let readonly=function (target,name,descriptor) {
        descriptor.writable=false;
        return descriptor
    };

    class Test{
        @readonly
        time(){
            return '218-01-11'
        }
    }

    let test=new Test();
    console.log(test.time());
    test.time=function () {
        console.log('rest time!');
    }
    console.log(test.time());
}

{
    // 用法二
    let typename=function (target,name,descriptor) {
        target.myname='hello'//添加一个类的静态属性
    }

    @typename
    class Test{

    }

    console.log(Test.myname);
}

 

第三方修饰器js库:core-decorators: cnpm install core-decorators  

 

转载于:https://www.cnblogs.com/xiaopi-python/p/8157229.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值