重开ES6

it2025-02-01  7

一、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的三种声明方式:

var:它是variable的简写,可以理解成变量的意思。let:它在英文中是“让”的意思,也可以理解为一种声明的意思。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执行多步操作非常好用,那我们就来模仿一个多步操作的过程,那就以吃饭为例吧。要想在家吃顿饭,是要经过三个步骤的。

洗菜做饭。坐下来吃饭。收拾桌子洗碗。

这个过程是有一定的顺序的,你必须保证上一步完成,才能顺利进行下一步。我们可以在脑海里先想想这样一个简单的过程在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)