JS高级第五天

JS第五天

一、ES6相关概念

1、什么是ES6

ES 的全称是 ECMAScript ,从2015年6月开始每年都会更新一下,统称为ES6

2、使用ES6的目的

  • 变量提升特性增加了程序运行时的不可预测性
  • 语法过于松散,实现相同的功能,不同的人可能会写出不同的代码

二、ES6新增语法

1、let (★★★)

1.1 作用:

用来声明一个有块级作用域的变量,使用方法和 var 一样

1.2 let 定义变量的特点:

  1. 只在声明时的块或子块中可用

  2. 不存在变量提升,只能先声明再使用

  3. 存在“暂存死区”

  4. 同一作用域下不能重复声明同一变量

  5. 声明的变量不会挂载在 window 对象上

1.3 暂时性死区的本质

只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

1
2
3
4
5
6
var bar = 20;
if (true) {
//bar存在当前的块级作用域中,但无法提前访问
console.log(bar);//会报错
let bar = 10;
}

1.4经典面试题:

1
2
3
4
5
6
7
8
let arr = [];
for (let i = 0; i < 2; i++) {
arr[i] = function() {
console.log(i)
}
}
arr[0]();//0
arr[1]();//1

2、const关键字

2.1const 作用

用来声明一个有块级作用域的常量(内存地址不能变化的量)

2.2const 定义常量的特点

  1. 声明常量时必须要初始化值

  2. 同样具有块级作用域和“暂存死区”

  3. 赋值为简单数据类型时,不能直接修改值

  4. 赋值为复杂数据类型时,可以修改对象内部的属性和方法

1
2
3
4
5
6
const data = {
a: 1,
b: 2
};
data.a = 10 //这里可以通过,原因是data的内存地址值没有发生改变
// data = []; //报错,原因是data的地址值发生了改变

2.3、let、const、var 的区别

var&let&const区别

3、解构赋值

3.1解构赋值(强大)

可以从数组或对象中,把值取出来,再赋值给对应的变量

3.2对数组进行解构

let [a, b, …] = 数组

使用变量名和对应位置的数组元素一一匹配,匹配成功就把元素赋值给变量

  • 使用注意

    (1) 没有解构成功的变量,值为 undefined

    (2) 变量的位置和数组中值的位置一一对应

1
2
3
4
5
6
7
8
9
10
11
12
// 1. 没有解构成功的变量,值为 undefined
const arr2 = [4];
let [aa, bb] = arr2;
console.log(aa, bb); //4 undefined
// 2. 不需要解构的元素可以使用 逗号 隔开
let [, a1, b1] = arr;
console.log(a1, b1);
// 3. 交换两个变量
let num1 = 10;
let num2 = 20;
[num1, num2] = [num2, num1];
console.log(num1, num2); //20 10

3.3对对象进行解构

let {prop1, prop2, …} = 对象

使用变量名和对象中的属性名进行一一匹配,匹配成功就把对象的属性值赋值给变量

  • 使用注意

    (1) 没有解构成功的变量,值为 undefined

    (2) 变量的名称和属性名一一对应

    (3) 变量名的顺序和数量没有要求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let obj = {
name: '张三',
age: 18,
height: '175cm',
weight: '65kg'
}
// 没有解构成功的变量,值为 undefined
let {
sex
} = obj;
console.log(sex);//undefined
// 变量名的顺序和数量没有要求
// 属性只能解构一次,因为let声明变量不能重复
let {
weight,
name,
age
} = obj;
console.log(name, age, weight);
  • 解构后的变量起个别名 : 变量名

这里冒号左边的name只用来进行属性名匹配, 冒号右边才是真正赋值的变量

1
2
3
4
5
6
7
8
  let obj = {
name: '张三',
age: 18,
height: '175cm',
weight: '65kg'
}
let {name: name2,height: height1} = obj;
console.log(name2, height1);//张三 175cm
  • 从data中结构出来goods对象下的name值
1
2
3
4
5
6
7
8
9
10
let data = {
id: 1,
name: '家电',
goods: {
id: 3,
name: 'TV'
}
}
let { goods: {name,id}} = data;
console.log(name, id);

4、箭头函数

4.1结构(极其简洁)

() => {} ;

4.2 箭头函数的特点

  1. 一般不会单独使用, 可以当做匿名函数进行赋值 \ 传参 \ 返回值

  2. 如果函数体只有一行代码,并代码执行结果就是返回值, 可以同时省略大括号和 return

  3. 如果形参只有一个, 可以省略小括号

  4. 内部没有 arguments 这个内置对象

