第十周
ES6——1
变量
-
ES6
- ECMA 规定了 JS 的标准,主要包括:语法、API
- ES6 也是 ES2015
- JavaScript = ECMAScript + DOM + BOM
-
let 和 const
-
声明变量和常量;
-
不知道用哪个,先用const,出了问题再改
-
与var 区别
-
重复声明
-
function fun(a){ let a = 1; } fun();
-
报错
-
-
变量提升
- let、const 不存在变量提升
-
暂时性死区
-
注意:函数只有被调用的时候才会形成作用域
-
let a = 1; function fun(){ console.log(a); let a = 2; } fun()
-
因为暂时性死区,作用域内存在a 变量,a 变量就会绑定这个作用域,不会去上层作用域找值
-
-
window 对象的属性和方法(全局作用域中)
- let、const 不会绑定到window 上
-
块作用域
-
for(let i=0; i<3 ;i++){ } console.log(i)
-
报错,let、const 存在块级作用域
-
-
-
模板字符串箭头函数
-
模板字符串
- `` 反引号
- $
- 变量,对象属性,表达式 只要最终可以得出一个值的,都可以注入模板字符串中
-
箭头函数
-
const add = (x, y) => { let sum = a + b; return sum; } add(1, 1);
-
单个参数可以省略括号
-
单条语句可以省略大括号以及return
-
返回单个对象时,圆括号包裹起来,不用写大括号
-
const add = (x, y) => ({value: x+y}) add(1, 1)
-
-
返回单个数组,可以不写大括号以及return
-
关于this 指向
-
普通函数指向回顾
- 'use strict'
- 全局作用域中执行的函数,其实指向的应该是undefined ,只不过在非严格模式下,系统帮我们指向了window 对象
- 事件处理函数,指向事件dom
- 构造函数,在new 关键字作用下,指向新实例
- 'use strict'
-
箭头函数没有自己的this
-
const calc = { add:() => { console.log(this); } } calc.add(); // window
-
-
-
不适合使用箭头函数
- 作为构造函数
- 需要this 指向调用对象
- 需要使用arguments,箭头函数中没有arguments
-
解构赋值
-
数组
-
原理
- 模式(结构)匹配
- 索引值相同的完成赋值
-
默认值
- 数组成员严格等于(===)undefined,默认值才会生效
- 如果默认值是表达式,默认值表达式是惰性求值的,也就是说只有在默认值生效时才会执行并赋值
-
常见的类数组解构赋值
-
arguments
-
function fun(){ const [a, b] = arguments; } fun(1, 2);
-
-
NodeLIst
-
document.querySelectorAll('p'); // 返回NodeList
-
-
-
函数参数解构赋值
-
const array = [1, 2]; // const add = arr => arr[0] + arr[1]; const add = ([a=0, b=0]) => a + b; console.log(add(array));
-
-
交换变量值
-
[a, b] = [b, a];
-
等号右边是静态,直接指向变量的值,不会反向赋值
-
-
-
对象
-
原理
-
模式(结构)匹配
-
属性名相同的完成赋值
-
const {age:age, username:username} = {username:'Alex', age:18}; const {age, username} = {username:'Alex', age:18}; // 取别名 const {age, username:uname} = {username:'Alex', age:18};
-
-
-
方法也是对象的属性,属性值是函数的特殊属性
-
对象解构赋值的默认值
- 属性值严格等于 undefined 才会生效,并且赋值一定是等号,多个变量之间还是逗号连接
- 如果默认值是表达式,默认值是惰性求值的,同数组
-
将一个已经声明的变量用于解构赋值
-
整个赋值过程包上圆括号,说白了就是规避语法错误
-
let x = 1; ({x}={x:2}); console.log(x); // 2
-
-
可以取到继承的属性
- 比如 toString 等原型链上的方法
-
复杂的嵌套
-
const obj = { x: 1, y: [2, 3, 4], z: { a: 5, b: 6 } }; const { y, y: [,yy], z, z: { b } } // 注意这里的 y 和 z 的取值,[, yy]是无法取到 y 整体的值的,z 同理,只能同时处理一层
-
-
-
其他数据类型
-
字符串
-
既可以用数组的方式解构,也可以用对象的方式
-
const [a, b, , , c] = 'hello'; // a=h, b=e, c=o const {0:a, 1:b, length} = 'hello'; // a=h, b=e, length=5
-
-
数值和布尔
- 只能使用对象的解构赋值方式
- 先转换成对象再解构赋值,转成对象之后,空空如也,但是有继承的属性
-
undefined 和 null
- 不可以进行解构赋值,因为无法转成对象,解构会报错
-
对象字面量的增强
-
属性和方法的简介表示法
-
const age = 1; const person = { // age: age age }; const person = { // speak:function(){} speak(){} }
-
方括号语法
-
const prop = 'age'; const person = {}; person[prop] = 1; const prop = 'age'; const person = { [prop]: 1 }
-
值 或者可以通过计算得到值得表达式 都可以放在方括号中
-
点语法是方括号语法的子集
-
-
函数参数的默认值
-
默认值的生效条件和表达式 和上面类似,严格等于 undefined 才会生效,表达式惰性求值,默认值参数写在后面
-
应用
-
接收很多参数的时候,可能会因为参数太多,顺序不明确容易乱
-
优化上面的方式:接收一个对象作为参数
-
可以通过解构赋值再次优化上一条,解构赋值再添加默认值,再添加函数默认值,最终:
-
const logUser = ({username='zs', age=0, sex='male'}={}) => { ... console.log(username, age, sex); }; logUser({}); logUser(); logUser({username:'alex'});
-
第十一周
ES6——2
剩余参数
-
表现
-
const add = (x, y, z, ...args) => { console.log(x, y, z, args); } add(); // undefined undefined []
-
剩余参数永远是数组
-
-
注意事项
- 箭头函数的剩余参数
- 即使只有一个剩余参数,也不能省括号
- 使用剩余参数代替arguments 获取实际参数
- arguments 是类数组,而剩余参数就是数组,箭头函数没有arguments 对象;
- 剩余参数的位置
- 剩余参数只能放在最后一个参数,否则报错
- 箭头函数的剩余参数
-
应用
-
使用数组的方法运算
-
与解构赋值一起用
-
const [num, ...args] = [1, 2, 3, 4]; const fun = ([num, ...args]) => {}; fun([1, 2, 3, 4]);
-
const {x, y, ...z} = {a:1, b:2. x:3. y:4}; // 解构对象中的剩余参数,应该叫剩余元素,是对象,不是数组了。
-
-
展开运算符
-
数组
-
其实和剩余参数就是反过来的过程,一个是把参数列表转换成数组,一个是把数组转换成参数列表
-
应用
-
复制数组
-
合并数组
-
字符串转成数组
-
const arr = [...'alex'];
-
-
类数组转换成数组
- arguments
- NodeList
-
-
-
对象
-
对象必须在 { } 中展开,区别于数组,不能直接展开
-
console.log({...apple} === apple); // false
-
应用
- 复制对象
- 合并对象(后面相同属性覆盖前面)
-
注意事项
- 空对象的展开
- 就得到空对象
- 非对象的展开
- (排除字符串,字符串是类数组)对于基本数据类型,转成对象之后,对象中也没有什么属性,数据值就是初始值,这个不是属性,因此展开就是空对象
- undefined 和 null 也是一样,转成对象之后什么都没有
- 对象中对象属性的展开
- 只展开一层,可以嵌套
- 空对象的展开
-
其他应用
-
用户参数和默认参数
-
const logUser = userParam => { const defaultParam = { username: 'zs'; age: 0; sex: 'male'; }; const param = {...defaultParam, ...userParam}; console.log(param.age); }
-
-
-
Set
-
什么是set
- “集合”,不要用中文翻译去理解
- 数组,是一系列有序的数据集合
- Set,是一系列无序、没有重复值的集合
- 不能添加重复值,不能通过下标访问
-
方法和属性
-
add
- 一次只能添加一个元素,但是可以连缀的写
-
has
- 返回true /false
-
delete
- 注意这里也是方法,不是操作符,删除不存在成员,并不会报错
-
clear
- 清空
-
forEach——按照添加顺序遍历
-
s.forEach(function (value, key, set){ // set 中 value = key // 第三个参数就是遍历的对象本身 },this指向)
-
注意,这里的第二个参数 this 指向, 只有在第一个回调函数不是箭头函数的时候才会被改变,如果是箭头函数,则无法改变this 指向,改变了 this 不会影响回调函数中 v k s 的值
-
-
属性:size
- 类似数组的length ,但是只读
-
-
Set 构造函数的参数
- 数组 / 字符串、arguments、NodeList、Set实例 等
- 将set 实例放到构造函数的参数中,就相当于复制set
-
Set 注意事项
-
判断重复的方式
- 基本遵循严格相等(===),但是 Set 中NaN === NaN
-
什么时候使用
- 数组/字符串 去重
- 不需要通过下标访问数据,只需要遍历时
- 为了使用 set 的方法或属性时(delete)
-
应用
-
set 可以展开,数组 / 字符串 使用set 构造函数去重之后,可以使用展开再转换回来
-
[...new Set(arr)] [...new Set(str)].join('') // 回顾:join 中如果没有“”,转成的字符串会有逗号隔开;
-
存放DOM
-
-
Map
-
什么是 Map
- 认识Map
- “映射”
- Map 和对象都是键值对的集合
- Map 和对象的区别
- 对象一般用字符串当作键,不是字符串的东西用【】包裹的,也会被转成字符串
- 所有数据类型都可以作为 Map 的键
- 认识Map
-
Map 实例方法和属性
- set
- 添加成员,可以连缀写法
- 键名存在的,后面属性覆盖前面属性,和对象一样
- 注意,这里方法叫set 是因为,Map 对象既能添加又能 通过get 获取成员,而Set 只能添加,因此是add 方法
- get
- 获取成员,成员不存在,不会报错,返回 undefined
- has
- 返回布尔
- delete
- 这里也是方法,不是操作符,删除不存在成员,不会报错
- clear
- 清空成员
- forEach
- 与 Set 类似
- 属性:size
- 这一点比对象强,对象没有长度属性
- set
-
Map 构造函数参数
-
数组 / Set、Map实例
-
数组:
-
只能传递二维数组,且必须体现出键值对
-
const m = new Map([ ['name', 'alex'], ['age', 18] ]);
-
-
Set:
-
Set 也是类似数组,必须体现出键值对
-
const s = new Set([ ['name', 'alex'], ['age', 18] ]); const m = new Map(s);
-
-
Map 实例:
- 相当于复制了一个Map,新创建的和原来的不等
-
-
Map 注意事项
- 判断键名相同的方式
- 基本遵循严格相等(===),但是 Map 中NaN === NaN
- 什么时候使用 Map
- 如果只是需要 key value 结构,或者需要字符串以外的值作为键,使用Map 更合适
- 因为Map 比object 更方便遍历,使用forEach 就可以了,object 没有自身的遍历方法 ,需要使用 for in ,Map 的方法也比较好用
- 一般只有模拟现实世界的实体时,才使用对象
- 判断键名相同的方式
iterator
-
是什么
-
迭代器
-
在数组原型链上,找到了 Symbol( Symbol.iterator ) , 在 Symbol 对象上的一个属性,找到了iterator
-
Symbol对象,可以用来创建基本数据类型
-
const it = [1,2][Symbol.iterator](); // Array iterator {} console.log(it.next()); // {value: 1, done: false}
-
it 就是可迭代对象
-
-
解惑
- 为什么使用iterator
- 之前学的遍历方法:
- 数组:forEach
- 对象:for in
- Iterator 是一个统一的遍历方式
- 之前学的遍历方法:
- 更方便的使用
- Symbol.iterator -> it -> next()
- for of 就是封装好的上面的流程
- 展开运算符,解构赋值,也会涉及到
- 为什么使用iterator
-
for of
-
认识for of
-
const arr = [1,2,3]; const it = arr[Symbol.iterator](); while(!next.done){ next = it.next(); console.log(next.value); }
-
const arr = [1,2,3]; for(const item of arr){ console.log(item); }
-
for of 只会遍历出 done 为 false 的 value 值
-
-
用法
-
与break、continue一起用,这一点是 forEach 做不到的
-
const arr = [1,2,3]; for(const item of arr){ console.log(item); if(item === 2) break; }
-
取得索引
-
const arr = [1,2,3]; arr.keys();
-
取得值
-
const arr = [1,2,3]; arr.values();
-
同时获取
-
const arr = [1,2,3]; arr.entires(); for(let entires of arr.entires()){ console.log(entires); } for(let [index, value] of arr.entires()){ console.log(index, value); }
-
-
-
原生可遍历 与 非原生可遍历
-
只要有Symbol.iterator 方法,并且这个方法可以生成可遍历对象,就是可遍历的
-
原生可遍历
- 数组,字符串,set,map,arguments,NodeList
-
非原生遍历
-
一般的对象
- 自己建立迭代函数,可以自定义返回属性的顺序,主要就是添加[Symbol.iterator]() 方法,和迭代器一样,返回一个对象,包含next() 方法,next() 方法再返回包含value 和 done 属性的对象
-
有length 属性和索引作为属性名的对象
-
和上面一样自己写迭代函数
-
obj[Symbol.iterator] = Array.prototype[Symbol.iterator];
-
-
-
-
其他使用了iterator 的场合
- 数组的展开运算符
- 因为数组是可遍历的,因此可以按照顺序展开,底层用的就是迭代器,类似的字符串也是一样
- 注意:展开运算的结果并不是某种数据类型,不是某种数据结构,只是为了更灵活的操作,比如展开一些类数组,再放到【】中,就转成了真正的数组,或者合并/复制数组,这样的操作可以更简单的实现,这样一个操作符而已,结果不能进行赋值,可以打印
- 数组的解构赋值
- Set Map 可以通过展开运算符,转成数组之后解构赋值,这里指的是所有可遍历对象
- Set 和 Map 的构造函数
- Set 和Map 构造函数接收的数据,其实不只是数组,而是可遍历对象,Map 不只需要满足可遍历,还需要体现键值,因此使用二维数组
- 数组的展开运算符
es6 新增方法
-
字符串
-
includes()
-
console.log('abc'.includes('ac')); // false console.log('abc'.includes('a',2)); // false
-
const url = 'https://www.imooc.com/list'; const addURLParam = (url, name, value) => { url += url.includes('?') ? "&" : "?"; url += `${name}=${value}`; return url; } url = addURLParam(url, 'c', 'fe'); url = addURLParam(url, 'sort', 'pop'); console.log(url);
-
-
padStart() padEnd()
-
pad:填充;补全字符串
-
console.log('x'.padStart(4, 'ab')); // 'abax' console.log('xxx'.padStart(2, 'ab')); // 'xxx' console.log('x'.padStart(4)); // ' x'
-
只会补全不会删位,默认空格补全
-
应用
- 显示日期格式
- 1-9 号日期补上0 1号变成 01号
-
-
trimStart() trimEnd() / trimLeft() trimRight() / trim()
-
console.log(' a b c '.trimStart()); // 'a b c '
-
-
-
数组
-
includes()
-
console.log([1,2,3].includes('2')); // false
-
这里的判断也是和Set Map 类似,基本遵循严格相等,但是 NaN = NaN
-
第二个参数和字符串一样也是开始判断的位置,默认值是0
-
应用
-
数组去重
-
const arr = []; for(const item of [1,2,3,1]){ if(!arr.includes(item)){ arr.push(item); } }
-
-
-
Array.from()
-
将其他数据类型转成数组
- 哪些可以转:所有可遍历的数据结构
- 但是其实用这个方法转成数组还是有点麻烦,直接用展开更加方便
-
拥有length 的任意对象
- 会根据length 创建数组,并把所有属性名为数字的按顺序出现,其他字符串的属性名会直接忽视
-
第二个参数,相当于集成了map 函数,就是map 函数的功能
-
console.log(Array.from('12', value => value * 2)); // [2, 4] console.log(Array.from('12').map(value => value * 2)); // [2, 4]
-
第三个参数,改变 this 指向
- 注意,箭头函数在声明的时候就已经决定了this 指向,因此不能改变箭头函数的 this
-
-
find() findIndex()
-
都是找到一个就立即返回
-
[1, 5, 10, 15].find((value, index, arr) => { return value > 9; // 10 });
-
第二个参数,改变this 指向
-
-
-
对象
-
Object.assign()
-
合并对象,后面覆盖前面,与展开运算符不同的是,合并的结果对象就是第一个参数对象,返回合并后的参数
-
Object.assign(apple, pen) === apple; // true Object.assign({}, apple, pen);
-
assign(target, source) 目标对象,源对象
-
基本数据作为源对象
-
Object.assign({}, undefined); // {}
-
与展开类似,先转成对象再合并,特殊注意字符串,因为字符串是类数组对象
-
Object.assign({}, 'str'); // {0: 's', 1: 't', 2: 'r'} {...'str'}; // {0: 's', 1: 't', 2: 'r'}
-
-
-
Object.keys() Object.values() Object.entries()
- 就是用来获取键、值、整体,返回数组,二维数组
- 与数组的区别:
- 数组的这些方法得到的是迭代对象,对象的是直接得到数组
- 对象构造函数上的keys 不是es6 新方法,另外两个是,而数组的包括迭代器,都是es6 新的,因此它们没有很统一,数组的方法,返回迭代对象,对象的返回数组或二维数组
- 这三个方法和 for in 一样,并不能保证遍历的顺序,对象本身就是没有什么顺序的数据结构
-