?目录
1.ES6. 3
1.1ECMAScript发展历史: 3
1.2ES6简介... 3
2.关键字... 3
2.1 let关键字... 3
2.2 let与var比较... 4
2.2const关键字... 5
3.字符串拓展... 7
3.1多行字符串... 7
3.1.1单行字符串: 7
3.1.2多行字符串... 7
3.2原始字符串(String.raw)... 8
3.3重复字符串(repeat)... 9
3.4判断字符串位置... 9
4.数字拓展... 10
4.1 isNaN.. 10
4.2 isFinite. 11
4.3 isInteger. 12
5.数学对象拓展... 12
6.对象拓展... 12
6.1字面量(let obj = {}) 12
6.2 is【Object.is(? ,? )】... 13
6.3 assign(用于复制对象) 14
7.数组拓展... 15
7.1 from方法:【Array.from(arrLike, fn)】... 15
7.2 of方法:【Array.of()】... 16
7.3查找数组(find、findIndex) 16
7.4数组内部复制(arr.copyWithin(pos, start, end))... 17
7.5迭代器... 18
7.5.1迭代器方法... 18
7.5.2for of循环... 19
8. 解构... 21
8.1结构含义:(解析聚合数据的结构)... 21
8.2对象解构(let { key1, key2, ..keys} = obj)... 21
8.3数组解构(let [item1, item2, ..tems] = arr)... 23
8.4解构总结... 24
9.函数拓展... 24
9.1默认参数... 24
9.2获取剩余参数... 25
9.3箭头函数(let demo=(? )=>{? })... 26
ES1.0 => 1997???? ES2.0 => 1998
ES3.0 => 1999???? S4.0 => 2007
ES3.1 => 2008???? S5 => 2009
ES6 => 2015???????? ES2016(ES7) => 2016
ES2017 => 2017? ES2018 => 2018
由于ES每年新增的特性非常之多,所以开始以年为单位,定义其版本,从ES6开始,吸取了ES4失败的教训,没有强制浏览器实现这些语法,而是将这些语法编译成ES5 (ES3.1) 版本,这样浏览器就支持了。
所以,ES6受到各大浏览器厂商广泛的认可,并开始实现其语法,因此好的浏览器能够支持90%以上的语法了,所以很多语法可以直接用浏览器测试。
ES6 着眼于未来,是为企业级大型项目的开发而设计的。由于还有很多浏览
器. (IE6,7,8)没有实现ES6语法,所以我们要编译ES6,ES6支持面向对象编程方式(class, extends等关键字),但是又保留了弱类型语言,动态语言的特征。
ECMA组织为了让制定的规范被编译成可被浏览器支持的版本,提供了babel编译库,ES每次发布版本,babel都会更新一个版本,在新版本中提供的功能,通过babel拓展来实现编译。
在nodejs端,在6.0版本之后,开始支持ES6,所以我们可以在后面的node学习中直接使用ES6了。
在浏览器端,为了兼容更多的浏览器。我们需要将ES6的代码,编译成浏览器支持的版本。
注:当前的语法浏览器支持,因此可以用浏览器直接测试。
用来定义块作用域变量的
var定义函数级作用域变量的:
在函数内部定义的变量,外部无法访问,
在代码块(if, for等)中定义的变量,外部可以访问
let定义块作用域变量的:
在函数内部定义的变量,外部无法访问
在代码块(if, for等)中定义的变量,外部仍然无法访问
用来定义块作用域变量的???????
1.作用域
var函数级作用域?????????????????? let块级作用域
?//?块级作用域
????????if?(true)?{var?c?=?30;let?d?=?40;
????????????//?d?只能在代码块的内部访问
????????????console.log(d); ?}//40
????????console.log(c);//30
????????//?console.log(d);//let的外部无法访问
????????//因此,var是函数级的,let?是块级的
2.重复定义
var可以重复定义变量?????????? let不可以重复定义变量
??????//重复定义
????????var?color?=?'red';var?color?=?'green';
????????console.log(color);//green;
????????let?color2?=?'red';let?color2?=?'green';
????????console.log(color2);//报错//?has?already?been?declared
3.声明前置
var支持声明前置?????????????????? let不支持声明前置
//声明前置
????????console.log(ccc);//undefined//阔以访问,虽然无值
????????var?ccc?=?'RED';
????????let?ccc?=?'red';//报错//Cannot?access?'ccc'?before?initialization
4.for循环中存储数据
var不能存储数据?????????????????? let可以存储数据
?//利用闭包存储数据??
for?(var?i?=?0;?i?<?5;?i++)?{
????????????arr[i]?=?(function?(i)?{
????????????????return?function?()?{
????????????????????console.log(i);} })(i) }//立即执行
????????arr[3]()//3?//?arr[2]();//2
//利用let存储数据
????????for?(let?i?=?0;?i?<?5;?i++)?{?
????????????arr[i]?=?function?()?{
????????????????console.log(i);}}
arr[3]()//3
5.被window挂载
var可以被挂载?????????????????????? let不能被挂载
???//?被window挂载
????????var?e?=?10;let?f?=?20;
????????console.log(window.e);//10
????????console.log(window.f);//undefined
const关键字是用于定义常量(一旦定义无法改变的变量,通常是表示一些固定不变的数据)
使用const关键字的特点:
1无法被修改
2支持块作用域
3无法重复定义
4无法声明前置
5不能被window挂载
6不能作为for循环体中的变量使用
7值只能是值类型,如果是引用类型则可以被修改
工作中,通常是将用大写字母表示,并且横线分割单词,常用于定义配置量
在ES5中,我们可以通过冻结对象技术,或者设置writable:false特性,来模拟静态变量。但问题是:值如果是引用类型依然会被修改
在ES3.1中,我们可以通过单例模式来模拟静态变量。在方法中只定义取值方法,而不定义赋值方法即可
??//1.定义常量,不能修改
????????//?var?a?=?10;
????????//?a?=?20;
????????//?console.log(a);//20//阔以被修改
????????const?a?=?10;a?=?20;
????????console.log(a);//报错//Assignment?to?constant?variable.
????????//2.声明前置,不能前置,只能在后面访问
????????console.log(COLOR);const?COLOR?=?'red';
????????//报错//Cannot?access?'COLOR'?before?initialization
????????//3.不能重复定义
????????const?COLOR?=?'red';
????????const?COLOR?=?'asdas';//报错//'COLOR'?has?already?been?declared
????????//4.?块级作用域
????????function?demo()?{
????????????const?COLOR?=?'red';//支持函数级作用域
????????????//?var?COLOR?=?'red'
????????????//?let?COLOR?=?'red'
????????????console.log(111,?COLOR) };//111?"red"//外部都无法访问
????????demo();
????????//块级
????????if?(true)?{const?COLOR?=?'red';//支持块级作用域
????????????console.log(222,?COLOR);?}//222?"red"//外部无法访问
????????console.log(COLOR);?//外部都无法访问
????????//5.不能挂载在window
????????const?COLOR?=?'red';console.log(window.COLOR);//undefined
????????//6.不能作为循环变量(常量不能被改变)
????????for?(const?i?=?0;?i?<?5;?i++)?{
????????????console.log(i);
????????//第一次执行时,未被修改可以执行,第二次循环到i++时,修改了变量,报错
????????}
????????//7.值只能是值类型,不能是引用类型
????????const?OBJ?=?{width:?10,height:?20};
????????OBJ.width?=?111;OBJ.height?=?2222;
????????console.log(OBJ);//{width:?111,?height:?2222}
????????//会被修改,所以,不能使用引用类型
????????//8.ES5模拟
????????var?obj?=?{color:?'red',num:?98,
????????????size:?{//8.2
????????????????width:?100,height:?200}}
????????//8.1:设置特性
????????Object.defineProperties(obj,?{
????????????color:?{writable:?false},num:?{writable:?false},
????????????size:?{writable:?false},})
????????obj.color?=?'sdsd';obj.num?=?678;
????????obj.size?=?[1,?2,?3]//8.3没有修改size:{width:?123,?height:?200}
????????obj.size.width?=?123;?//8.2被修改了size:{width:?123,?height:?200}
????????//8.4即,size属性不能被修改,但是size的子属性可以被修改
????????console.log(obj);//8.1没有被修改{color:?"red",?num:?98}
????????//9.1:通过ES5中,对象的冻结实现
????????Object.freeze(obj);
????????obj.color?=?'sdsd';obj.num?=?678; //red //98
????????obj.size?=?[1,?2,?3];//没有修改size
????????obj.size.width?=?123;//可以修改:{width:?123,?height:?200}
??????console.log(obj);//color:?"red"?num:?98?{width:?123,?height:?200}
????????//同8.4:即,size属性不能被修改,但是size的子属性可以被修改
//10.1在ES3.1中,使用单例模式
????????var?conf?=?(function?()?{
????????????var?_data?=?{
????????????????color:?'red',num:?98,
????????????????size:?{width:?100,height:?200}}
????????????//只返回取值器,不返回复制器
????????????return?function?(key)?{return?_data[key];}
????????console.log(conf('color'));//red
????????console.log(conf('num'));//98
????????//如果返回的是对象可以被修改
????????conf('size').width?=?333333;
????????console.log(conf('size'));//{width:?333333,?height:?200}
3.字符串拓展
由一组单引号或者双引号定义的字符串
单行字符串的问题:
1单行字符串不能换行
2 一些特殊的按键要使用转义字符\n
3一些特殊的字符要使用转义字符\x20
4字符串标志符号不能直接嵌套
5单引号中不能直接写单引号,要转义\'
6双引号中不能直接写双引号,要转义\”
....
ES6为了解决单行字符串中的问题,提供了多行字符串,
通过 ` 定义,在多行字符串中,只有`需要转义\,其他的字符,都可以直接书写
????????var?str?=?`hello
????????qaq???"?"?'?'??\`
????????`
????????console.log(str);
并且ES6多行字符串支持插值语法:
?${key}
${}提供了js环境,因此我们可以写js表达式
ES6的插值语法,让其它框架的插值语法的重要性,大打折扣。
????//数据
????????let?size?=?{width:?10,height:?20};
????????//?输出:面积:10x20=200
????????var?str?=?'面积:'?+?size.width?+?'x'?+?size.height?+?'='?+?size.height?*?size.width
????????//2.多行字符串
????????var?str?=?`面积:${size.width}x${size.height}=${size.width?*?size.height}`
????????console.log(str);//面积:10x20=200
例二:
???????//数据
????????let?data?=?[
{title:?'1.被枚举到(for...in?或?Object.keys?方法),',type:?'推荐'},
{title:?'2.可以改变这些属性的值,也可以删除这些属性。',type:?'关注'},
{title:?'3.这个方法允许修改默认的额外选项(或配置)。',type:?'热议'},
{title:?'4.默认情况下,使用?Object.defineProperty()',type:?'热点'},]
????????//定义字符串
????????let?html?=?'';
????????for?(let?i?=?0;?i?<?data.length;?i++)?{?//遍历数据
????????????//字符串拼接
????????????html?+=?`
????????????<li>
????????????????<span>${data[i].title}</span>
????????????????<span>${data[i].type}</span>
????????????</li>
????????????`}
??????????app.innerHTML?=?html;//?console.log(html);
3.2原始字符串(String.raw)
在使用了转义字符之后,并且在浏览器查看的时候,我们只能看到结果,不能看到原始完整的字符串(包含转义字符),于是ES6中拓展了String.raw方法。
用于,查看完整的原始字符串。
使用方式:
String.raw``
1.参数通过多行字符串的形式传递
2.字符串中的转义字符串不会被转义
//转义字符
????????let?str?=?`hello?\nqa\nq`;//被转义了,即换行了
????????//原始字符串
????????//?let?str?=?String.raw`hello?\nqa\nq`//hello?\nqa\nq
????????console.log(str);
????????//实现://不让\n实现,把\n改成\\n即可
????????//注意\\n是一个整体,匹配修改时,要一起匹配
????????console.log(str.replace(/\n/g,?'\\n'));//hello?\nqa\nq
3.3重复字符串(repeat)
ES6中拓展了repeat方法用于重复输出字符串
参数:要重复的次数
返回值:重复的结果
注意:不影响原始字符串
????????let?str?=?`hello?||`;?//?重复字符串(repeat)
????????//让str重复三次
????????console.log(str.repeat(3));//hello?||hello?||hello?||
????????console.log(str.repeat(0));//
????????console.log(str);//hello?||
????????//实现:
????????String.prototype.qaqRepeat?=?function?(num)?{
????????????var?result?=?''; //this?代表字符串//定义结果字符串
????????????//循环拼接
????????????for?(var?i?=?0;?i?<?num;?i++)?{result?+=?this;}
????????????return?result}
????????console.log(str.qaqRepeat(3));//hello?||hello?||hello?||
3.4判断字符串位置
startsWith(str, pos)
是否以参数字符串开头
截取后面的部分,并且包含截取位置字符
str:参数字符串 (子字符串)???????????? pos:字符串截取位置
返回值:布尔值
??//定义字符串
????????//????????0?1?2?3?4?5?6
????????let?str?=?`我是一个大帅逼`
?console.log(str.startsWith('我',?0));//true
????????console.log(str.startsWith('帅逼',?5));//true
endsWith(str, pos)
是否以参数字符串结尾
截取前面的部分,并且不包含截取位置字符
?console.log(str.endsWith('帅逼'));//true
????????console.log(str.endsWith('帅',?5));//false
????????console.log(str.endsWith('帅',?6));//true
includes(str, pos)
是否包含参数字符串
截取后面的部分,并且包含截取位置字符
????console.log(333,?str.includes('帅'));//true
????????console.log(333,?str.includes('帅逼',?5));//true
ES6中为数字拓展了几个方法:
?isNaN(数字?)、 isFinite(有限?)、 isInteger(整数?)
????? ??var?num1?=?0?/?1;//??????0
????????var?num2?=?0?/?-?1;//???-0
????????var?num3?=?1?/?0;//?????Infinity
????????var?num4?=?-?1?/?0;//???-Infinity
????????var?num5?=?0?/?0;//?????NaN
1.全局中的NaN
全局中有一个isNaN方法,是用于判断是否是NaN(not a Number)
全局中isNaN在判断的时候,会进行类型转换
???????console.log(isNaN(num4));???????//F
????????console.log(isNaN(num5));???????//T
????????console.log(isNaN(100.00));?????//F
????????console.log(isNaN('100abc'));???//T
????????console.log("+'100abc'",?isNaN(+'100abc'));??//F//T//存疑
????????//用typeof查看+'100abc?时,貌似会会在后台进行数字的?转换
????????console.log(isNaN(parseInt('100abc')));??//F
//?isNaN('123ABC');
//?👆true:??parseInt("123ABC")的结果是?123,?但是Number("123ABC")结果是?NaN
????????console.log(isNaN(Math.floor('100abc')));?//F//T
????????//Math方法不支持隐性转换,100abc仍是字符串?不是一个数字
????????console.log(isNaN(1?/?3));?//F
????????console.log(isNaN(Math.PI));?//F
2.Number拓展的isNaN
在判断的时候不会做类型转换
1.首先必须是数字
其次才去判断是否是NaN
2.如果是NaN,则返回true
如果不是NaN,则返回false
??????? console.log(Number.isNaN(num4));???????????????????//F
????????console.log(Number.isNaN(num5));???????????????????//T
????????console.log(Number.isNaN(100.00));?????????????????//F
????????console.log(Number.isNaN('100abc'));//T//先直接判断类型:字符串//F
console.log(Number.isNaN(+'100abc'));//T//是数字类型,但不是一个数字//是NaN
????????console.log(Number.isNaN(parseInt('100abc')));?????//F
????????console.log(Number.isNaN(Math.floor('100abc')));???//T
????????console.log(Number.isNaN(1?/?3));??????????????????//F
????????console.log(Number.isNaN(Math.PI));????????????????//F
全局中:
有一个isFinite方法, 是用于判断是否是有限的
全局中的isFinite,在判断的时候,会进行类型转换
而Number拓展的isFinite:
在判断的时候不会做类型转换
1.首先必须是数字
其次才去判断是否是有限的
2.如果是有限的,则返回true
如果不是有限的,则返回false
注意:
?????? 1. 判断数学上是不是有限的
?????? 2. 只要是整数都是有限的
?console.log(Number.isFinite(num4));???????????????????//?T?//F
????????console.log(Number.isFinite(num5));???????????????????//?F
????????console.log(Number.isFinite(100.00));?????????????????//?F?//T
????????console.log(Number.isFinite('100.00'));???????????????//?F
????????console.log(Number.isFinite('100abc'));???????????????//?F
????????console.log(Number.isFinite(+'100abc'));??????????????//?F
????????console.log(Number.isFinite(parseInt('100abc')));?????//?F?//T
????????console.log(Number.isFinite(Math.floor('100abc')));???//?F
????????console.log(Number.isFinite(1?/?3));??????????????????//?F?//T
????????console.log(Number.isFinite(Math.PI));????????????????//?F?//T
Number拓展的isInteger方法,用于判断是否是整型的
在判断的过程中,会校验类型
1.首先必须是数字
其次才去判断是否是整型的
2.如果是整型,则返回true
如果不是整型,则返回false
5.数学对象拓展
就是对Math对象的拓展
ES6为了适应大型项目,解决自身运算的问题,拓展了大量的方法。
Math.cbrt:计算一个数的立方根。
Math.fround:返回一个数的单精度浮点数形式。
Math.hypot:返回所有参数的平方和的平方根。
Math.expm1(x):返回ex- 1。
Math.log1p(x):返回1 + x的自然对数。如果x小于-1,返回NaN。
Math.log10(x):返回以10为底的x的对数。如果x小于0,则返回NaN。
Math.log2(x):返回以2为底的x的对数。如果x小于0,则返回NaN。
三角函数方法:
Math.sinh(x)返回x的双曲正弦(hyperbolic sine)
Math.cosh(x)返回x的双曲余弦(hyperbolic cosine)
Math.tanh(x)返回x的双曲正切(hyperbolic tangent)
Math.asinh(x)返回x的反双曲正弦(inverse hyperbolic sine)
Math.acosh(x)返回x的反双曲余弦(inverse hyperbolic cosine)
Math.atanh(x)返回x的反双曲正切(inverse hyperbolic tangent)
Math.sign返回一个数字的标志,用来判断数字范围的
(0, Infinity] =>1,[-Infinity, 0) => -1,0=>0,-0 => -0,NaN =>NaN
6.1字面量(let obj = {})
对象字面量: letobj = {}
省略语法:
1如果定义的属性名称与属性值变量同名,我们可以省略属性名称以及冒号
2可以对属性名称书写表达式,通过[]来动态的设置属性名称,之前可以通过[]来获取属性,现在我们可以通过[]来设置属性名
3在对象中定义的方法可以省略冒号以及function关键字
???????? let?color?=?"red";
????????let?obj?=?{//定义对象
????????????//?color:?color//1.1添加一个color属性
????????????//1.2如果定义的属性名称与属性值变量同名,可以省略属性名称以及冒号
????????????color,
????????????//1.4对象字面量中,可以通过[]来动态的设置属性名称
????????????[color]:?200,
????????????//1.5?[?]提供了js环境,可以书写复杂的表达式
????????????[color.toLocaleUpperCase()?+?'hello']:?200,
????????????//1.6获取方法
????????????//?getColor:?function?()?{??//老式写法
????????????//?????return?this.color; }
??????????//ES6中,属性方法可以省略冒号以及function关键字
????????????getColor()?{return?this.color;}};
????????//设置属性
????????//?obj[color]?=?100;//1.3{color:?"red",?red:?100}
????????console.log(obj);
????????//1.1&1.2{color:?"red"}
????????//1.4{color:?"red",?red:?200}
????????//1.5{color:?"red",?red:?200,?REDhello:?200}
????????//1.6{color:?"red",?red:?200,?REDhello:?200,?getColor:??}
????????console.log(obj.getColor());//1.6//red
6.2?is【Object.is( ?, ?)】
is方法用于判断两个参数是否全等(===)
全等判断有几个问题:
1:0和 -0之前在进行全等判断的时候,得到的是true
0和- 0之间是差了一个符号位,在二进制中,存储的数据是不同的
2:NaN和NaN在进行全等判断的时候,得到的是false
3:所有NaN都表示“不是一个数字”,它们存储的地址是一样
对象拓展的is方法:
在判断0和-0的时候得到的false
在判断NaN的时候得到的就是true
注意:
?????? 比较的是存储的地址。
????? ? ?console.log(0?/?1?===?0?/?-1);??????? ?//true
????????console.log(NaN?===?+'asd');???????????//false
????????//is方法纠正上述?===?的错误//除此之外,is方法与?===?是一致的
????????console.log(Object.is(0?/?1,?0?/?-1));?//false
????????console.log(Object.is(NaN,?+'asd'));???//true
ES6拓展的assign是用于复制对象的,和jQuery、undescore中的extend方法类似
使用方式: Object.assign(obj, obj1, obj2)
obj:被复制的目标对象
从第二个参数开始,都是复制的对象
返回值:目标对象obj
注意:
1.后面对象中的同名属性会覆盖前面对象中的属性
2.assign方法实现的是一个浅复制
浅复制:
值类型是直接复制,而引用类型是改变指向,没有真正的复制
深复制:
值类型是直接复制,引用类型也是直接复制,并不是改变指向(函数除外)
3.简单实现深复制: JSON.parse(JSON.stringify), 但是转换json字符串的时候,会过滤掉函数
4.jQuery中的extend方法,第一个参数传递 true的时候就是深复制
?//实现(浅复制)(这是静态方法,直接放在Object上面)
????????Object.qaqAssign?=?function?(target)?{
????????????//遍历后面的参数对象
????????????for?(var?i?=?1;?i?<?arguments.length;?i++)?{
????????????????//获取当前参数对象
????????????????var?obj?=?arguments[i];
????????????????//将obj中的属性赋值给target
????????????????for?(var?key?in?obj)?{
????????????????????target[key]?=?obj[key]; ? //赋值
}
}
????????????//返回目标对象
????????????return?target}
????????var?result?=?Object.qaqAssign(obj1,?obj2,?obj3);
7.1 from方法:【Array.from(arrLike, fn)】
from方法是用于遍历类数组对象,或将类数组对象转换成数组,是数组的静态方法。
类数组对象:
1.可以通过索引值获取属性值,并且要具备length属性的这一类对象
2.类数组对象不能使用数组的遍历器方法,ES6中拓展的from方法可以将类数组对象转为真正的数组,之后就可以使用数组的常用方法
使用方式:
Array.from(arrLike, fn)
arrLike:类数组对象
fn:执行的函数
参数:??????????? 成员值、索引值。
作用域: ??全局作用域(即this默认指向window)
如果传递的fn参数,此时,fn方法的返回值是from函数的执行结果
总结:
from方法不仅可以将类数组转为数组,还可以遍历类数组对象
????<div>1-1-1</div>
????<div>2-2-2</div>
????<div>3-3-3</div>
????<div>4-4-4</div>
????<div>5-5-5</div>
?//将类数组对象转成数组
????????//1.可以将类数组转为数组;2.还可以遍历类数组对象
????????let?arr?=?Array.from(div,?function?(item,?index)?{
????????????console.log(111,?arguments);
????????????//3.返回值影响from方法运行的结果
????????????return?index});
????????console.log(arr);//(5)?[div,?div,?div,?div,?div]
????????arr.forEach(function?()?{
????????????console.log(arguments);})
//实现
????????Array.qaqFrom?=?function?(arrLike,?fn)?{
????????????//1.定义返回的数组
????????????let?result?=?[];
????????????//2.遍历类数组对象
????????????for?(var?i?=?0,?len?=?arrLike.length;?i?<?len;?i++)?{
????????????????//2.1判断是否传递fn
????????????????if?(fn)?{
????????????????????//2.2传递了fn,存储fn执行结果
????????????????????result.push(fn(arrLike[i],?[i]))
????????????????}?else?{
????????????????????//2.3没有传递fn,直接存储fn的成员
????????????????????result.push(arrLike[i],?[i])}}
????????????return?result;}
????????//使用
????????var?arr?=?Array.qaqFrom(div,?function?(item,?index)?{
????????????item.innerHTML?=?'qaq'?+?index;
????????????return?item;});
????????console.log(arr);
7.2 of方法:【Array.of()】
of方法用于创建数组的,是数组的一个静态方法。
之前通过new Array(或者是Array()创建数组有一些问题:
? 1如果没有传递参数,得到的是一个空数组
? 2如果传递了一个数字参数,得到的是带有一个长度的空数组
? 3如果传递一个非数字参数,得到的是带有一个成员的数组
? 4如果传递了多个参数,得到就是一个带有多个参数的数组
ES6中拓展的of方法可以实现:将所有传递的参数都作为数组中的成员存在
创建数组的四种方式
字面量[],
构造函数new Array(),
工厂方法Array(),
Array.of()
?//实现数组的静态方法,
????????Array.qaqOf?=?function?()?{
????????????//?console.log(arguments);
????????????//?return?Array.from(arguments)//一:ES6方法
????????????//二:普通方法:slice方法可以转换数组
????????????return?Array.prototype.slice.call(arguments)}
????????let?arr1?=?Array.qaqOf();?????????//[]
????????let?arr2?=?Array.qaqOf(5);????????//[5]
????????let?arr3?=?Array.qaqOf('5');??????//["5"]
????????let?arr4?=?Array.qaqOf(5,?6,?7);??//[5,?6,?7]
????????console.log(arr1,?arr2,?arr3,?arr4);
7.3查找数组(find、findIndex)
在ES5中拓展了查找成员的方法: indexOf、 lastIndexOf
在ES6中拓展了查找成员的方式:?find、 findIndex
1.允许参数是可以执行的函数
2.参数:执行的函数
函数中有三个参数:成员值、索引值、原数组。
3.作用域:全局作用域(即this默认指向window)
4.find方法
在查找成员的时候,如果找到了则返回该成员,如果没有找到则返回undefined
5.findIndex方法
在查找成员的时候,如果找到了则返回该成员的索引值,如果没有找到返回-1,在查找的过程中,一旦找到则停止遍历
7.4数组内部复制(arr.copyWithin(pos, start, end))
ES6为了实现数组内部复制成员提供了一个方法: copyWithin
1.使用方式:
arr.copyWithin(pos, start, end)
pos: ?要粘贴的位置
start: 要复制的起始位置(包含起始位置)
end: ?要复制的结束位置(不包含结束位置)
返回值:原数组,并且原数组发生变化
例如:
[0,1,2,3,4,5, 6,7,8,9]. copyWithin(3, 6, 9)
结果:
[0,1,2,6,7,8,6,7,8,9]
???????????? //实现
????????Array.prototype.qaqCopyWithin?=?function?(pos,?start,?end)?{
????????????//截取
????????????var?arr?=?this.slice(start,?end);
????????????//?for?(var?i?=?0;?i?<?arr.length;?i++)?{//法一:粘贴
????????????//?????//更新成员,返回原数组
????????????//?????this[i?+?pos]?=?arr[i];
????????????//?}
????????????//法二:数组操作
????????????//?(splice()?方法用于添加或删除数组中的元素。)
????????????//?array.splice(index,howmany,item1,.....,itemX)
????????????//?this.splice(pos,?end?-?start)
????????????//?this.slice.apply()将数组作为参数传递
????????????this.slice.apply(this,?[pos,?end?-?start].concat(arr))
????????????//返回原数组
????????????return?this;}
????????//缩成一句话
????????Array.prototype.qaqCopyWithin?=?function?(pos,?start,?end)?{
return?this.slice.apply(this,?[pos,?end?-?start].concat(this.slice(start,?end))),?this;}
????????//逗号语法,前面的执行完后,执行后面的,并把后面的作为return返回
????????var?result?=?arr.qaqCopyWithin(2,?5,?8);
????????console.log(result);//[0,?1,?5,?6,?7,?5,?6,?7,?8,?9]
????????console.log(result?===?arr);//true//修改的是原数组
ES6中为了遍历数组中成员,拓展了三个迭代器方法:
keys、values、entries
keys:获取索引值
values:获取成员值
entries:获取索引值以及成员值: [index, item, ]
由于实现了数组的迭代器接口方法,就可以使用for of或者是next方法遍历
实现了迭代器接口的数据,都有next方法,可以通过next方法来遍历成员。
返回值:一个对象
value:表示成员值
done:表示是否遍历完成
如果遍历完成了,此时: done将永远是true
value将永远是undefined
var?arr?=?['red',?'green',?'blue',?'pink'];
????????//?//创建迭代器//索引值
????????//?var?result1?=?arr.keys();
????????//?console.log(result1);
????????//还可以通过for?of循环遍历
????????var?result1?=?arr.values();
????????for?(let?item?of?result1)?{
????????????console.log(item);
}
????????//遍历每一个成员
????????console.log(result1.next());//{value:?0,?done:?false}
????????console.log(result1.next());//{value:?1,?done:?false}
????????console.log(result1.next());//{value:?2,?done:?false}
????????console.log(result1.next());//{value:?3,?done:?false}
????????console.log(result1.next());//{value:?undefined,?done:?true}
????????console.log(result1.next());//{value:?undefined,?done:?true}
????????//创建迭代器//成员值
????????var?result2?=?arr.values();
????????console.log(result2);
????????//遍历每一个成员
????????console.log(result2.next());//{value:?red,?done:?false}
????????console.log(result2.next());//{value:?green,?done:?false}
????????console.log(result2.next());//{value:?blue,?done:?false}
????????console.log(result2.next());//{value:?pink,?done:?false}
????????console.log(result2.next());//{value:?undefined,?done:?true}
????????console.log(result2.next());//{value:?undefined,?done:?true}
????????//创建迭代器//成员值
????????var?result3?=?arr.entries();
????????console.log(result3);
????????//遍历每一个成员
????????console.log(result3.next());//{value:?Array(2),?done:?false}//value:?(2)?[0,?"red"]
????????console.log(result3.next());//
????????console.log(result3.next());//
????????console.log(result3.next());//
????????console.log(result3.next());//
//一旦遍历完成,需要重新创建一个迭代器,var?result4=.......
1.for of循环是ES6专门为实现了迭代器接口的对象设计的循环结构
for of是专门为迭代器接口设置的遍历方法。
2.语法:
for (let item of data) {}
可以像其它循环一样在内部使用continue、 break等关键字
3.for of也是可以遍历数组的,但是在遍历过程中,无法使用索引值
遍历数组的时候,item表示数组的每一个成员,没有办法访问索引值,但是我们可以在外部定义一个循环变量,在循环体中手动更新。
for of循环遍历数组的时候,不需要通过索引值访问成员,而for循环以及for in循环要通过索引值访问
4.for in也可以遍历数组,但是有一些问题:
遍历的时候,key显示的是字符串,不是数字(改变了索引值类型)
5.总结:
for循环用于遍历数组、类数组对象,
for in循环用于遍历对象,
for of循环遍历实现了迭代器接口的对象(包括数组)
????? ??var?arr?=?['red',?'green',?'blue',?'pink'];
????????//创建迭代器//索引值
????????var?result1?=?arr.values();
????????//for循环与?for?in循环无法遍历
????????//?for?(var?i?=?0;?i?<?result1.length;?i++)?{
????????//?????console.log(result1);//没有报错,但是也没有执行
????????//?}
????????for?(let?key?in?result1)?{
????????????console.log(key); ?}//没有报错,但是也没有执行
????????//循环//遍历对象
????????for?(let?item?of?result1)?{
????????????//?//遍历到蓝色就停止
????????????//?if?(item?===?'blue')?{
????????????//?????break;
????????????//?}
????????????//?//遍历到蓝色就跳过蓝色
????????????//?if?(item?===?'blue')?{
????????????//?????continue;
????????????//?}
????????????console.log(item);}
????????//迭代器对象一旦遍历完成,就无法再遍历了
????????for?(let?ltem?of?result1)?{
console.log(222); }//前面迭代器执行过result1之后,就不会再执行这个循环了
????????
????????//遍历数组
????????for?(let?item?of?arr)?{console.log(item);}
????????for?(let?item?of?arr)?{console.log(222,?arr);}
????????//数组可以多次遍历
????????//?for?of也是可以遍历数组的,但是在遍历过程中,无法使用索引值
????????var?index?=?0;
????????for?(var?item?of?arr)?{
????????????console.log(item,?index);
????????????//与while循环类式,需要手动更新循环变量
????????????index++;}
8.1结构含义:(解析聚合数据的结构)
1.所谓解构就是解析聚合数据的结构
2.在ES5中的聚合数据有:
对象、数组
在之前,对象中获取数据的方式
只能通过点语法或中括号语法
在之前,数组中获取数据的方式
只能通过中括号语法
3.在ES6中简化了获取数据的方式,提供了解构语法:对象解构与数组解构
4.解构语法不会影响原来的数据。
8.2对象解构(let { key1, key2, ..keys} = obj)
1.语法:
let { key1, key2, ..keys} = obj;?
key1相当于obj.key1
key2相当于obj.key2
keys获取的是剩余的属性,如果没有剩余的属性,获取到的就是一个空对象
注意:
解构出来的属性、变量一定是和对象中的属性是同名的
??????? ?var?obj?=?{
????????????num:?100,color:?'red',shuaibi:?'it?is?me',
????????????arr:?[1,?2,?3],
????????????size:?{width:?222,height:?555},
????????????demo()?{
????????????????console.log(222,?this); }};//指向调用者:obj
????????//过去访问数据?的方法:通过访问obj获取数据
????????//?console.log(obj.num);//100
????????//?console.log(obj['color']);//red
????????//ES6对象解构语法:?let?{?key1,?key2,?..keys}?=?obj;
????????//其中:?...keys三点语法获取剩余的属性
????????//?let?{?num,?color,?...qaq?}?=?obj;
????????console.log(num);//100
????????console.log(color);//red
????????console.log(qaq);//{}//没有剩余的对象就为:空对象
????????//{shuaibi:?"it?is?me",?arr:?Array(3),?size:?{…},?demo:??}
????????obj.demo()
2.解构问题:
1如果使用var解构,会污染全局对象(window),我们可以使用let关键字解决
//使用var会污染全局对象,一般使用let
????????var?{?num,?color,?...qaq?}?=?obj;
????????console.log(window.num);//100
????????//结构语法相当于在全局?var?num?=?obj.num;//var?换成let即可
2解构出来的方法,方法中的this将发生变化
?????? ?obj.demo();//指向调用者:obj
????????//结构出来,this指向会发生改变
????????let?{?num,?color,?demo,?...qaq?}?=?obj;
????????demo();
????????//指向为window//因为相当于let?demo=?obj.demo,window也调用了demo
????????//Window?{window:?Window,?self:?Window,?document:?document,?name:?"",?location:?Location,?…}
????????//注意:严格模式指向undefined
3对于引用类型来说,只是指向的改变,而对于值类型来说,是真正的复制
??//结构值类型的是复制,结构引用类型的是指向改变(引用同一个)
????????let?{?num,?color,?demo,?arr,?size,?...qaq?}?=?obj;
????????//修改数据
????????num?=?200; arr[1]?=?112233; size.width?=?123;
????????console.log(num);//200
????????console.log(arr);//[1,?112233,?3]
????????console.log(size);//{width:?123,?height:?555}
????????console.log(obj);
????????/**?arr:?(3)?[1,?112233,?3]?//引用类型?:指向同一个存储地址
?????????*?color:?"red"???????????//值类型:是直接复制一份,改变前后互不影响
?????????*?demo:???demo()
?????????*?num:?100
?????????*?shuaibi:?"it?is?me"
?????????*?size:?{width:?123,?height:?555}**/
3.逆运用:
我们可以通过三个点语法,将一个对象中的所有数据传递给一个对象字面量中: { ...keys }
?//?结构语法的:逆运用:
????????let?{?num,?color,?demo,?...qaq?}?=?obj;
????????//?注意:num和color是对象字面量的省略语法
????????//??????(对象与属性名同名[参./ES06-01/04.1],...qaq是解构的逆运用)//记住等号是赋值的意思即可
????????var?newObj?=?{?num,?...qaq?};
????????console.log(newObj);
????????//{num:?100,?shuaibi:?"it?is?me",?arr:?Array(3),?size:?{…}}
????????//注意:由于解构出来的数据会创建全局变量,因此,工作中常配合模块化开发使用(相当于局部变量)
8.3数组解构(let [item1, item2, ..tems] = arr)
1.语法:
let [item1, item2, ...items] = arr;
item1表示第一个成员
item2表示第二个成员
items表示剩余的成员
注意:
1.如果使用var解构,也会污染全局对象(window) ,我们可以通过使用let关键字解决
2.左边数组与数据有对应的成员,返回成员;没有的话,返回undefined
???????var?arr?=?['red',?'green',?'blue',?'pink',
?'orange',?'gold',?'yellow',?'purple',?'gray'];
????????//?console.log(arr.slice(2));//获取第三个及其后面的成员
????????//结构语法//let?[item1,?item2,?..tems]?=?arr
????????//注意:var?同样会污染window,使用let即可
????????//等价方式:?let?red?=?arr[0];
????????let?[red,?green,?...items]?=?arr;
????????console.log(red,?green);//red?green
????????console.log(items);//?["blue",?"pink",?"orange",?"gold",?"yellow",?"purple",?"gray"]
2.获取剩余成员的语法:
1如果数组有剩余的成员,获取到的是数组中所有的剩余成员
2如果没有剩余的成员,获取到的是一个空数组
3前面解构的变量,可以正常使用
3.逆运:
我们可以通过三个点语法,将一个数组中的所有数据传递到一个数组字面量中,[ ...r](复制数组)
????????//解构
????????let?[red,?green,?...items]?=?arr;
????????//复制数组
????????//?var?newArr?=?[red,?green,?...items];
????????var?newArr?=?[red,?...items,?green];//注意,新数组里面的顺序,是按复制的顺序排列
????????console.log(newArr);//["red",?"green"......]全部都复制了过来
?//如果只传递?...items,newArr与arr成员完全相同,但不相等
????????var?newArr?=?[...items];
????????console.log(newArr?==?arr);//false
????????console.log(newArr?===?arr);//false
1.记住单个等号为赋值的意思即可:
解构指的是等号左侧的部分,
逆运用是等号右侧的部分,
例如,复制数据
2.解构:
对象解构,属性名称匹配
数组解构,索引值匹配(位置对应)
之前适配默认参数的方式:
1可以通过 || 运算符来适配参数的默认值
但是使用 || 运算符会忽略6个值为false的参数:
?0、 ‘ ’ 、 undefined、 null、 false、 NaN
2可以使用三元运算符: ?
? ?: ??
如果参数过多,书写比较麻烦
3使用extend | assign方法适配对象, 对于值类型的参数不适用。
4 在ES6中为了解决这样的问题,提供了适配默认参数的方式,直接在参数集合中为形参赋值即可
如果传递了参数,则使用传递的参数
如果没有传递参数,则使用默认参数
注:ES6拓展的适配默认参数的方式与三元运算符的方式是等价的
????? ??//定义函数
????????//4.1在ES6中,可以直接为参数赋值,定义默认参数
????????function?demo(color?=?'pink')?{
????????????//1.1通过?||(或)运算符设置默认值
????????????//?color?=?color?||?'red';
????????????//2.1三元运算符适配,如果参数较多会比较麻烦
????????????//?color?=?color?===?undefined???'red'?:?color;
????????????//3.使用extend?|?assign方法适配对象,?对于值类型的参数不适用。且是比较麻烦的
????????????console.log(color);
????????}
????????//执行函数并传递参数
????????demo();?????????//1.2?red???//2.1?red???//4.1?pink
????????demo(0);????????//1.2?red???//2.1??0????//4.1??0
????????demo(NaN);??????//1.2?red???//2.1?NaN???//4.1?NaN
????????demo(false);????//1.2?red???//2.1?false?//4.1?false
????????demo(null);?????//1.2?red???//2.1?null??//4.1?null
????????demo(undefined);//1.2?red???//2.1?red???//4.1?pink
????????demo('red');????//1.2?red???//2.1?red???//4.1?red
之前,可以通过arguments来获取所有参数,但是arguments是一个类数组对象,不能使用数组的常用方法。
于是ES6拓展了获取剩余参数语法,获取的剩余参数是一个数组,所以可以直接使用数组的常用方法
1.语法:
function demo(arg1, arg2, ...args) {}
arg1表示第一个参数
arg2表示第二个参数
args表示剩余的参数
????????//?function?demo()?{
?????//?console.log(arguments); }//1.1类数组,不能直接使用数组方法
//?获取剩余参数
????//?function?demo(num1,?num2,?...args)?{
//console.log(num1,?num2,?...args); }//2.1获取的是数组,可以使用数组方法
?? ??????demo();??????????????//1.2:[]???????//2.2:undefined?undefined
????????demo(1);?????????????//1.2:[1]?????????//2.2:1?undefined
????????demo(1,?2);??????????//1.2:[1,2]???????//2.2:1?2
????????demo(1,?2,?3);???????//1.2:[1,2,3]?????//2.2:1?2?3
????????demo(1,?2,?3,?4);????//1.2:[1,2,3,4]???//2.2:1?2?3?4
????????demo(1,?2,?3,?4,?5);?//1.2:[1,2,3,4,5]?//2.2:1?2?3?4?5
//3.1求参数和老方法
????????function?add()?{
????????????//?根据argument求和
????????????var?result?=?0;
????????????for?(var?i?=?0;?i?<?arguments.length;?i++)?{
????????????????result?+=?arguments[i]}
????????????return?result}
????????console.log(add(1,?2,?3,?4,?5)); //3.2测试//15
????????//3.3获取剩余参数?求和
????????function?add(...nums)?{//通过数组的方法求和
????????????return?nums.reduce(function?(res,?item)?{
????????????????return?res?+?item},?0)}
????????console.log(add(1,?2,?3,?4,?5));//15
2.获取剩余参数的语法:
1如果有剩余的参数,获取到的是一个由所有剩余参数组成的数组
2如果没有剩余的参数,获取到的是一个空数组
3前面参数可以正常使用,如果没有对应的参数,返回undefined
4在箭头函数中有广泛的应用
3.获取剩余参数的逆运用:
语法:
demo(...args)
1.我们可以将一个数组中成员,作为参数传递到一个方法中
2.在之前我们可以通过apply方法,将数组中的每一项数据传递到一个方法中
3.但是使用apply需要考虑this的指向问题
4.我们可以使用获取剩余参数的语法,就不需要考虑this指向的问题了,正常执行函数。
??//4.1逆运用
????????var?arr?=?[1,?2,?3,?4,?5];
????????function?add(...nums)?{
????????????//通过数组的方法求和
????????????return?nums.reduce(function?(res,?item)?{
????????????????return?res?+?item
????????????},?0)
}
????????//?//4.2使用apply传递
????????//?var?result?=?add.apply(null,?arr);
????????//4.3使用?...args传递
????????let?result?=?add(...arr)
????????console.log(result);//4.2/4.3:?15
9.3箭头函数(let demo=(? )=>{? })
1.在ES5中定义函数的方式:
?1函数定义式、 2函数表达式、 3构造函数式
4.在ES6中又拓展了一种方式:
箭头函数
2.语法:
let demo=(? )=>{? }
(? ) : ?表示参数集合
=> :? 是箭头函数的标志
{? } :? 是函数体
3.几点省略语法:
1如果参数集合中只有一个参数,即可省略参数集合
如果使用三个点语法获取剩余参数或者解构语法,不能省略参数集合
2如果函数中只有一句话,或者只有返回值的时候,可以省略return以及函数体
??????? //?4.1省略参数集合
????????let?print?=?(msg)?=>?{
????????????console.log(msg);}
????????//4.3只有一个参数省略参数集合
????????let?print?=?msg?=>?{
????????????console.log(msg);}
????????print('hello');//4.2/4.3?hello
????????//4.4获取剩余参数语法不能省略
????????let?print?=?(...args)?=>?{
????????????console.log(...args); }//三个点语法的逆运用
????????print(100,?'hello',?true);//4.5?100?"hello"?true
????????//4.6解构语法不能省略
????????let?print?=?({?msg?})?=>?{
????????????console.log(msg);}
????????print({?color:?'red',?msg:?'hello'?})//hello
????????//4.7省略函数体
????????var?arr?=?[1,?3,?5,?7,?9];
????????//数组映射
????????//?let?result?=?arr.map((item)?=>?{
????????//?????//?return?item?*?item
????????//?????//?return?Math.pow(item,?2)
????????//?????return?Math.pow(item,?3)
????????//?})
????????//4.8进行省略
????????//?let?result?=?arr.map(item?=>?item?*?item)
????????let?result?=?arr.map(item?=>?Math.pow(item,?2))
????????console.log(result);//[1,?9,?25,?49,?81]
4. 箭头函数的特点:
1无法使用arguments,但是我们可以使用三个点语法获取剩余参数
????????//?//?1.1无法使用arguments
????????//?let?add?=?(...args)?=>?{//1.3添加...args
????????//?????//?console.log(args);//1.2//1.3
????????//?????return?args.reduce((res,?item)?=>?res?+?item)//1.5
????????//?}
????????//?console.log(add(1,?2,?3,?4,?5));
????????//1.2报错arguments不能使用 ?
?//1.3?[1,?2,?3] ??//1.5?15
????????//1.6简化
????????let?add?=?(...args)?=>?args.reduce((res,?item)?=>?res?+?item)
????????console.log(add(1,?2,?3,?4,?5));//1.6?15
2无法作为构造函数来使用
?//?2.1无法作为构造函数来使用
????????//?function?Player(x,?y)?{
????????//?????this.x?=?x;
????????//?????this.y?=?y;}
????????//?//2.7函数表达式
????????//?let?Player?=?function?(x,?y)?{
????????//?????this.x?=?x;
????????//?????this.y?=?y; }
????????//2.8箭头函数不允许
????????let?Player?=?(x,?y)?=>?{
????????????this.x?=?x;
????????????this.y?=?y;}
????????//?//2.2定义原型方法//老方法
????????//?Player.prototype={
????????//?????constructor:?}//这个需要重写
????????//?Player.prototype.getPosition?=?function?()?{?};//2.3
????????//2.4
????????Object.assign(Player.prototype,?{
????????????getPosition()?{
????????????????console.log(this.x,?this.y);}})
????????//2.5实例化
????????let?p?=?new?Player(100,?200);
????????p.getPosition()
????????//2.6/2.7?100?200
????????//2.8?报错:箭头函数不能作为构造函数
3箭头函数中的this指向永远是定义时的
?????? A在普通函数中,this是执行时的上下文对象,谁调用指向谁
B无论使用call、apply或者是 bind方法都无法改变箭头函数的this指向
C改变箭头函数this指向唯一的方式就是改变其宿主环境this
也就是说改变其外部函数的作用域
??????? ?//3.1箭头函数中的this指向永远是?定义时的
????????//3.2严格模式:中的普通函数?this是undefined
????????'use?strict'
????????console.log(this);//window
????????var?demo?=?()?=>?{
????????????console.log(this);
????????};
????????//3.3普通函数
????????function?demo2()?{
????????????console.log(this);
????????}
????????demo()//3.1?Window
????????demo2()//3.3?undefined
|