1
2
3
4
5
6
7
8
9
10
11
12
// 使用箭头函数遍历数组
var arr1 = [1, 2, 3, 4, 5]
// 如果形参只有一个, 可以省略小括号
arr1.forEach(item => console.log(item))
console.log('----------------------');
// 筛选出数组中所有的偶数
var arr1 = [1, 2, 3, 4, 5, 6, 7]
var newArr = arr1.filter(item => {
console.log(item);
return item % 2 != 0;
})
console.log(newArr);

4.3 箭头函数中this指向问题

(★★★) 箭头函数没有自己的 this, 它里面的 this 指向箭头函数所处位置的 this

1
2
3
4
5
6
7
8
9
10
11
const obj = {
name: '张三'
}
function fn() {
console.log(this) //{name:'张三'} this指向obj
return () => {
console.log(this) //{name:'张三'} this也指向obj
}
}
const resFn = fn.call(obj)
resFn()

(★★★)4.4this 情况讨论

  • (1) 非函数中的 this 指向 window

  • (2) es5 中函数的 this 指向函数的调用者

  • (3) call, apply, bind 这三种手动改变 this 的情况特殊对待, this 指向传递的第一个参数

  • (4) es6 中的箭头函数没有自己的 this, 指向所处位置的 this

5、剩余参数

5.1 剩余参数语法(…变量名)

允许我们将剩下的所有参数表示为一个数组

1
2
3
4
5
6
7
8
//用来计算多个数的和 (1, 2, 3, 4, 5)
const getSum = (...rest) => {
console.log(rest);//[1, 25, 25, 49]
let sum = 0;
rest.forEach(item => sum += item)
console.log(sum);
}
getSum(1, 25, 25, 49)//100

5.2剩余参数和解构配合使用

  • 把数组中剩下的元素组成新的数组
1
2
3
4
const arr = ['red', 'orange', 'yellow', 'green', 'black']
let [a, b, ...c] = arr;
console.log(a, b);//'red' 'orange'
console.log(c);//['yellow', 'green', 'black']
  • 把对象剩下的属性组成一个新对象

  • 使用剩余参数快速实现浅拷贝

1
2
3
4
5
6
7
8
9
10
11
const obj = {
name: '小明',
age: 12,
height: '170cm',
weight: '135kg',
}
let { ...obj2} = obj;
console.log(obj2);//{name: "小明", age: 12, height: "170cm", weight: "135kg"}

obj2.name = '小李';
console.log(obj2);//{name: "小李", age: 12, height: "170cm", weight: "135kg"}

三、ES6 的内置对象扩展

1、 拓展运算符(展开语法 或 spred运算符)

…对象名 或 …数组名

  • 作用:把数组或对象转为用逗号分隔的参数形式

  • 使用拓展运算符也可以快速完成浅拷贝

1
2
const arr2 = [...arr1];
console.log(arr2);

2、拓展运算符的应用

2.1用来合并数组

  • concat方法
  • push方法(直接将最后的合并结果赋值给前者)
  • 直接利用拓展运算符
1
2
3
4
5
6
7
8
9
10
11
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
//concat方法
const res1 = arr1.concat(arr2);
console.log(res1);
// push方法
// arr1.push(...arr2);
// console.log(arr1);
// 直接利用拓展运算符
const res2 = [...arr1, ...arr2]
console.log(res2);

2.2求数组中的最大值

1
2
3
const arr3 = [5, 4, 3, 2, 1]
const res3 = Math.max(...arr3);
console.log(res3);

2.3拓展对象

  • 拓展对象只能在{}中

  • 合并两个对象,如果有相同的属性,直接后者值覆盖前者

1
2
3
4
5
6
7
8
9
10
11
const obj = {
name: 'Jhon',
age: 18,
color: 'red'
}
const obj1 = {
weight: '120kg',
height: 180,
color: 'blue'
};
console.log({...obj, ...obj1 }); //{name: "Jhon", age: 18, color: "blue", weight: "120kg", height: 180}

2.4拓展字符串

1
2
const str = 'hello';
console.log(...str);//h e l l o

2.5使用拓展运算符拓展字符串和伪数组

结果:为数组,也可以使用forEach进行遍历

3、模板字符串

  • ES6新增的创建字符串的方式,使用反引号定义
  • 使用 ${变量名或表达式} 代替原来的 ‘引引加加’
  • 模板字符串支持换行
  • 在模板字符串中可以放任意的表达式 (如三元表达式, 函数调用, 逻辑运算符, +-*/…)
1
2
3
4
  const foo = () => 'abc';
let str3 = `hello${false?'abc':'ABC'}
${foo()}`;
console.log(str3);

4、构造函数方法Array.from()

  • 将伪数组或可遍历对象转换为真正的数组
