文章目录
1. 工具函数
file对象转base64
//这个file参数 也就是文件信息,你使用html文件选择或者插件上传时 你就可以打印出文件信息看看
function getBase64(file){
return new Promise((resolve,reject)=>{
let reader = new FileReader();
let fileResult = "";
reader.readAsDataURL(file);
//开始转
reader.onload =function(){
fileResult = reader.result;
};
//转失败
reader.onerror =function(error){
reject(error)
};
//转结束咱就 resolve 出去
reader.onloadend =function(){
resolve(fileResult);
}
});
}
使用防抖(Debounce)
防抖是一种限制函数频繁执行的技巧,只有当一定时间内没有新的执行请求时,才会执行函数。在搜索请求的场景中,我们可以对用户的输入事件使用防抖,例如:
function debouncedSearch() {
clearTimeout(searchTimer);
searchTimer = setTimeout(() => {
// 发送搜索请求的逻辑
}, 300); // 假设我们设置300毫秒的延迟
}
const searchInput = document.getElementById('search-input');
searchInput.addEventListener('input', debouncedSearch);
// 防止处理多次点击
/**
*
*
* @param {*} methods
* @param {*} info
*/
function noMultipleClicks(methods, info) {
// methods是需要点击后需要执行的函数, info是点击需要传的参数
let that = this;
if (that.noClick) {
// 第一次点击
that.noClick = false;
if (info && info !== '') {
// info是执行函数需要传的参数
methods(info);
} else {
methods();
}
setTimeout(() => {
that.noClick = true;
}, 1500)
} else {
// 这里是重复点击的判断
alert("请勿重复点击!")
}
}
//导出
export default {
noMultipleClicks, //禁止多次点击
}
使用节流(Throttle)
节流与防抖类似,但节流会保证在一定时间内至少执行一次函数。这在需要保证一定频率执行函数的场景中很有用。例如,可以使用第三方库 lodash 的 throttle 函数来限制搜索请求:
const throttledSearch = _.throttle(() => {
// 发送搜索请求的逻辑
}, 300);
searchInput.addEventListener('input', throttledSearch);
2. 常见问题解决
管理请求并取消之前的请求
当你使用 fetch 或其他HTTP库发送请求时,你可以存储请求的引用,并在发送新请求前取消之前的请求。例如,使用 AbortController 来取消 fetch 请求:
let controller = new AbortController();
function fetchSearchResults() {
controller.abort(); // 取消之前的请求
controller = new AbortController();
fetch('/search', { signal: controller.signal })
.then(response => response.json())
.then(data => {
// 处理搜索结果
});
}
解决AbortController中断请求无法再次请求问题
- 因为我们点击取消请求后,AbortController中的aborted属性由false --> true,并始终保持为true,因此我们后面的请求也再也发不了了,且AbortController中的aborted属性为只读属性,我们没办法通过修改aborted来改变这种现状
解决方法如下:
AbortController中的aborted属性为只读属性,那我们只能换一种思路,既然改变不了AbortController中的aborted属性,那我们可以改变AbortController,只要AbortController刷新了,那么aborted也会变会变为初始状态,代码如下
<script>
const btn1 = document.getElementById('btn1')
const btn2 = document.getElementById('btn2')
let controller = ''
// 获取所有人信息
btn1.onclick = () => {
// 如果controller不为空,说明已经请求且创建过了,
// 因此我们只需把他置空重新创建,就可以得到新的controller
if(controller){
controller = null
}
controller = new AbortController()
axios({
url:'http://localhost:5000/test1',
params:{delay:3000},
signal:controller.signal
}).then(
response => console.log(response.data),
error => console.log(error)
)
}
// 点击取消请求
btn2.onclick = () => {
controller.abort('请求取消')
}
</script>
3.【经典再现】ES6数组操作这篇就够了
(一)数组的创建
- 使用
Array
构造函数的方式
new Array(); // 创建一个数组
new Array([size]); // 创建一个数组并指定长度,注意不是上限,是长度
new Array(element0, element1, ..., elementn); // 创建一个数组并赋值
const array = new Array();
array[0] = '1';
- 采用字面量的方法
const array = []; //创建一个空数组
const array2 = [1, 2, 3]; //创建一个有三个元素的数组
在使用数组字面量表示法时,不会调用Array
构造函数。
(二)数组自带属性
constructor // 返回创建数组对象的原型函数
length // 返回数组对象的长度
prototype // 可以增加数组的原型方法和属性
关于数组的**length**
属性
(1)关于数组的的length
属性,这个属性不是只读的,数组的该属性可读可写;通过设置这个属性,可以从数组的末尾移除项或向数组中添加新项。
// 将其 length 属性设置为 2 会移除最后一项结果再访问 colors[2]就会显示 undefined 了
var colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组
colors.length = 2;
alert(colors[2]); //undefined
(2)如果将其 length
属性设置为大于数组 项数的值,则新增的每一项都会取得undefined
值。
var colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组
colors.length = 4;
alert(colors[3]); //undefined
(3)利用 length
属性可以方便地在数组末尾添加新项。
var colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组
colors[colors.length] = "black"; //(在位置 3)添加一种颜色
colors[colors.length] = "brown"; //(在位置 4)再添加一种颜色
(三)检测是否为数组
- 使用
instanceof
方法
instanceof
用于判断一个变量是否是某个对象的实例
const array = new Array();
array instanceof Array; //true
- 使用
constructor
属性
constructor
属性返回对创建此对象的数组函数的引用,就是返回对象相对应的构造函数。
const array = new Array();
array.constructor === Array; // true
- 使用
isArray()
方法
对支持isArray
的浏览器,直接使用isArray
方法。
const array = new Array();
Array.isArray(array); //true
如果浏览器不支持Array.isArray()
则需进行必要判断。
/**
* 判断一个对象是否是数组,参数不是对象或者不是数组,返回false
*
* @param {Object} arg 需要测试是否为数组的对象
* @return {Boolean} 传入参数是数组返回true,否则返回false
*/
function isArray(arg) {
if (typeof arg === 'object') {
return Object.prototype.toString.call(arg) === '[object Array]';
}
return false;
}
(四)数组元素的增加与删除
array.push(e1, e2, ...eN)
将一个或多个元素添加到数组的末尾,并返回新数组的长度。
const array = [1, 2, 3];
const length = array.push(4, 5);
// array: [1, 2, 3, 4, 5]; length: 5
array.unshift(e1, e2, ...eN)
将一个或多个元素添加到数组的开头,并返回新数组的长度。
const array = [1, 2, 3];
const length = array.unshift(4, 5);
// array: [ 4, 5, 1, 2, 3]; length: 5
array.pop()
从数组中删除最后一个元素,并返回最后一个元素的值,原数组的最后一个元素被删除。数组为空时返回undefined
。
const array = [1, 2, 3];
const poped = array.pop();
// array: [1, 2]; poped: 3
array.shift()
删除数组的第一个元素,并返回第一个元素,原数组的第一个元素被删除。数组为空时返回undefined
。
const array = [1, 2, 3];
const shifted = array.shift();
// array: [2, 3]; shifted: 1
array.splice(start[, deleteCount, item1, item2, ...])
从数组中添加/删除元素,返回值是由被删除的元素组成的一个新的数组,如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。
start
指定修改的开始位置(从0计数)。如果超出了数组的长度,则从数组末尾开始添加内容;如果是负值,则表示从数组末位开始的第几位(从1计数)。deleteCount
(可选),从start
位置开始要删除的元素个数。如果deleteCount
是 0,则不移除元素。这种情况下,至少应添加一个新元素。如果deleteCount
大于start
之后的元素的总数,则从start
后面的元素都将被删除(含第start
位)。item1, item2, …
(可选),要添加进数组的元素,从start
位置开始。如果不指定,则splice()
将只删除数组元素。
const array = [1, 2, 3, 4, 5];
const deleted = array.splice(2, 0, 6); // 在索引为2的位置插入6
// array 变为 [1, 2, 6, 3, 4, 5]; deleted为[]
(五)数组与字符串的相互转化
- 数组转字符串
array.join(separator=',')
将数组中的元素通过separator
连接成字符串,并返回该字符串,separator默认为","。
const array = [1, 2, 3];
let str = array.join(',');
// str: "1,2,3"
toLocaleString()
、toString()
、valueOf()
:所有对象都具有这三个方法,数组继承的这个三个方法,可以看作是join()
的特殊用法,不常用。
var colors = ["red", "blue", "green"];
// 调用数组的 toString()方法会返回由数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串
console.log(colors.toString()); // red,blue,green
// 调用 valueOf()返回的还是数组
console.log(colors.valueOf()); // ["red", "blue", "green"]
console.log(colors.toLocaleString()); // red,blue,green
如果数组中的某一项的值是 null
或者 undefined
,那么该值在join()
、 toLocaleString()
、toString()
和 valueOf()
方法返回的结果中以空字符串表示。
- 字符串转数组
string.split(separator,howmany)
用于把一个字符串分割成字符串数组。separator
(必需),字符串或正则表达式,从该参数指定的地方对字符串进行分割。howmany
(可选),该参数可指定返回的数组的最大长度。
let str = "abc,abcd,aaa";
let array = str.split(",");// 在每个逗号(,)处进行分解。
// array: [abc,abcd,aaa]
const array1 = "helloworld";
let str1 = array1.split('');
//["h", "e", "l", "l", "o", "w", "o", "r", "l", "d"]
(六)数组的截取和合并
- 数组的截取 -
array.slice(start, end)
方法
slice()
通过索引位置,从数组中返回start
下标开始,直到end
下标结束(不包括)的新数组,该方法不会修改原数组,只是返回一个新的子数组。
start
(必填),设定新数组的起始位置(下标从0开始算起);如果是负数,则表示从数组尾部开始算起(-1 指最后一个元素,-2 指倒数第二个元素,以此类推)。end
(可选),设定新数组的结束位置;如果不填写该参数,默认到数组结尾;如果是负数,则表示从数组尾部开始算起(-1 指最后一个元素,-2
指倒数第二个元素,以此类推)。
// 获取仅包含最后一个元素的子数组
let arraay = [1,2,3,4,5];
array.slice(-1); // [5]
// 获取不包含最后一个元素的子数组
let arrayay2 = [1,2,3,4,5];
array2.slice(0, -1); // [1,2,3,4]
该方法并不会修改数组,而是返回一个子数组。如果想删除数组中的一段元素,应该使用方法 **array.splice()**
。
- 数组的合并 -
array.concat([item1[, item2[, . . . [,itemN]]]])
方法
conact()
是将多个数组(也可以是字符串,或者是数组和字符串的混合)连接为一个数组,返回连接好的新的数组。
constmergedArr ay rrayy = [1,2].concat(['a', 'b'], ['name']);
// [1, 2, "a", "b", "name"]
(七)数组元素的排序
array.sort()
方法
sort()
方法用于对数组的元素进行排序,并返回原数组。如果不带参数,按照字符串UniCode
码的顺序进行排序。
const array = ['a', 'd', 'c', 'b'];
array.sort(); //['a', 'b', 'c', 'd']
为sort()
中传入排序规则函数可实现自定义排序。
排序函数规则:(1)传两个形参;(2)当返回值为正数时,交换传入两形参在数组中位置。
按照数值大小进行排序-升序
[1, 8, 5].sort((a, b) => {
return a-b; // 从小到大排序
});
// [1, 5, 8]
按照数值大小进行排序-降序
[1, 8, 5].sort((a, b) => {
return b-a; // 从大到小排序
});
// [8, 5, 1]
array.reverse()
方法reverse()
方法将数组中元素的位置颠倒,第一个数组元素成为最后一个数组元素,最后一个数组元素成为第一个。在原数组上操作,然后返回原数组。
let arr = [1,2,3,4,5]
console.log(arr.reverse()) // [5,4,3,2,1]
console.log(arr) // [5,4,3,2,1]
数组的**sort()**
和**reverse()**
方法都对原数组进行了修改,返回值是经过排序之后的数组。
(八)元素在数组中的位置
indexOf()
与lastIndexOf()
indexOf(searchElement[, fromIndex = 0])
方法返回某个指定的字符串值在字符串中首次出现的位置。lastIndexOf(searchElement[, fromIndex = 0])
方法返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。- 这两个方法都接受两个参数:
searchElement
:要查找的元素;fromIndex
:开始查找的索引位置。- 这两个方法都返回查找的项在数组中的位置,或者在没找到的情况下返回-1。
[2, 9, 7, 8, 9].indexOf(9); // 1
[2, 9, 7, 8, 9].lastIndexOf(9); // 4
find()
与findIndex()
(1) find(callback[, thisArg])
方法,用于找出第一个符合条件的数组元素。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined
。
[1, 4, -5, 10].find((n) => n < 0)
// -5
find()
方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10
(2) findIndex(callback[, thisArg])
返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2
这两个方法都可以接受第二个参数,用来绑定回调函数的this
对象。
function f(v){
return v > this.age;
}
let person = {name: 'John', age: 20};
[10, 12, 26, 15].find(f, person); // 26
includes(searchElement[, fromIndex = 0])
方法返回一个布尔值,表示某个数组是否包含给定的值。
这个方法都接受两个参数:searchElement
:要查找的元素;fromIndex
:开始查找的索引位置。
[1, 2, 3].includes(2) // true
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
(九)数组的遍历与迭代
array.filter(callback, thisArg)
方法使用指定的函数测试所有元素,并创建一个包含所有通过测试的元素的新数组。
参数说明:
callback
用来测试数组的每个元素的函数,返回true
表示保留该元素(通过测试),false
则不保留。thisArg
可选。执行callback
时的用于this
的值。
// callback定义如下,三个参数: element:当前元素值;index:当前元素下标; array:当前数组
function callback(element, index, array) {
// callback函数必须返回true或者false,返回true保留该元素,false则不保留。
return true || false;
}
const filtered = [1, 2, 3].filter(element => element > 1);
// filtered: [2, 3];
array.every(callback[, thisArg])
方法检测数组中的每一个元素是否都通过了callback
测试,全部通过返回true
,否则返回false
。
// callback定义如下: element:当前元素值;index:当前元素下标; array:当前数组
function callback(element, index, array) {
// callback函数必须返回true或者false告知every是否通过测试
return true || false;
}
let a = [1, 2, 3, 4, 5];
let b = a.every((item) => {
return item > 0;
});
let c = a.every((item) => {
return item > 1;
});
console.log(b); // true
console.log(c); // false
array.some(callback[, thisArg])
判断数组中是否包含可以通过callback
测试的元素,与every
不同的是,这里只要某一个元素通过测试,即返回true
。callback
定义同上。
[2, 5, 8, 1, 4].some(item => item > 6);
// true
array.map(callback[, thisArg])
方法返回一个由原数组中的每个元素调用callback
函数后的返回值组成的新数组。
let a = [1, 2, 3, 4, 5];
let b = a.filter((item) => {
return item > 3;
});
console.log(b); // [4 ,5]
let bb = [];
a.map((item) => {
if (item > 3) {
bb.push(item);
}
});
console.log(bb); // [4, 5]
let bbb = a.map((item) => {
return item + 1;
});
console.log(bbb); // [2, 3, 4, 5, 6]
array.forEach(callbak)
为数组的每个元素执行对应的方法。
// callback定义如下: element:当前元素值;index:当前元素下标; array:当前数组
let a = [1, 2, 3, 4, 5];
let b = [];
a.forEach((item) => {
b.push(item + 1);
});
console.log(b); // [2,3,4,5,6]
- 遍历数组的方法:
entries()
、values()
、keys()
这三个方法都是返回一个遍历器对象,可用for...of
循环遍历,唯一区别:keys()
是对键名的遍历、values()
对键值的遍历、entries()
是对键值对的遍历。
for(let item of ['a','b'].keys()){
consloe.log(item);
//0
//1
}
for(let item of ['a','b'].values()){
consloe.log(item);
//'a'
//'b'
}
let arr4 = [0,1];
for(let item of arr4.entries()){
console.log(item);
// [0, 0]
// [1, 1]
}
for(let [index,item] of arr4.entries()){
console.log(index+':'+item);
//0:0
//1:1
}
array.reduce(callback[, initialValue])
方法返回针对数组每项调用callback
函数后产生的累积值。
const total = [0, 1, 2, 3].reduce((sum, value) => {
return sum + value;
}, 0);
// total is 6
const flattened = [[0, 1], [2, 3], [4, 5]].reduce((a, b) => {
return a.concat(b);
}, []);
// flattened is [0, 1, 2, 3, 4, 5]
参数说明:initialValue
:累加器初始值, callback
函数定义如下:
function callback(accumulator, currentValue, currentIndex, array) {
}
以上callback
的参数中accumulator
代表累加器的值,初始化时,如果initialValue
有值,则accumulator
初始化的值为initialValue
,整个循环从第一个元素开始;initialValue
无值,则accumulator
初始化的值为数组第一个元素的值,currentValue
为数组第二个元素的值,整个循环从第二个元素开始。initialValue
的数据类型可以是任意类型,不需要跟原数组内的元素值类型一致。
const newArray = [{ name: 'aa', age: 1 }, { name: 'bb', age: 2 }, { name: 'cc', age: 3 }].reduce((arr, element) => {
if (element.age >= 2) {
arr.push(element.name);
}
return arr;
// 必须有return,因为return的返回值会被赋给新的累加器,否则累加器的值会为undefined。
}, []);
// newArray is ["bb", "cc"];
// 上面代码的同等写法:
const newArray = [{ name: 'aa', age: 1 }, { name: 'bb', age: 2 }, { name: 'cc', age: 3 }].filter(element => element.age >= 2).map(item => item.name);
// newArray is ["bb", "cc"];
(十)其他方法
Array.from()
方法
Array.from()
方法是用于将类似数组的对象(即有length属性的对象)和可遍历对象转为真正的数组。
比如,使用·Array.from()·方法,可以轻松将·JSON·数组格式转为数组。
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
Array.of()
方法
Array.of()
方法是将一组值转变为数组。
let arr0 = Array.of(1,2,33,5);
console.log(arr0);//[1,2,33,5]
let arr1 = Array.of('你好','hello');
console.log(arr1);//["你好", "hello"]
(十一)扩展运算符
扩展运算符(spread
)是三个点(...
)。它好比rest
参数的逆运算,将一个数组转为用逗号分隔的参数序列。
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
该运算符主要用于函数调用。
function add(x, y) {
return x + y;
}
const numbers = [4, 38];
add(...numbers) // 42
注意,扩展运算符如果放在括号中,**JavaScript**
引擎就会认为这是函数调用,就会报错。
(...[1,2])
// Uncaught SyntaxError: Unexpected number
console.log((...[1,2]))
// Uncaught SyntaxError: Unexpected number
console.log(...[1, 2])
// 1,2
4. 在JavaScript中,多种方法合并数组。
下面是8种常用的方法,包括concat()、spread operator、push()、unshift()、splice()、Array.from()、Array.prototype.reduce()和ES6的Array.prototype.flat()。
- concat()方法:
使用场景:适用于合并两个或多个数组,并创建一个新数组。
优点:简单易用,不会修改原始数组。
缺点:每次调用concat()方法都会创建一个新数组,可能会影响性能。 - Spread Operator(展开运算符):
使用场景:适用于合并两个或多个数组,并创建一个新数组。
优点:简洁易懂,可以合并任意数量的数组。
缺点:如果要合并的数组数量很大,可能会导致栈溢出。 - push()方法:
使用场景:适用于将一个数组的元素添加到另一个数组的末尾。
优点:直接修改原始数组,不会创建新数组。
缺点:只能将数组添加到目标数组的末尾。 - unshift()方法:
使用场景:适用于将一个数组的元素添加到另一个数组的开头。
优点:直接修改原始数组,不会创建新数组。
缺点:只能将数组添加到目标数组的开头。 - splice()方法:
使用场景:适用于将一个数组的元素插入到另一个数组的指定位置。
优点:直接修改原始数组,可以在任意位置插入元素。
缺点:会修改原始数组,可能会导致其他代码出现错误。 - Array.from()方法:
使用场景:适用于将类似数组或可迭代对象转换为数组,并合并为一个新数组。
优点:可以处理各种类型的输入,灵活性高。
缺点:每次调用Array.from()都会创建一个新数组,可能会影响性能。 - Array.prototype.reduce()方法:
使用场景:适用于遍历数组并将其元素逐个合并为一个新数组。
优点:可以自定义合并逻辑,比较灵活。
缺点:需要编写reduce函数的回调函数,语法稍微复杂一些。 - ES6的Array.prototype.flat()方法:
使用场景:适用于将多维数组扁平化为一维数组,并合并其他数组。
优点:可以处理多维数组,简化了代码。
缺点:需要ES6支持,不适用于较旧的浏览器。
根据你的需求和个人偏好,选择合适的方法进行数组合并。如果性能是关键因素,可以考虑使用直接修改原始数组的方法(如push()、unshift()、splice()),如果需要更灵活的合并逻辑,可以考虑使用reduce()方法。展开运算符和concat()方法是常用且简单的合并数组的方式。
下面是代码示例
- concat()方法:
使用concat()方法将两个或多个数组合并为一个新数组。
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const mergedArray = array1.concat(array2);
console.log(mergedArray); // 输出 [1, 2, 3, 4, 5, 6]
- Spread Operator(展开运算符):
使用展开运算符将两个或多个数组合并为一个新数组。
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const mergedArray = [...array1, ...array2];
console.log(mergedArray); // 输出 [1, 2, 3, 4, 5, 6]
- push()方法:
使用push()方法将一个数组的元素添加到另一个数组的末尾。
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
array2.push(...array1);
console.log(array2); // 输出 [4, 5, 6, 1, 2, 3]
- unshift()方法:
使用unshift()方法将一个数组的元素添加到另一个数组的开头。
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
array2.unshift(...array1);
console.log(array2); // 输出 [1, 2, 3, 4, 5, 6]
- splice()方法:
使用splice()方法将一个数组的元素插入到另一个数组的指定位置。
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
array2.splice(1, 0, ...array1);
console.log(array2); // 输出 [4, 1, 2, 3, 5, 6]
- Array.from()方法:
使用Array.from()方法将类似数组或可迭代对象转换为数组,并合并为一个新数组。
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const mergedArray = Array.from(array1).concat(Array.from(array2));
console.log(mergedArray); // 输出 [1, 2, 3, 4, 5, 6]
- Array.prototype.reduce()方法:
使用reduce()方法遍历数组并将其元素逐个合并为一个新数组。
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const mergedArray = [array1, array2].reduce((acc, val) => acc.concat(val), []);
console.log(mergedArray); // 输出 [1, 2, 3, 4, 5, 6]
- ES6的Array.prototype.flat()方法:
使用flat()方法将多维数组扁平化为一维数组。
const array1 = [1, 2, [3, 4]];
const array2 = [5, 6];
const mergedArray = array1.flat().concat(array2);
console.log(mergedArray); // 输出 [1, 2, 3, 4, 5, 6]
原文链接:https://blog.csdn.net/ACCPluzhiqi/article/details/131702269
5. 在JavaScript中,多种方法合并对象。
1、使用 Object.assign() 方法:
它可以将一个或多个对象的属性复制到目标对象中。例如:
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const obj3 = Object.assign({}, obj1, obj2);
console.log(obj3); // { a: 1, b: 3, c: 4 }
这里我们使用空对象({})作为第一个参数,避免直接修改第一个对象。
2、使用解构赋值语法:
这种方法会在合并对象时保留键值相同的对象的属性,例如:
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const obj3 = { ...obj1, ...obj2 };
console.log(obj3); // { a: 1, b: 3, c: 4 }
这里使用了扩展运算符,可以将一个对象的属性解构到另一个对象中。
3、使用 Lodash 中的 merge() 方法:
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const obj3 = _.merge(obj1, obj2);
console.log(obj3); // { a: 1, b: 3, c: 4 }
4、for-in 循环 + 手动赋值:
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const obj3 = {};
for (const key in obj1) {
obj3[key] = obj1[key];
}
for (const key in obj2) {
obj3[key] = obj2[key];
}
console.log(obj3); // { a: 1, b: 3, c: 4 }
5、使用 Object.keys() 和 Array.forEach() 方法:
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const obj3 = {};
Object.keys(obj1).forEach(key => {
obj3[key] = obj1[key];
});
Object.keys(obj2).forEach(key => {
obj3[key] = obj2[key];
});
console.log(obj3); // { a: 1, b: 3, c: 4 }
最后需要提醒的是,在合并对象时如果键值相同的对象属性类型不同,例如一个为字符串类型,一个为数值类型,会覆盖之前的属性,因此需要根据项目需求做出相应的处理。
6、此外,如果需要对合并对象的属性进行特殊处理,例如合并对象的属性值是一个数组,需要合并成一个新数组,可以使用 Array.concat() 方法。
const obj1 = { a: [1, 2] };
const obj2 = { a: [3, 4] };
const obj3 = Object.assign({}, obj1, {
a: obj1.a.concat(obj2.a)
});
console.log(obj3); // { a: [1, 2, 3, 4] }
或者使用扩展运算符
const obj1 = { a: [1, 2] };
const obj2 = { a: [3, 4] };
const obj3 = {...obj1, a: [...obj1.a, ...obj2.a]}
console.log(obj3); // { a: [1, 2, 3, 4] }
如果需要对合并对象的属性值进行进一步的处理,如去重、排序等,可以使用 Array.filter()、Array.sort() 等方法。
6. ES6+ Set和Map
一、Set
1)Set是一种叫做集合的数据结构。集合是由一组无序且唯一的项组成的,即是一个没有重复元素也没有顺序概念的数组
2)Set本身是一个构造函数,用来生成Set数据结构
-
1、属性:
size:返回集合所包含元素的数量 -
2、操作方法:
- add(value):向集合添加一个新的项
- delete(value):从集合移除某个值
- has(value):判断集合是否存在某个值,返回true/false
- clear():移除集合里所有项
-
3、遍历方法:
- keys():返回一个包含集合中所有键的数组
- values():返回一个包含集合中所有值得数组
- entries():返回一个包含集合中所有键值对的数组
- forEach():用于对集合成员执行某种操作,没有返回值
-
4、注意点:
- 向Set加入值时,不会发生类型转换。Set内部判断两个值是否不同使用的算法类似于精确相等运算符===,唯一不同的是向Set多次添加NaN时,只会加入一个,而NaN!===NaN时返回的是false
- 向Set加入的值为对象类型时,不会对相同类型的值进行去重
- Set的遍历顺序就是插入顺序,可利用这个特性保存一个回调函数列表,调用时就能保证按照添加顺序调用
- Set结构没有键名,只有键值(或者说键名和键值是同一个值)所以keys()方法和values()方法的行为完全一致 set.keys()和set.values()
- 可以通过Array.from或者扩展运算符…将Set结构转为数组
示例代码:
//1. 创建集合方式1
let setData1 = new Set();
setData1.add("codeSE");
setData1.add(2213);
setData1.add(2213);//有则不添加
setData1.add(true);
setData1.add({a:'中国'});
//. 创建集合方式2
let setData2 = new Set(["回家",123,123,false,{b:true}])
console.log("==============================================Set========================================================")
console.log("setData1集合",setData1)
console.log("setData2集合",setData2)
console.log("------------------------------------------------------------------------------------------------------------")
console.log("setData2集合属性size():",setData2.size)
console.log("------------------------------------------------------------------------------------------------------------")
console.log("setData2集合操作add():",setData2.add(999))
console.log("setData2集合操作delete():",setData2.delete({b:true}))
console.log("setData2集合操作has():",setData2.has(999))
console.log("setData2集合操作clear():",setData2.clear())
console.log("setData2集合",setData2)
console.log("------------------------------------------------------------------------------------------------------------")
console.log("setData1集合遍历keys():" ,setData1.keys())
console.log("setData1集合遍历values():" ,setData1.values())
console.log("setData1集合遍历entries():" ,setData1.entries())
setData1.forEach((item,index)=>{
console.log("-->setData1集合遍历forEach():",item,index)
})
console.log("------------------------------------------------------------------------------------------------------------")
console.log("setData1集合使用Array.from转数组:" ,Array.from(setData1))
console.log("setData1集合使用扩展运算符转数组:" ,Array.from(setData1))
二、Map
Map数据结构类似于对象,也是键值对的集合,那么对象和Map有什么区别呢?
- 首先最明显得区别就是对象只能用字符串当做键,map的键是不限于字符串的,各种类型的值都可以当做键值
- Map中的键值是有序的,而添加到对象中的键则不是
- Map的键值对个数可以从size属性获取,而对象的键值对个数只能手动计算
- 对象都有自己的原型,原型链上的键名有可能和自己在对象上设置的键名产生冲突
- 当我们想创建一个Map时,可以通过
- 属性:
size:返回字典所包含的元素个数 - 操作方法:
- set(key,val):向字典中添加新元素
- get(key):通过键值查找特定的数值并返回
- has(key):判断键值是否存在字典中,返回true/false
- delete(key):通过键值从字典中移除对应的数据
- clear():将这个字典中的所有元素删除
- 遍历方法:
- keys():将字典中包含的所有键名以数组形式返回。
- values():将字典中包含的所有数值以数组形式返回。
- forEach():遍历字典的所有成员,可以接受两个参数,第二个参数用来绑定this
- entries():返回所有成员,效果和for(let [key,value] of map){}一致
- 注意点:
- Map的遍历顺序就是插入顺序
- Map的键是跟内存地址绑定的,只要内存地址不一样,就视为两个键。好处是扩展别人的库时,如果使用对象作为键名,就不用担心自己的属性与原作者的属性同名。
- 如果键名是一个简单类型的值,则只要两个值严格相等,则视为一个键。如-0和+0为一个键
- 但是两个NaN虽然不严格相等,还是会视为同一个键。
示例代码:
console.log("==============================================Map========================================================")
const mapData1 = new Map()
mapData1.set('foo',1)
mapData1.set('foo',1)
mapData1.set('isOk',true)
mapData1.set('name',"codeSE")
mapData1.set('obj',{a:12,b:"ABC"})
//或者
const mapData2= new Map([
['foo', 1],
['bar', 2]
]);
console.log("mapData1字典",mapData1)
console.log("mapData2字典",mapData2)
console.log("------------------------------------------------------------------------------------------------------------")
console.log("mapData1字典属性size():",mapData1.size)
console.log("------------------------------------------------------------------------------------------------------------")
console.log("mapData1字典操作set():",mapData1.set("j",999))
console.log("mapData1字典操作get():",mapData1.get("j"))
console.log("mapData1字典操作delete():",mapData1.delete("foo"))
console.log("mapData1字典操作has():",mapData1.has("obj"))
console.log("mapData1字典操作clear():",mapData2.clear())
console.log("------------------------------------------------------------------------------------------------------------")
console.log("mapData1字典",mapData1)
console.log("mapData2字典",mapData2)
console.log("------------------------------------------------------------------------------------------------------------")
console.log("mapData1字典遍历keys():" ,mapData1.keys())
console.log("mapData1字典遍历values():" ,mapData1.values())
console.log("mapData1字典遍历entries():" ,mapData1.entries())
mapData1.forEach((item,index)=>{
console.log("-->mapData1集合遍历forEach():",item,index)
})
效果:
三、应用场景
1)由于Set的值是唯一的,所以可以用来做数组的去重
2)当我们在业务开发中遇到需要通过多次数组循环
才能找到对应的值时,可以考虑将数据存储为Map结构
,这样可以方便我们根据key值
快速获取到对应的value值
。
四、简单了解WeakSet、WeakMap
- WeakSet:
- 成员都是对象
- 成员都是弱引用,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,可以用来保存DOM节点,不容易造成内存泄漏。
- 不能遍历,方法有add、delete、has
- WeakMap:
- 只接受对象作为键名(null除外),不接受其他类型的值作为键名
- 键名是弱引用,键值可以是任意的,键名所指向的对象不计入垃圾回收机制
- 不能遍历,方法有get 、set 、has、delete