重开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的三种声明方式:
- 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)
}) }
在转换数组的同时也可以充当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,但是数组中其实全是空值,这就是一个坑啊。那用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
重开ES6的更多相关文章
- ES6模块import细节
写在前面,目前浏览器对ES6的import支持还不是很好,需要用bable转译. ES6引入外部模块分两种情况: 1.导入外部的变量或函数等: import {firstName, lastName, ...
- webpack+react+redux+es6开发模式
一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...
- ES6的一些常用特性
由于公司的前端业务全部基于ES6开发,于是给自己开个小灶补补ES6的一些常用特性.原来打算花两天学习ES6的,结果花了3天才勉强过了一遍阮老师的ES6标准入门(水好深,ES6没学好ES7又来了...) ...
- ES6(块级作用域)
我们都知道在javascript里是没有块级作用域的,而ES6添加了块级作用域,块级作用域能带来什么好处呢?为什么会添加这个功能呢?那就得了解ES5没有块级作用域时出现了哪些问题. ES5在没有块级作 ...
- es6小白学习笔记(一)
1.let和const命令 1.es6新增了let和const命令,与var用法类似,但它声明的变量只在let所在的代码块内有效(块级作用域,es5只有全局和函数作用域) { let a = 1; v ...
- ES6之变量常量字符串数值
ECMAScript 6 是 JavaScript 语言的最新一代标准,当前标准已于 2015 年 6 月正式发布,故又称 ECMAScript 2015. ES6对数据类型进行了一些扩展 在js中使 ...
- ES6之let命令详解
let与块级作用域 { var foo='foo'; let bar='bar'; } console.log(foo,'var'); //foo varconsole.log(bar ,'bar') ...
- ES6 箭头函数中的 this?你可能想多了(翻译)
箭头函数=>无疑是ES6中最受关注的一个新特性了,通过它可以简写 function 函数表达式,你也可以在各种提及箭头函数的地方看到这样的观点——“=> 就是一个新的 function”. ...
- ES6+ 现在就用系列(二):let 命令
系列目录 ES6+ 现在就用系列(一):为什么使用ES6+ ES6+ 现在就用系列(二):let 命令 ES6+ 现在就用系列(三):const 命令 ES6+ 现在就用系列(四):箭头函数 => ...
随机推荐
- Generative Adversarial Nets
1. 基本思想 两个模型: 判别器:预测从生成器生成的样本的概率 生成器:生成样本时,最大化使得判别器发生错误的概率 最后得到唯一解:使得生成器生成的样本输入到判别器中,得到的概率全是1/2. ...
- Linux 系统查看对应公网映射地址
最近在解决网络问题时,需要查看本机的出口公网IP信息,所以在网络上搜索和请求运维达人,获得如下两个方法: curl ifconfig.me 在linux系统中输入上述的命令,可以查看到本机连接的公网信 ...
- makefile中的patsubst函数有何作用?
答:这是个模式替换函数,格式为: $(patsubst <pattern>,<replacement>,<text>) 查找text中的单词,如果匹配pattern ...
- 线程(六)之LOCK和synchronized
在java.util.concurrent.locks包中有很多Lock的实现类,常用的有ReentrantLock.ReadWriteLock(实现类ReentrantReadWriteLock), ...
- http随笔
1.什么是http? HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从WWW服务器传输超文本到本地浏览器的传送协议.它可以使浏览器更加高效,使网 ...
- SQLLITE HELPER
using System;using System.Data.SQLite; namespace SQLiteSamples{ class Program { //数据库连接 ...
- Rails6.0 Beta版本1: Action Text的简单使用
主要功能是新增2个主要的框架Mailbox和action Text. 和2个重要的可扩展的升级: multiple databases support和parallel testing. Action ...
- vs环境open读写创建
vs环境openfd = open(save_as_file, O_RDWR|O_CREAT);//创建文件属性为只读fd = open(save_as_file, O_RDWR|O_CREAT, S ...
- js中提示框闪退问题
当页面存在刷新 或 在线引用iframe框架时(引用框架也会导致刷新) 会导致页面加载时的弹出框闪退 解决方法:设置弹出框在页面或者框架完全加载一段时间后再弹出 <script type=& ...
- 『PyTorch』第五弹_深入理解Tensor对象_中下:数学计算以及numpy比较_&_广播原理简介
一.简单数学操作 1.逐元素操作 t.clamp(a,min=2,max=4)近似于tf.clip_by_value(A, min, max),修剪值域. a = t.arange(0,6).view ...