目录
7.1 from方法:【Array.from(arrLike, fn)】... 15
7.4数组内部复制(arr.copyWithin(pos, start, end))... 17
8.2对象解构(let { key1, key2, ..keys} = obj)... 21
8.3数组解构(let [item1, item2, ..tems] = arr)... 23
9.3箭头函数(let demo=( )=>{ })... 26
1.ES6
1.1ECMAScript发展历史:
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等关键字),但是又保留了弱类型语言,动态语言的特征。
1.2ES6简介
ECMA组织为了让制定的规范被编译成可被浏览器支持的版本,提供了babel编译库,ES每次发布版本,babel都会更新一个版本,在新版本中提供的功能,通过babel拓展来实现编译。
在nodejs端,在6.0版本之后,开始支持ES6,所以我们可以在后面的node学习中直接使用ES6了。
在浏览器端,为了兼容更多的浏览器。我们需要将ES6的代码,编译成浏览器支持的版本。
注:当前的语法浏览器支持,因此可以用浏览器直接测试。
2.关键字
2.1 let关键字
用来定义块作用域变量的
var定义函数级作用域变量的:
在函数内部定义的变量,外部无法访问,
在代码块(if, for等)中定义的变量,外部可以访问
let定义块作用域变量的:
在函数内部定义的变量,外部无法访问
在代码块(if, for等)中定义的变量,外部仍然无法访问
用来定义块作用域变量的
2.2 let与var比较
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
2.2const关键字
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.字符串拓展
3.1多行字符串
3.1.1单行字符串:
由一组单引号或者双引号定义的字符串
单行字符串的问题:
1单行字符串不能换行
2 一些特殊的按键要使用转义字符\n
3一些特殊的字符要使用转义字符\x20
4字符串标志符号不能直接嵌套
5单引号中不能直接写单引号,要转义\'
6双引号中不能直接写双引号,要转义\”
....
3.1.2多行字符串
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
4.数字拓展
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
4.1 isNaN
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
4.2 isFinite
全局中:
有一个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
4.3 isInteger
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.对象拓展
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
6.3 assign(用于复制对象)
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.数组拓展
7.1 from方法:【Array.from(arrLike, fn)】
from方法是用于遍历类数组对象,或将类数组对象转换成数组,是数组的静态方法。
类数组对象:
1.可以通过索引值获取属性值,并且要具备length属性的这一类对象
2.类数组对象不能使用数组的遍历器方法,ES6中拓展的from方法可以将类数组对象转为真正的数组,之后就可以使用数组的常用方法
使用方式:
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//修改的是原数组
7.5迭代器
7.5.1迭代器方法
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=.......
7.5.2for of循环
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. 解构
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
8.4解构总结
1.记住单个等号为赋值的意思即可:
解构指的是等号左侧的部分,
逆运用是等号右侧的部分,
例如,复制数据
2.解构:
对象解构,属性名称匹配
数组解构,索引值匹配(位置对应)
9.函数拓展
9.1默认参数
之前适配默认参数的方式:
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
9.2获取剩余参数
之前,可以通过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.语法:
( ) : 表示参数集合
=> : 是箭头函数的标志
{ } : 是函数体
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