【H2O2|全栈】JS进阶知识(六)ES6(2)
目录
前言
开篇语
本系列博客主要分享JavaScript的进阶语法知识,本期为第六期,依然围绕ES6的语法进行展开。
本期内容为:Set,Map,This指向和闭包。
与基础部分的语法相比,ES6的语法进行了一些更加严谨的约束和优化,因此,在之后使用原生JS时,我们应该尽量使用ES6的语法进行代码编写。
准备工作
软件:【参考版本】Visual Studio Code
插件(扩展包):Open in browser, Live Preview, Live Server, Tencent Cloud AI Code Assistant, htmltagwrap
提示:在不熟练的阶段建议关闭AI助手
浏览器版本:Chrome
系统版本: Win10/11/其他非Windows版本
Set和Map
基本概念
Set和Map是ES6新增的两种数据类型,它们本质上都是构造函数,使用new进行实例化。
Set中的数据项为单项,且可以实现自动去重。
Map中的数据项为键值对,可以利用键进行增删改查。
Set
相互转化
Set的构造器可以接收一个数组,即将数组转化成Set类型数据。
基本形式如下——
let set = new Set(arr);
在这个过程中,数组arr中的重复数据将被自动去除。
与之对应的,Set可以使用扩展运算符展开,并存入数组中。
基本形式如下——
let arr = [...set];
常见属性和API
属性/API | 作用 |
---|---|
size | 获取Set的大小 |
add() | 增加数据,可以链式操作 |
delete() | 删除数据,不可链式操作 |
clear() | 清空Set |
has() | 查询是否含有某个元素,返回true/false 只可以查单层,如果有多层数组转成的Set集合,则查询第一层 |
数组去重
在数组==>Set==>数组的过程中,可以实现数组的去重操作。
于是,可以得到数组去重的最简单的方式——
arr = [...new Set(arr)];
并集、交集和差集
利用Set集合和数组的API结合,可以求两个数组之间的集合关系。
比如有下面这两个数组——
let arr1 = [1, 2, 5, 8]
let arr2 = [2, 5, 9, 11]
现在要求它们的并集,可以先将两个数组拼接起来,然后转成Set集合去重,最后转回数组。
let arr3 = [...new Set([...arr1, ...arr2])]
如果需要求它们的交集,可以现将其中的一个数组转为Set集合,利用另一数组的filter方法过滤出包含对方的数据。
let arr4 = arr1.filter(item => new Set(arr2).has(item))
如果需要求它们的差集,则只需要从并集中过滤出不是交集的部分即可。
let arr5 = arr3.filter(item => !arr4.has(item))
Map
转化
Map中存储的是键值对数据,所以它的构造器需要接受一个二维数组,每个元素的第一位是键,第二位是值,类似下面的形式——
var arr = [["key1", "value1"], ["key2", "value2"], ["key3", "value3"]]
let map = new Map(arr)
常见的属性和API
属性/API | 作用 |
---|---|
size | 获取Map的大小 |
set(key, value) | 没有key,则设置key => value对 有key,则修改key对应的value |
delete() | 删除指定键值对 |
clear() | 清空Map() |
get() | 查询某个键对应的值 |
Set和Map的区别
①应用场景:Set用于数据重组,Map用于数据储存;
②Set:
(1)成员不能重复
(2)只有键值没有键名,类似数组
(3)可以遍历,方法有add, delete, has, clear
Map:
(1)本质上是健值对的集合,类似集合
(2)可以遍历,可以跟各种数据格式转换,方法有add, delete, set, has, clear
This的指向
function函数
命名函数,this指向window。
function fn() {
console.log(this);//window
}
匿名函数,this指向window。
let a = function () {
console.log(this);//window
};
立即调用函数,this指向window。
(function () {
console.log(this);//window
})();
事件函数,this指向事件源。
document.querySelector("#btn").onclick = function () {
console.log(this);//事件源(btn)
}
构造函数,this指向实例化对象。
function Per(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
this.fn = function () {
console.log(this);//实例化对象
}
}
对象中的函数,this指向调用者。
let obj = {
fn: function() {
console.log(this);//obj
}
}
箭头函数
箭头函数没有this指向,在箭头函数中的this指向为父级的this指向。
let obj = {
fn: () => {
console.log(this);//window
}
}
修改this
使用方式
目前,有三种修改this指向的方式——call(),apply(),bind()。
call()的使用方式如下——
方法名.call(修改后的指向,参数1,参数2,……)
call的参数为枚举类型。
apply()的使用方式如下——
方法名.apply(修改后的指向,[参数1,参数2,……])
apply的参数为数组类型。
bind()的使用方式如下——
方法名.bind(修改后的指向,参数1,参数2,……)
bind()的参数也是枚举类型。
三种方式的异同
三个的相同点:都用于修改this指向;
不同点:
1.调用方式不同:call和apply都是默认立即调用,bind返回函数体,需要手动调用(可以使用立即调用函数);
2.传参方式不同:call和bind都是枚举形式传参,apply为数组形式传参。
案例
更改this指向为obj
对于下面这段代码——
var x = 1, y = 2
var obj = {
x: 3,
y: 4
}
function fun() {
console.log(this.x, this.y);
}
上面的代码中,this的指向默认为window,所以这里输出的是window中的x和y的值。
如果想要输出obj中的x和y,可以使用下面的方式(示例)更改this指向——
fun.call(obj)
求数组数据最大值
Math对象的max()方法可以用来求输入参数中的最大值,如果我们想要让传入的参数为一个数组,则需要使用到apply()方法。
这里我们不需要改变this指向,依然设置原来的指向Math.max。
let maxNum = Math.max.apply(Math.max, [1, 2, 3])
闭包
概念
js方法的作用域是静态的,是定义函数的作用域,不是执行的作用域。
调用外部函数返回的内部函数后,即使外部函数已经执行完毕,被内部函数引用的外部函数的变量依然会保存在内存中,这些引用了其他函数作用域变量的函数(或变量)以及这些被引用变量的集合,就是闭包。
形式
闭包的一种示例形式如下,b就是一种闭包(保存了方法内部变量a的值)。
function fn() {
// 函数作用域
let a = 7
return a
}
// 执行作用域
let b = fn()
优缺点
优点:读取函数内部变量,使这些变量保存在内存中,不会在外部函数执行完毕后销毁。
缺点:内存消耗大,IE中会造成内存泄漏。
案例
事件绑定
还记得之前的经典案例li绑定点击事件吗,我们此前已经说过三种方式——
- 绑定index属性
- 使用let造成暂时性死区
- forEach自行遍历
提示:lis为原生DOM获取的所有li。
方式一:
for (var i = 0; i < lis.length; i++) {
lis[i].setAttribute("index", i)
lis[i].onclick = function () {
console.log(this.getAttribute("index"));
}
}
方式二:
for (let i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
console.log(i);
}
}
方式三:
lis.forEach(function (item, index) {
item.onclick = function () {
console.log(index);
}
})
现在,我们补充一种使用闭包绑定li点击事件的方式。
首先,设定一个方法用来绑定当前的点击事件,而该方法的参数为当前的索引。
let fn = function (index) {
lis[index].onclick = function () {
console.log(index);
}
}
由于index为方法内部的变量,所以我们可以使用一个外部变量来记住index。
而这个外部变量,其实也就是当前的索引值,我们只需要把当前索引值传入fn的形参列表即可。
而我们知道,在for-i遍历中,绑定事件之前的i是可以作为当前li的索引的。
所以,直接传入当前遍历变量i的值即可。
fn(i)
上述代码可以写成立即调用函数的形式,完整代码如下——
for (var i = 0; i < lis.length; i++) {
(function (index) {
lis[index].onclick = function () {
console.log(index);
}
})(i)
}
稍微复杂一些的情况
下面这个闭包的使用稍稍复杂一点,代码如下——
var name = "The Window";
var object = {
name: "MyObject",
getNameFunc() {
console.log(this.name, this); // 1
return function () {
console.log(this); // 2
return this.name;
};
}
};
object.getNameFunc();
object.getNameFunc()();
console.log(object.getNameFunc()());
现在,问最后三行代码会输出什么结果?
首先,看到第一行输出,调用了object对象的getNameFunc()方法,所以首先会输出语句1的内容,即MyObject object。
而方法的返回值为一个匿名方法,而该行输出中没有调用这个方法,所以该方法没有执行。
接下来,看到第二行输出,调用了object对象的getNameFunc()方法的返回值中的匿名方法。
当然,首先还是先输出和第一行中相同的输出,即MyObject object。
然后,立即调用匿名方法,输出语句2的内容,对于这个匿名方法,相当于一个闭包,记录了方法内部的返回值,实质上是在全局执行的,所以输出window。
同样的,匿名方法的返回值没有使用到,所以没有输出。
最后,看到第三行输出, log将最后匿名方法返回的值也输出出来了,而匿名方法是在全局执行的,所以此时的this.name为全局的name。
结束语
本期内容到此结束。关于本系列的其他博客,可以查看我的JS进阶专栏。
在全栈领域,博主也只不过是一个普通的萌新而已。本系列的博客主要是记录一下自己学习的一些经历,然后把自己领悟到的一些东西总结一下,分享给大家。
文章全篇的操作过程都是笔者亲自操作完成的,一些定义性的文字加入了笔者自己的很多理解在里面,所以仅供参考。如果有说的不对的地方,还请谅解。
==期待与你在下一期博客中再次相遇==
——临期的【H2O2】
原文地址:https://blog.csdn.net/ZC13786305863/article/details/143873734
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!