ES6简介
ECMAScript 6
ECMAScript 是语言的标准
6是版本号
ES6 = ECMAScript 这门语言的第六代标准
ECMAScript = 语法 + API
ES与Javascript的关系
Javascript(浏览器端)= ECMAScript (语法+API) + DOM + BOM
ES的兼容性
主流浏览器几乎都支持ES6
IE老版本等不支持的浏览器,可以用Babel转码
let和const是什么
声明变量或常量
let代替var
const 声明常量 constant
const
为什么需要const
const就是为了一些初始化后就不希望改变的属性
const的注意事项
使用const声明常量,一旦声明,就必须立即初始化,不能留到以后赋值
const声明常量,允许在不重新赋值的情况下修改它的值
let、const与var的区别
重复声明
已存在的变量,又声明一遍 var允许重复声明,let、const不允许
变量提升
var会提升变量的声明到当前作用域的顶部
let和const不存在变量提升
暂时性死区
只要作用域内存在let、const,它们所声明的变量或常量就自动“绑定”这个区域,不在受到尾部作用域的影响
window对象的属性和方法
在全局作用域中,var声明的变量,通过function声明的函数,会自动变成window对象的属性或方法
let 和 const 不会
块级作用域
什么是块级作用域
var没有块级作用域
let/const有块级作用域
作用域链
内层 -》 外层-》… -》 全局
有哪些块级作用域
{}
for(){}
while(){}
do{}while()
if(){}
switch(){}
函数作用域 function(){}
对象中的{}不构成作用域
模板字符串
表示
模板字符串与一般字符串的区别
一般字符串使用 + 好拼接变量
模板字符串 使用${变量}
输出多行字符串使用\n 也可以直接回车换行
输出 `和\等特殊字符
` hello ${world}`
模板字符串的注入
模板字符串可以注入变量
对象属性
函数
运算
总而言之就是能得到一个值
箭头函数
认识箭头函数
箭头函数的结构
const/let 函数名 = 参数 =》函数体
如何讲一般函数写成箭头函数
箭头函数的注意事项
单个参数
const add = x => { return x + 1; }
无参数或则多个参数()不能省略
单行函数体
const add = (x,y) => x + y;
单行函数体可以同时省略{}和return
多行函数体不能省略
单行对象
const add = (x,y) => { return { value: x + y; }; } const add = (x,y) => ({ value: x + y; })
返回单行函数在{}外面加上 ()浏览器会将他看成对象{}
this指向
全局作用域中的this指向
console.log(this); //window
一般函数(非箭头函数)中的this指向
'use strict';//标注为严格模式 function add(){ console.log(this); } //非严格模式下undefined->window add(); //严格模式下 add(); //undefined window.add();//window调用
只有在函数调用的时候this指向才确定,不调用的时候,不知道指向谁
this指向和函数在哪里调用没关系,只和谁在调用有关
dom的事件,this就是dom对象
构造函数中的this 就是指向这个对象
apply()和call()中的this指向window
数组中的this指向 数组本身
new 函数返回的对象 第一步创建一个{} 第二部this = {} 第三步值赋给this 最后返回this
箭头函数中的this指向
const calc = { add:() => { console.log(this); } } calc.add();//window /* 解析: 结合作用域链 箭头函数没有this 所以在calc中找this 因为对象的{}不构成作用域 所以最后this指向windwo */
箭头函数没有自己的this指向
`use strict`; //开启严格模式 const calc = { add:function(){ const adder = () =>{ console.log(this); }; adder(); } }; calc.add();//指向calc const addFn = calc.add; addFn(); //undefined -> window
不适合箭头函数的场景
作为构造函数
const Person = () => {} new Person(); // 箭头函数没有this指向 // 所以报错
需要使用arguments的时候
function add(){ console.log(arguments);//arguments [1,2] } add(1,2); //变成箭头函数 const add = () => console.log(arguments); add();//报错 因为 箭头函数中没有arguments //ES6中会剩余参数可以代替arguments子
例子
const timer = { time: 0, start: function(){ btn.addEventListener('click',function(){ setInterval(function(){ console.log(this);//这里的setInterval在非严格模式下undefined-》window对象 this.time++; result.innerHTML = this.time; },1000); },false) } } //用that 保存上下文的this 解决 const timer = { time: 0, start: function(){ let that = this; btn.addEventListener('click',function(){ setInterval(function(){ this = that; console.log(this);//这里的setInterval在非严格模式下undefined-》window对象 this.time++; result.innerHTML = this.time; },1000); },false) } } //用箭头函数解决这个问题 const timer = { time: 0, start: function(){ btn.addEventListener('click',() =>{ setInterval(() =>{ console.log(this);//这里的setInterval在非严格模式下undefined-》window对象 this.time++; result.innerHTML = this.time; },1000); },false) } } timer.satrt() //解析因为箭头函数没有自己的this //所以在第一个内层的箭头函数中会去上一个函数获取this对象 //但是上一个对象也是箭头函数没有this //所以在上面找到了timer对象作为this
解构赋值
认识解构赋值
//以前的写法 const arr = [1,2,3]; const a = arr[0]; const b = arr[1]; const c = arr[2]; //解构赋值 const [a,b,c] = [1,2,3]
解构赋值是什么
解析某一数据的结构,将外面想要的东西提取出来,赋值给变量或常量
数组的解构赋值的原理
模式(结构)匹配
[] = [1,2,3]
左右的结构一样都是数组
索引值相同的完成赋值
[a,b,c] = [1,2,3]
const [a,[,,b],c] = [1,[2,4,5],3] //获取1 5 3
数组结构赋值的默认值
默认值的基本用法
const [a,b] = []; //const [a,b] = [undefined,undefined] const [a = 1,b = 2] = []; //设置默认值
默认值生效条件
只有当一个数组成员严格等于(===)undefined时,对应的默认值才会生效
const [a=1,b=2] = [3,0] //a = 3 //b = 0 const [a=1,b=2] = [3,null] //a = 3 //b = null const [a=1,b=2] = [3] //a = 3 //b = 2
默认值表达式
如果默认值是表达式,默认值表达式是惰性求值的
const func = () => { console.log("我被执行了"); return 2; } const [x= func()] = [1]; console.log(x); // 1 //用到了才会去执行这个函数 const [x= func()] = []; console.log(x); // 2
常见的类数组的解构赋值
arguments
将arguments类数组可以看成数组去解构赋值
function func(){ const [a,b] = arguments; console.log(a,b); } func(1,2);
NodeList
const [p1,p2,p3] = document.querySelectorAll('p');
NodeList也可以使用数组的方式解构赋值
函数参数的解构赋值
const array = [1,2]; const add = arr => arr[0]+ arr[1]; //使用解构赋值 const add = ([x,y]) => x + y; add(array);
交换变量的值
let x = 1;let y = 2;let temp = x;x = y;y = temp;//解构的方式交换[x,y] = [y,x];
对象的解构赋值的原理
模式(结构)匹配
- {} = {}
属性名相同的完成赋值
const {'age':age,'username':username} = {username:'Alex',age:18};
属性名和变量相同可简写
const {age,username} = {username:'Alex',age:18};
可以通过这个取别名
const {'age':age,'username':name} = {username:'Alex',age:18}
;
对象结构赋值的注意事项
默认值的生效调剂
对象的属性值严格等于undefined的时候,对应的默认值才会生效
数组还是对象的默认值都使用等号 const {username = 'ZhangSan', age = 0} ={username:'alex'}
默认值表达式
如果默认值是表达式,默认值表达式是惰性求值的将一个已声明的变量用于解构赋值
let x = 2;
({x} = {x:1})
1
2
如果一个已经声明的变量用于对象的解构赋值,整个赋值需要在圆括号中进行
const {toString} = {}; console.log(toString);
如果一个已经声明的变量用于对象的解构赋值,整个赋值需要在圆括号中进行
可以取到继承得到属性
const {toString} = {}; console.log(toString);
对象解构赋值的应用
const logPersonInfo = ({username,age}) => {console.log(username,age)} logPersonInfo({username:'alex',age:18})
const obj { x:1, y:[2,3,4], z:{ a:5, b:6 } } const {y,y:[,yy]} = obj; //只取3 和数组
字符串的解构赋值
数组形式的解构赋值
const [a,b,,c] = 'hello'; console.log(a,b,c)//h e o
对象形式解构赋值
const { 0:a,1:b,length} = 'hello' console.log(a,b,length)//h e 5
数字和布尔值的解构赋值
const { a = 1 ,toString} = 123; const { b = 2 ,toString} = true; //右边转换为了包装类但是没有属性只有值所以取不到
先将等号右边的值转为对象
undefined 和 null的解构赋值
const {toString} = undefined; const {toString} = null; //都会报错 • 1 • 2 • 3
- 由于undefined 和 null 无法转为对象,所以对他们进行解构赋值,都会报错
属性和方法的简洁表示法
对象字面量是什么
实例化构造函数生成对象
const person = new Object(); person.age = 18; person.speak = function(){};
对象字面量
const person = { age:18, speak: function(){} }
属性的简洁表示法
const age = 18; const person = { // age:age age };
键名和变量或常量名一样的时候,可以只写一个
方法的简洁表示 const person = { // speak:function(){} speak(){} }
方法可以省略冒号和function关键字
方括号语法
方括号语法的用法
const prop = 'age'; const person = {}; //person.prop = 18; person[prop] = 18; const person = { [prop]:18 }; //方括号语法可以卸载对象字面量中
方括号中可以放什么
${}
[值或通过计算可以得到的(表达式)]
const prop = 'age'; const func = () => 'age2'; const person = { [prop]:18, [func()]:18, ['sex']:'male', ['sex' + '1']:'male' }
方括号语法和点语法的区别
点语法是方括号语法的特殊形式
点语法使用:属性名有数字、字母、下划线以及$构成,并且数字还不能打头的时候可以使用点语法
当你的属性或方法名是合法标识符时,可以使用点语法,其他情况下请使用方括号语法
函数参数的默认值
认识函数参数的默认值
调用函数的时候传参了,就用传递的参数;如果没传参,就用默认值
函数参数默认值的基本用法
//以前做法 const multiply = (x,y) => { if(typeof y === 'undefined') y = 1; return x * y; } //函数参数默认值 const multiply = (x,y=1) => { return x * y; }
函数参数默认值的注意事项
默认值的生效条件
不传递参数,或者明确的传递的undefined作为参数,只有这两种情况下,默认值才会生效
const multiply = (x,y=1) => { return x * y; } multiply(2,0); // 2 multiply(2,null); // 0 2*null null被看待成了0 multiply(2,undefined);//2
默认值表达式
如果默认值是表达式,默认值表达式是惰性求值的
设置默认值的小技巧
函数参数的默认值,最好从参数列表的右边开始设置默认值
函数参数默认值的应用
接受很多参数得到时候
const logUser = (username = 'ZhangSan',age = 0,sex = 'male') => console.log(username,age,sex);
接收一个对象作为参数
const logUser = options => console.log(options.username,options.age,optionssex); const logUser = ({username,age,sex}) => console.log(username,age,sex); const logUser = ({username= 'ZhangSan',age = 0,sex = 'male'} = {}) => console.log(username,age,sex);
剩余参数
认识剩余参数
const add = (x,y,z,...args) => {}
剩余参数的本质
const add = (x,y,...args) => { console.log(x,y,args); } add(1,2,3,4,5); // 1 2 [3,4,5]
剩余参数永远都是一个数组,即使没有值,也是空数组
箭头函数的剩余参数
箭头函数的参数部分即使只有一个剩余参数,也不能省略圆括号
使用剩余参数代替arguments获取实际参数
const add = function(){ console.log(arguments); } //箭头函数中没有arguments 使用过剩余参数代替 const add = (...args) => { console.log(args); } add(1,2);
剩余参数的位置
剩余参数只有是最后一个参数,之后不能在有其他参数,否则会报错
剩余参数的应用
const add = (...args) => { let sum = 0; for(let i=0;i sum += args[i]; } return sum; }
与解构赋值结合使用
const [num,...agrs] = [1,2,3,4] // num 1 // agrs [2,3,4]
const func = ([num,..agrs]) => {} func([1,2,3])
const {x,y,...z} = { a:3, x:1, y:2, b:4 } //x 1 //y 2 //z {3,4} 剩余元素
展开运算符
认识展开运算符
[3,1,2] Math.min([3,1,2]) // 错误 Math.min(3,1,2) [3,1,2] => 3,1,2
数组展开运算符的基本用法
Math.min(...[3,1,2])
区分剩余参数和展开运算符
根本区别
//展开运算符 // [3,1,2] => 3,1,2 //剩余参数 // 3,1,2 => [3,1,2]
- 他们的操作刚好相反
区分剩余参数和展开运算符
const add = (...agrs) => { console.log(args); // [1,2,3] console.log(...args); //1 2 3 } add(1,2,3)
consloe.log([...[1,2,3],4]) // [1,2,3,4]
数组展开运算符的应用
复制数组
const a = [1,2] const c = [...a]
合并数组
const a = [1,2] const b = [3] const c = [4,5] d = [0,...a,...b,...c] //d [0,1,2,3,4,5]
字符串转为数组
- 字符串也可按照数组的形式展开
arr = [...'hello']; // arr ["h","e","l","l","o"]
常见的类数组转化为数组
arguments
function func(){ console.log([...argument]) }
NodeList
let nodeList = [...document.querySelectorAll('p')];
对象展开运算符
展开对象
对象不能直接展开,必须在{}中展开
对象的展开:把属性罗列出来,用逗号分隔,方法一个{}中,构成新的对象
const apple = { color:'红色', shape:'球形', taste:'甜' }; console.log({...apple})
合并对象
const apple = { color:'红色', shape:'球形', taste:'甜' }; const pen = { color:'黑色', shape:'圆柱形', use:'写字' }; console.log({...apple,...pen}) /* 会拥有所有属性 属性名相同的会被后者覆盖 { color:'黑色', shape:'圆柱形', taste:'甜', use:'写字' } */
注意事项
空对象的展开
如果展开一个空对象,则没有任何效果
非对象的展开
如果展开的不是对象,则会自动将其转为对象,在将其属性罗列出来
如果展开运算符后面是字符串,它会自动转成一个类似数组的对象,因此返回的不是空对象
对象中对象属性的展开
对象中还有对象 不会展开对象中的对象属性
对象展开运算符的应用
复制对象
const a = {x:1,y:2}; const b = {a:1}; const c = {...a,...b}
用户参数和默认参数
// 对象解构 函数参数加默认值 const logUser = ({username = 'ZhangSan',age = 0,sex = 'male'} = {}) => { console.log(username,age,sex) } //使用展开运算符 const logUser = userParam => { cons defaultParam = { username:'ZhangSan', age = 0, sex = 'male' }; const param = {...defaultParam,...userParam}; }
Set集合
Set是什么
数组是一系列有序的数据集合
Set是一系列无序、没有重复值的数据集合
const s = new Set(); s.add(1); s s.add(1); // s.length 2 //s {1,2}
Set没有下标取标识每一个值,所以Set是无序的,也不能像数组那样通过下标取访问Set的成员
Set实例的方法和属性
add方法
const s = new Set(); s.add(1).add(2).add(1);
delete方法
s.delete(1);
clear方法
s.clear();//清楚set集合所有内容
forEach方法
s.forEach(function(value,key,set){ //Set 中的 value = key console.log(value,key,set) console.log(this) //指向 document },document) //按照成员添加进集合的顺序遍历
size属性
s.size
Set构造函数的参数
数组
const s = new Set([1,2,1]); // s {1,2}
字符串、arguments、NodeLIst、Set等
const s = new Set('hi'); //s {'h','i'} function func(){ console.log(new Set(arguments)); } func(1,2,1) console.log(new Set(document.querySelectorAll('p'))); console.log(new Set(s));
判断重复的方式
const s = new Set([1,2,1]); //set 对重复值的判断基本遵循严格相等(===) //但是对于NaN的判断与 === 不同,Set中NaN等于NaN const s = new Set([NaN,2,1,NaN]);
什么时候使用Set
数组或字符串去重时
不需要通过下标访问,只需要遍历时
为了使用Set提供的方法和属性时(add delete clear has forEach size等)
Set的应用
数组去重
const s = new Set([1,2,1]) console.log([...s]) console.log([...new Set([1,2,1])])
字符串去重
const s = new Set('adsabd'); console.log([...new Set('adsabd')].join('0'))
存放DOM元素
const s = new Set(document.querySelectorAll('p')) console.log(s) s.forEach(function(elem){ elem.style.color = 'red'; });
Map集合
Map是什么
Map和对象都是键值对的集合
键->值 key->value
Map和对象的区别
对象一般用字符串当做键
const obj = { name:'alex',true:'true'}
基本数据类型: 数字、字符串、布尔值、undefined、null
应用类型:引用对象([]、{}、函数、Set、Map等)
都可以作为Map的键
Map实列的属性和方法
set方法
const m = new Map(); m.set('age',18).set(true,'true').set('age',20); console.log(m)
get方法
const m = new Map(); m.set('age',18).set(true,'true').set('age',20); console.log(m.get('age')) //不存在的 会返回undefined
has方法
m.has('age')
delete方法
m.delete('age') //删除不存在的成员 什么都不会发生 也不会报错
clear方法
m.clear()
forEach方法
m.forEach(function(value,key,map){ console.log(this);//document },document)
size属性
//对象没有size属性 m.size
Map构造函数的参数
数组
//只能传二维数组,必须体现出键和值 console.log(new Map(['name','alex'],['age',18]))
Set、Map
//set 中也必须体现出键和值 const s = new Set(['name','alex'],['age',18]) console.log(new Map(s)
const m1 = new Map(['name','alex'],['age',18]); console.log(new Map(m1))
Map的注意事项
判断键名是否相同的方式
基本遵循严格相等(===)
列外就是NaN ,在Map中是相等的
什么时候使用Map
如果只需要 k - v的结构,或者需要字符串以外的值做键,使用Map更适合
Map的应用
const [p1,p2,p3] = document.querySe;ectoryAll('p') const n = new Map([p1,'red'],[p2,'green'],[p2,'blue']); m.forEach(function(color,elem) => { elem.style.color = color; })
Iterator
作用
遍历器(迭代器)
寻找Iterator
let a = [1,2][Symbol.iterator]() //a Array Iterator {} a.next() //{value: 1, done: false} a.next() //{value: 2, done: false} a.next() //{value: undefined, done: true}
为什么需要iterator
iterator 是统一的一个遍历方式
更方便使用iterator
我们一般不会直接使用iterator 去遍历
比如 es6 提供的 for of
for … of的用法
认识 for…of
const arr = [1,2,3] /* for of 的本质就是封装了这一套东西 const it = arr[Symbol.iterator](); let next = it.next(); while(!next){ console.log(next.value); next = it.next; } */ for(const item of arr){ console.log(item); }
for of 循环只会遍历出那些done为false时,对应的值
与beak、continue一起使用
const arr = [1,2,3] for(const item of arr){ if(item == 2){ break; } console.log(item); }
在for of中取到数组的索引
const arr = [1,2,3] //keys()得到的就是索引的可遍历对象,可以遍历的索引值 for(const key of arr.keys){ console.log(key); } //valus()得到的是值 for(const v of arr.values){ console.log(v); } //entries() 得到是索引 + 值得数组得可遍历对象 for(const entrues of arr.entrues()){ console.log(entrues); } //使用解构赋值 直接拿到索引 + 值 for(const {index,value} of arr.entrues()){ console.log(index , value); }
原生可遍历与非原生可遍历
什么是可遍历
只要有Symbol.iterator方法,并且这个方法可以生成可遍历对象,就是可遍历的
只要可遍历,就可以使用 for…of循环来统一遍历
原生可遍历有哪些
数组
字符串
Set
Map
arguments
NodeList
非原生可遍历有哪些
一般对象 可以使用 for in 自己添加Symbol.iterator方法
const person = {sex:'male',age:18}; person[Symbol.iterator] = () => { let index = 0; return { next() { index++; if (index === 1) { return { value: person.age, done: false }; } else if (index === 2) { return { value: person.sex, done: false }; } else { return { done: true }; } } }; };
使用了Iterator
原生可遍历
Array数组
String数组
Set
Map
函数得arguments对象
NodeList对象
数组得展开运算符
数组得解构赋值
ES6中新增加方法
includs()方法
判断字符串中是否包含有某些字符
//基本用法 console.log('abc'.includes('a')); // true console.log('abc'.includes('ab')); // true console.log('abc'.includes('bc')); // true console.log('abc'.includes('ac')); // false
// 第二个参数 // 表示开始搜索的位置,默认是0 console.log('abc'.includes('a')); //ture console.log('abc'.includes('a',0)); //true console.log('abc'.includes('a',1)); //false
实际开发中的应用