1
2
3
4
5
6
7
const obj = {
0: 'a',
1: 'b',
length: 2
}
const arr = Array.from(obj);
console.log(arr);//["a", "b"]
  • (了解)第二个可选参数 fn 用于对转化后的数组进行遍历修改
1
2
3
4
5
const arr2 = Array.from(obj, function(item) {
console.log(item); //a b
return item + '1';
})
console.log(arr2); //["a1","b1"]

4.1.实例方法:find()

  • 用于查找数组中符合条件的第一个元素
  • 返回值: 找到就返回这个元素, 没有找到则返回 undefined
1
2
3
4
5
const arr = [5, 12, 8, 13, 44]
// 找出大于 10 的第一个元素
console.log(arr.indexOf(8)); //2 返回的是查找的索引号
const res = arr.find((item, index) => item > 10);
console.log(res);//12

4.2 findIndex() 方法

  • 用于查找数组中符合条件的第一个元素的索引
  • 返回值: 找到就返回当前元素的所以, 没有找到始终返回 -1
1
2
3
4
const arr = [5, 12, 8, 130, 44]
// 找元素中大于 10 的元素索引
const res = arr.findIndex((item, index) => item > 10);
console.log(res); //1

4.3includes(固定值) 方法

  • 判断数组是否包含给定的值
  • 返回值: 如果包含则返回 true,否则返回 false
1
2
3
4
const arr = [5, 12, 8, 130, 44]
// 判断数组中是否包含 44 这个元素
console.log(arr.includes(44)); //true
console.log(arr.indexOf(8) !== -1); //true

注意: 和其他查找方法的区别 ==> includes 只能接受一个固定值,不能接受一个函数

4.4map() 方法

  • 基于原数组去创建一个新数组,不影响原数组
  • 返回值: 新数组
1
2
3
4
const arr2 = [2, 4, 6, 8, 10];
const res = arr2.map(item => item / 2);
console.log(res);//[1, 2, 3, 4, 5]
console.log(arr2);//[2, 4, 6, 8, 10]不影响原数组

4.5 startsWith() 方法

判断字符串是否以某些字符开头,返回 Boolean

1
2
 const str = 'hello wrold';
console.log(str.startsWith('hello')); //true

4.6 endsWith() 方法:

判断字符串是否以某些字符结尾,返回 Boolean

1
2
 const str = 'hello wrold';
console.log(str.endsWith('ld'));

4.7 repeat(n) 方法

用于将某个字符串重复 n 次, 返回重复后的新字符串

1
2
3
let str = '123'
str = str.repeat(10);
console.log(str);

5、Set 数据结构(★★)

它类似于数组,但所有的元素都是唯一的,没有重复值

5.1 语法

new Set(数组)

1
2
3
const set = new Set([1, 2, 3, 4, 1, 2, 3, 4]);
console.log(set); //所有的元素都是唯一的,没有重复值
console.log(set.size);// 4

5.2 实例方法

  • add(value):添加某个值,返回 Set 结构本身
  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功
  • has(value):返回一个布尔值,表示该值是否为 Set 的成员
  • clear():清除所有成员,没有返回值
1
2
3
4
5
6
const s = new Set();
s.add(1).add(2).add(3); // 向 set 结构中添加值
s.delete(2) // 删除 set 结构中的2值
s.has(1) // 表示 set 结构中是否有1这个值 返回布尔值
s.clear() // 清除 set 结构中的所有值
//注意:删除的是元素的值,不是代表的索引
  • 案例:利用 set 数据类型的不重复性进行数组去重
1
2
3
4
const arr = [1, 2, 3, 4, 3, 2, 1];
// 将数组转化为set类型
const set2 = new Set(arr);
console.log([...set2]);

5.3总结: 数组去重的方法

​ (1) 建立一个新数组, 遍历数组, indexOf去判断元素是否存在

​ (2) filter(fn)

​ (3)原生for循环进行双重遍历,splice(i,1)

​ (4)[…new Set(arr)]

5.3 遍历

  • forEach() 方法遍历 set 数据中的每个元素
  • for…of 方法遍历任何可迭代的数据( Set, 数组, Map, 字符串)
1
2
3
4
5
6
7
8
9
 const mySet = new Set([2, 4, 5, 7]);

mySet.forEach(item => console.log(item));


for (let item of mySet) {
console.log(item);
}

注意: 对象不支持 for..of 方法

1
2
3
4
5
6
7
8
9
const obj = {
a: 1,
b: 2,
c: 3
}
for (let item of Object.keys(obj)) {
console.log(item);//a b c
console.log(obj[item]);//1 2 3
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!