是什么
数组每个值叫做一个元素,而每个元素在数组中有一个位置,以数字表示,称为索引。
- 数组是值的有序集合
- 固定长度
- 可以存放不同的数据结构
- 一段线性分配的内存.
目录
- 数组-类数组
- 数组-复制
- 数组-内置方法
- 数组-其他类型转换
1. 数组-类数组
- 是一个对象
- 拥有一个 length 属性
- 不具有数组的 push()、pop()、shift()、forEach() 等方法。
- 方便处理复杂的数据结构
var array = ['name', 'age', 'sex'];
var arrayLike = {
0: 'name',
1: 'age',
2: 'sex',
length: 3
}
转数组
Array.from() 可以将两类对象转为真正的数组:
- 类数组对象 (Arguments对象 和 NodeList对象)
- 可遍历(iterable)对象(包括ES6新增的数据结构 Set 和 Map)
Array.prototype.slice.call(arrayLike) // ["name", "age", "sex"]
Array.prototype.join.call(arrayLike,'&'); // name&age&sex
Array.prototype.splice.call(arrayLike, 0); // ["name", "age", "sex"]
Array.from(arrayLike); // ["name", "age", "sex"]
Array.prototype.concat.apply([], arrayLike) // ["name", "age", "sex"]
2. 数组-复制
var numbers = [1,2,3,'hello','javascript',33,'world', {"name":"wxh","age":33}];
// 复制数组
var _array = [];
// 方法一(浅拷贝)
// for (var i = 0; i < numbers.length; i++) {
// _array[i] = numbers[i]
// };
// 方法二(浅拷贝)
// _array = numbers.slice();
// 方法三(浅拷贝)
// _array = numbers.map((item) => item);
// 方法四(浅拷贝)
// _array = numbers.filter((item) => true);
// 方法五(浅拷贝)
// var _array = [...numbers];
// 方法六(浅拷贝)
// _array = numbers.reduce((prev,all)=> {
// prev.push(all);
// return prev;
// },[]);
// 方法七(浅拷贝)
// _array = Array.from(numbers);
// 方法八(浅拷贝)
// _array = numbers.concat([])
// 方法九(深拷贝)
_array = JSON.parse(JSON.stringify(numbers))
console.log(_array)
3. 数组-内置方法
slice
截取数组中的几个元素 组成新的数组
- slice(start,end)表示从下标start开始到下标end(不包括end)进行截取,得到的是一个新数组,不改变原数组。
- 当start为负值时表示从倒数第几个元素开始往后截取
- 不填end的话就表示从倒数第几个元素开始截取,一直截取到数组末尾元素。
// 简单复制,浅拷贝
var _array = [1,2,3,4,5]
var copyArray = _array.slice();
// 获取从 N 开始的子数组
// 希望弹出数组的第一个元素并使用它,返回剩余的数组,但希望在不修改原始数组的情况下执行此操作。
function useone (arr) {
const usedItem = arr[0]
return arr.slice(1)
}
// 获取从末尾 N 开始的子数组,负索引使删除任意数量的元素变得简单
const sliceArr = _array.slice(-3)
console.log('sliceArr ',sliceArr) //[3,4,5]
// 获取数组的前n个
const first4 = _array.slice(0, 4) // [1,2,3,4]
// 获取数组中某段子数组
function getSegement(arr, begin, length) {
return arr.slice(begin, begin + length);
}
console.log(getSegement(_array,1,3)) // [2,3,4]
// 类似数组的对象转换
Array.prototype.slice.call(arguments)
// 修改数组中的特定索引
// slice在函数上下文中一个强大而常见的用法是替换数组中特定项的值。从本质上讲,这很简单,只需要分配新值,但是在函数世界中,不能修改原始数组。相反,可以将slice与扩展运算符一起使用,以返回一个相同但对于要更新的索引的新数组:
function replaceIdx(arr,index,newVal) {
return [
...arr.slice(0,index),
newVal,
...arr.slice(index+1)
]
}
// 偏函数应用
var partial = function() {
const fn = arguments[0];
const args = Array.prototype.slice.call(arguments, 1);
// Return a function that calls fn
return function() {
var remainingArgs = Array.prototype.slice.call(arguments);
return fn.apply(this, args.concat(remainingArgs));
}
}
// 将任意长度多余的参数强制转换为数组
function myFunc(a, b) {
const extraArgs = Array.prototype.slice.call(arguments, 2);
}
myFunc(1, 2, 3, 4, 5, 6, 7, 8) // 得到a == 1,b === 2,extraArgs=== [3,4,5,6,7,8]
splice
splice()方法有三个参数,分别表示从哪个下标开始,删几个元素。可以实现增加,删除,替换数组元素的功能。arr.splice(-5,5)表示从倒数第五个元素开始,删五个元素。巧妙的是该方法的返回值是删除的元素集合。同时该方法改变了原数组。原数组变成了除了删除的元素剩下的元素集合。
var numbers = [1,2,3,'hello','javascript',33,'world', {"name":"wxh","age":33}];
// 复制数组
var _array = [];
console.log(numbers.splice(0,2,'a','b','c')) // [ 1, 2 ]
console.log(numbers) // [ 'a','b','c', 3,'hello','javascript',33,'world',{ name: 'wxh', age: 33 } ]
forEach
//标准
forEach(callback[,thisArg])
//简单示例
Array.forEach(function(item, index, array){
//回调函数内容
}, args);
// 扩展
if (!Array.prototype.forEach) {
Array.prototype.forEach = function (callback, thisArg) {
for (var i = 0; i < this.length; i++) {
//当thisArg为undefined时,JS引擎会将window作为其调用者
if (this[i])
callback.call(thisArg, this[i], i, this);
}
}
}
filter
3个参数同forEach,args也同forEach,唯一不同的是,函数有回调函数里有return返回值。
- 简单来说,该方法返回值是一个数组。
- 初始时,这个数组是空数组,该方法会通过回调函数遍历整个数组(指Array这个),
- 假如当前的元素返回值为true(或者可以隐式转换为true的,比如一个长度大于0的字符串),
- 那么会将当前元素添加到被返回的数组中。
例如:[1, 2, 3], 回调函数的return是item > 1, 当第一个元素1时,1>1为false,因此不会添加到返回的数组中, 而2和3 >1显然是true,因此会被添加到数组中。最终,返回值是[2,3]。
//标准
filter(callback[,thisArg])
//简单示例
Array.filter(function(item, index, array){
//回调函数内容
}, args);
// 扩展
if (!Array.prototype.filter) {
Array.prototype.filter = function (callback, thisArg) {
var temp = [];
for (var i = 0; i < this.length; i++) {
if (this[i]) {
if (callback.call(thisArg, this[i], i, this)) {
//如果callback返回true,则该元素符合过滤条件,将元素压入temp中
temp.push(this[i]);
}
}
}
return temp;
}
}
map
3个参数同forEach,args也同forEach,唯一不同的是,函数有回调函数里有return返回值。 简单来说,该方法的返回值也是一个数组(类filter);
- 和filter的区别在于,filter是将原数组元素,选择性加入到新数组中。
- map是将原数组的每个元素,进行处理后,放到新数组中。
例如:[1,2,3]作为原数组,map回调函数内的代码为: return item + 10; 那么就相当于将1+10放到数组中,然后将2+10放到数组中,再将3+10放到数组中。 结果为:[11, 12, 13] 当然,也可以写更复杂的逻辑,比如if(item>3)时+10,然后else if(item>2)时+5,否则else -10 那么结果就是[-9, 7, 13]
//标准
map(callback[,thisArg])
//简单示例
Array.map(function(item, index, array){
//回调函数内容
}, args);
// 扩展
if (!Array.prototype.map) {
Array.prototype.map = function (callback, thisArg) {
var temp = [];
for (var i = 0; i < this.length; i++) {
if (this[i]) {
var newItem = callback.call(thisArg, this[i], i, this);
temp[i] = newItem//将callback返回的新元素压入temp中
}
}
return temp;
}
}
reduce
首先看回调函数,他有四个参数, item是当前元素,别的地方写的是currentValue表示当前值,为了方便理解,我这里写item和上面统一风格 index是当前元素的索引; Array是整个数组(可以通过这个修改源数组); 上面3个都很好理解。
第一个参数previousValue是核心。他表示上一次执行回调函数时的返回值。 例如,有数组[1, 2, 3, 4] 当我遍历到第二个元素时,回调函数的previousValue的值是1,item的值为2, return我写为:return previousValue + item 那么当遍历到第三个元素时,回调函数的previousValue的值则为3(因为1+2),item的值为3 当遍历到第四个元素时,previous的值则为6(因为3+3), 最终reduce的返回值为10(因为6+4)
那么问题来了,为什么没提到遍历第一个元素? 原因是,当reduce没有第二个参数时,遍历从数组的第二个元素开始, 第一次执行回调函数的previousValue的值是数组第一个元素的值
当reduce存在第二个参数时(哪怕是null或者undefined),遍历都将从第一个元素开始; 第一次执行回调函数时(遍历第一个元素),previousValue的值是第二个参数的值,而item是第一个元素的值
所以在使用的时候需要注意,如果需要执行和数组元素个数一样次数的回调函数,那么必须设置reduce的第二个参数; 如果不设置,那么回到函数次数执行的次数,将比数组元素个数少1。
//标准
reduce(callback[,initialValue])
//简单示例
arr.reduce(function (previousValue, item, index, Array) {
return xxx; //xxx表示省略
});
// 扩展
if (!Array.prototype.reduce) {
Array.prototype.reduce = function (callback, initialValue) {
var previousValue = initialValue || this[0];//如果不指定intialValue,则默认为数组的第一个元素
//如果不指定initialValue(即第二个参数),i从1(第二个元素)开始遍历,否则就从0(第一个元素)开始遍历
for (var i = initialValue ? 0 : 1; i < this.length; i++) {
//previousValue 累加每一次返回的结果
if (this[i])
previousValue = callback(previousValue, this[i], i, this.toString());
}
return previousValue;
}
}
reduceRight
//标准
reduceRight(callback[,initialValue])
//简单示例
arr.reduceRight(function (previousValue, item, index, Array) {
return xxx; //xxx表示省略
});
// 扩展
if (!Array.prototype.reduceRight) {
Array.prototype.reduceRight = function (callback, initialValue) {
var previousValue = initialValue || this[this.length - 1];//如果不指定intialValue,则默认为数组的第一个元素
//如果不指定initialValue(即第二个参数),i从1(第二个元素)开始遍历,否则就从0(第一个元素)开始遍历
for (var i = (initialValue ? this.length - 1 : this.length - 2); i > -1; i--) {
//previousValue 累加每一次返回的结果
if (this[i])
previousValue = callback(previousValue, this[i], i, this);
}
return previousValue;
}
}
every
返回值是true或者false 初始情况下是true; 然后遍历数组,有一个不满足,则为false,并且终止遍历过程。 回调函数的this依然默认指向window,或者是every的第二个参数。
空数组的every返回结果是true。
//标准
every(callback, thisArg);
//简单示例
arr.every(function(item, index, array){
return item > xx;
});
if (!Array.prototype.every) {
Array.prototype.every = function (callback, thisArg) {
var result = true;
for (var i = 0; i < this.length; i++) {
if (this[i]) {
if (!callback.call(thisArg ? thisArg : window, this[i], i, this)) {
result = false;
break;
}
}
}
return result; //所有元素都符合条件,返回true
}
}
indexOf
用于查找第一个参数是否在数组中; 如果不在,返回-1; 如果在,返回在数组中遇见的第一个的下标; 例如:[1,2,3,2].indexOf(2)的返回值是1,虽然第二个和第四个元素都是,但是先遇见第二个,而第二个的下标是1
如果indexOf有第二个参数,那么从数组中第二个参数所指向的下标位置开始往后找; 例如:[1,2,3,2].indexOf(2,2)的返回值是3,因为开始下标是2(即第三个元素3),因此从第三个开始,遇见的第一个2的下标是2; 判断时含第二个参数所指向的数组元素
//标准
arr.indexOf(searchElement, fromIndex);
//简单示例
[1,2,3].indexOf(2); //1(数组的第二个元素)
[1,2,3].indexOf(4); //-1(未找到,注意,-1不是false,隐式转换后他的值为true)
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement, fromIndex) {
var result = -1;
for (var i = fromIndex ? fromIndex : 0; i < this.length; i++) {
if (this[i]) {
if (searchElement === this[i]) {
result = i;
break;
}
}
}
return result; //所有元素都符合条件,返回true
}
}
lastIndexOf
//标准
arr.lastIndexOf(searchElement, fromIndex);
//简单示例
[1,2,1].lastIndexOf(1); //2
[1,2,1].lastIndexOf(1, 1); //0
if (!Array.prototype.lastIndexOf) {
Array.prototype.lastIndexOf = function (searchElement, fromIndex) {
var result = -1;
for (var i = (fromIndex ? fromIndex : this.length - 1); i > -1; i--) {
if (this[i]) {
if (searchElement === this[i]) {
result = i;
break;
}
}
}
return result; //所有元素都符合条件,返回true
}
}
from
Array.from() 从类数组对象或者可迭代对象中创建一个新的数组实例。
console.log(Array.from([1,2,3],x=>x*x)); // 2,4,9
Array.isArray() 用来判断某个变量是否是一个数组对象。
console.log(Array.isArray(Array.from([1,2,3]))); // true
Array.of() 根据一组参数来创建新的数组实例,支持任意的参数数量和类型。
console.log(Array.of(1, 2, 3));// [1,2,3]
concat
连接两个或更多的数组,并返回结果
var arr = [ 1, 2, 3 ];
var arr2= arr.concat("4", "5", "6"); //["1", "2", "3", "4", "5", "6"];
join
把数组的所有元素放入一个字符串并通过指定的分隔符进行分隔
arr.join("+"); //"1+2+3";
reverse
反转数组中元素的顺序。
arr.reverse();
console.log(arr); // [3, 2, 1];
sort
数组排序 按照字符串的方式来排序。
toString
把数组转换为字符串,并返回结果
find
返回传入一个测试条件,符合条件的数组第一个元素,当数组中的元素在测试条件时返回true时, find() 返回符合条件的元素,之后的值不会再调用执行函数。如果没有符合条件的元素返回 undefined
const pets = [
{ type: 'Dog', name: 'Max'},
{ type: 'Cat', name: 'Karl'},
{ type: 'Dog', name: 'Tommy'},
];
var pet = pets.find(pet => pet.type ==='Dog' && pet.name === 'Tommy');
console.log(pet); // { type: 'Dog', name: 'Tommy' }
some
用于检测数组中的元素是否满足指定条件,如果有一个元素满足条件,则表达式返回true, 剩余的元素不会再执行检测,如果没有满足条件的元素,则返回false。
let arr = [1, 2, 3, 4, 5]
console.log(arr.some(item => item === 2)); // true
// ES5循环实现 some 方法
const selfSome = function (fn, context) {
let arr = Array.prototype.slice.call(this) // 复制数组原型对象
// 空数组直接返回 false,数组的 every 方法则相反返回 true
if(!arr.length) return false
for (let i = 0; i < arr.length; i++) {
if(!arr.hasOwnProperty(i)) continue;
let res = fn.call(context,arr[i],i,this)
if(res)return true
}
return false
}
// 挂载
Array.prototype.selfSome ||(Object.defineProperty(Array.prototype, 'selfSome', {
value: selfSome,
enumerable: false,
configurable: true,
writable: true
}))
console.log(arr.selfSome(item => item === 2)) // true
4. 数组-其他类型转换
数组与字符串
var arr = ['wxh','cjk','dbt','cjk']
console.log(arr.join(",")) // 以 逗号 进行分割
Array.from(new Set(arr)) // ['wxh','cjk','dbt'] // 数组去重
var str = "wxh,cjk,dbt"
console.log(str.split(","))
console.log(Array.from(str)) // ['w', 'x', 'h', ',',....]
数组与对象
let arrayLike = {
'0': 'wxh',
'1': 'cjk',
'2': 'dbt',
length: 3
};
// ES5 的写法
var arr1 = [].slice.call(arrayLike); // ['wxh', 'cjk', 'dbt']
// ES6 的写法
let arr2 = Array.from(arrayLike); // ['wxh', 'cjk', 'dbt']
// NodeList 对象
let arr3 = document.querySelectorAll('p');
Array.from(arr3).forEach(function (item) {
console.log(item);
});
// arguments 对象
function foo() {
var args = Array.from(arguments);
}
二维数组字符转换为数组
const arr =
"[['语文','89.5','80','20','45','100'],['数学','89.5','80','45','45','100'],['英语','89.5','80','38','45','100'],['总分','89.5','80','97','45','100'],] "
console.log(eval(scores))
5. 数组-最大值与最小值
- 排序
- 循环比较
- reduce
- apply
- 扩展运算符
排序
var arr = [6, 4, 1, 8, 2, 11, 23];
arr.sort(function(a,b){return a - b;});
console.log(arr[arr.length - 1])
循环比较
var arr = [6, 4, 1, 8, 2, 11, 23];
var result = arr[0];
for (var i = 1; i < arr.length; i++) {
result = Math.max(result, arr[i]);
}
console.log(result);
reduce
var arr = [6, 4, 1, 8, 2, 11, 23];
function max(prev, next) {
return Math.max(prev, next);
}
console.log(arr.reduce(max));
apply
var arr = [6, 4, 1, 8, 2, 11, 23];
console.log(Math.max.apply(null, arr))
扩展运算符
var arr = [6, 4, 1, 8, 2, 11, 23];
console.log(Math.max(...arr))
6. 数组去重复
双层循环去重
var array = [1, 1, '1', '1'];
function unique(array) {
// res用来存储结果
var res = [];
for (var i = 0, arrayLen = array.length; i < arrayLen; i++) {
for (var j = 0, resLen = res.length; j < resLen; j++ ) {
if (array[i] === res[j]) {
break;
}
}
// 如果array[i]是唯一的,那么执行完循环,j等于resLen
if (j === resLen) {
res.push(array[i])
}
}
return res;
}
console.log(unique(array)); // [1, "1"]
Object 键值对去重复
利用一个空的 Object 对象,我们把数组的值存成 Object 的 key 值,比如 Object[value1] = true,在判断另一个值的时候,如果 Object[value2]存在的话,就说明该值是重复的。
var array = [{value: 1}, {value: 1}, {value: 2}];
function unique(array) {
var obj = {};
return array.filter(function(item, index, array){
console.log(typeof item + JSON.stringify(item))
return obj.hasOwnProperty(typeof item + JSON.stringify(item)) ? false : (obj[typeof item + JSON.stringify(item)] = true)
})
}
console.log(unique(array)); // [{value: 1}, {value: 2}]
set 去重复
var array = [1, 2, 1, 1, '1'];
function unique(array) {
return Array.from(new Set(array));
}
console.log(unique(array)); // [1, 2, "1"]
function unique(array) {
return [...new Set(array)];
}
map 去重复
function unique (arr) {
const seen = new Map()
return arr.filter((a) => !seen.has(a) && seen.set(a, 1))
}
7. 数组-创建
[...Array(3).keys()] // [0, 1, 2]
// 数组操作
let arr = [1,2,3,4,5,2,3,4];
let str = "a1b2c3d4e5";
// filter : 不改变原数组, 返回删除后的结果
console.log(arr.filter((item) => item>2)) // 3,4,5,3,4
// 返回相等数据(要过滤掉的数据)
console.log(arr.filter((item) => item.text==text))
// 返回不相等数据(要保留的数据)
console.log(arr.filter((item) => item.text!=text))
// every : 检测数组中的数据是否都满足条件
console.log(arr.every((item) => item>2)) // false
// some: 检测数组中的数据是否有满足的,有就返回 true
console.log(arr.some((item) => item>2)) // true
// forEach: 可以改变数组,无返回值,返回数组的每一项
arr.forEach((item,index) => {
console.log(item,index)
});
// map: 不改变原数组,将原数组改变后,组成新数组返回
console.log(arr.map((item) => item * 2));
// 复制数组
console.log([...arr]);
// slice: 不改变原数组,截取数组中的几个元素 组成新的数组,不包括end
console.log('slice',arr.slice(0,2));
// splice: 改变了原数组,实现增加,删除,替换数组元素,表示从哪个下标开始,删几个元素,返回删除数组元素
console.log('splice',arr,arr.splice(0,2,'s','s'));
// substring: 截取字符串, 1开始, 截取到位置 2 ,并不包含位置
console.log(str,str.substring(0,2));
// substr: 截取字符串,0开始,截取2个
console.log(str,str.substr(0,2))
// 数组去重复
var uniqueFruits = Array.from(new Set(fruits));
[...new Set(fruits)]
对象转数组
var friends = [
{ name: ‘John’, age: 22 },
{ name: ‘Peter’, age: 23 },
{ name: ‘Mark’, age: 24 },
{ name: ‘Maria’, age: 22 },
{ name: ‘Monica’, age: 21 },
{ name: ‘Martha’, age: 19 },
]
var friendsNames = Array.from(friends, ({name}) => name);
console.log(friendsNames); // returns [“John”, “Peter”, “Mark”, “Maria”, “Monica”, “Martha”]
8. 数组转对象
var fruits = [“banana”, “apple”, “orange”, “watermelon”];
var fruitsObj = { …fruits };
console.log(fruitsObj); // returns {0: “banana”, 1: “apple”, 2: “orange”, 3: “watermelon”, 4: “apple”, 5: “orange”, 6: “grape”, 7: “apple”}
9. 数组操作
用数据填充数组
var newArray = new Array(10).fill(“1”);
console.log(newArray); // returns [“1”, “1”, “1”, “1”, “1”, “1”, “1”, “1”, “1”, “1”, “1”]
合并数组
var fruits = [“apple”, “banana”, “orange”];
var meat = [“poultry”, “beef”, “fish”];
var vegetables = [“potato”, “tomato”, “cucumber”];
var food = […fruits, …meat, …vegetables];
console.log(food); // [“apple”, “banana”, “orange”, “poultry”, “beef”, “fish”, “potato”, “tomato”, “cucumber”]
查找两个数组的交集
1. filter 函数
2. includes 函数
var numOne = [0, 2, 4, 6, 8, 8];
var numTwo = [1, 2, 3, 4, 5, 6];
var duplicatedValues = […new Set(numOne)].filter(item => numTwo.includes(item));
console.log(duplicatedValues); // returns [2, 4, 6]
从数组中删除假值
在 JavaScript 中,假值是 false, 0, "",null, NaN, undefined。
var mixedArr = [0, “blue”, “”, NaN, 9, true, undefined, “white”, false];
var trueArr = mixedArr.filter(Boolean);
console.log(trueArr); // returns [“blue”, 9, true, “white”]
数组混淆
// 随机更改数组元素顺序,混淆数组
(arr) => arr.slice().sort(() => Math.random() - 0.5)
获取URL的查询参数
function queryParam(){
let q={};
location.search.replace(/([^?&=]+)=([^&]+)/g,(_,k,v)=>q[k]=v);
return q;
}
生成随机ID
// 生成长度为11的随机字母数字字符串
Math.random().toString(36).substring(2);
Math.random().toString(36).substring(2);
// hg7znok52x
日历过去7天的数组
// 创建过去七天的数组
[...Array(7).keys()].map(days => new Date(Date.now() - 86400000 * days));
类数组对象转数组
// 类数组对象转数组:
var arr = [].slice.call(arguments)
获取调用函数名
function where() {
return where.caller.name;
}
function doWhere() {
var name = where();
console.info(name); // where
}
doWhere();
星级评分
function getRating(rating) {
if(rating > 5 || rating < 0) throw new Error('数字不在范围内');
return '★★★★★☆☆☆☆☆'.substring(5 - rating, 10 - rating );
}
console.log(getRating(3));
多行字符串格式化
var myString = (function () {/*
<div id="someId">
some content<br />
<a href="#someRef">someRefTxt</a>
</div>
*/}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1];
console.log(myString);
对象属性访问 a.b.c.d
// babel-node code1.js
// fun-1
let a = {
b: {
c: {
d: "hello-d"
}
}
}
let obj = a && a.b && a.b.c && a.b.c.d;
console.log("基本==>",obj);
// fun-2
let _ = require('lodash');
// import _ from 'lodash' // 引入 es6 语法
const r = _.get(a,'b.c.d');
console.log("lodash==>",r)
// fun-3
// let r = a?.b?.c?.d
// console.log(r)
// fun-4 循环
function get1 (obj,path) {
for(var i = 0; i < path.length; i++) {
if (obj !== null && obj !== undefined) {
obj = obj[path[i]]
} else {
break
}
}
return obj;
}
console.log("循环==>",get1(a,['b','c','d']))
// fun-5 递归
function get2 (obj,path) {
if(path.length) {
if(obj) {
var key = path.shift();
return get2(obj[key],path);
}else {
return obj;
}
}else {
return obj
}
}
console.log("递归==>",get2(a,['b','c','d']))
// fun-6 reduce
function get3(obj,path) {
return path.reduce(function(obj,curr) {
if(obj!=null && obj!=undefined) {
return obj[curr];
}else{
return obj
}
},obj);
}
console.log("reduce==>",get3(a,['b','c','d']))
数组-浅拷贝
1. 浅拷贝:浅拷贝只是复制了内存地址,如果原地址中的对象改变了,浅拷贝出来的对象也会相应改变。
2. 深拷贝:开辟了一块新的内存存放地址和地址指向的对象,原地址的任何对象改变了,深拷贝出来的对象不变。
// 方法一
var arr = ["foo","osr","weixin"];
function copy(arr) {
var temp = [];
for(var i = 0;i<arr.length;i++) {
temp.push(arr[i])
}
return temp;
}
var test = copy(arr)
console.log(test)
// 方法二
var concatTest = arr.concat();
// 方法三
var sliceTest = arr.slice();
console.log(sliceTest)
console.log(concatTest)
然而如果第一级数组元素是对象或数组,无法修改内部的数值,上面三种方式都失效
var arr = [
{number:1},
{number:2},
{number:3}
];
var concatTest = arr.concat();
concatTest[0].number = 10;
console.log(concatTest); [1,2,3]
对象-浅拷贝
var obj = {
name: "张三",
job: "学生"
}
// 方法一
function copyObj(obj) {
if (typeof obj !== 'object') {
return;
}
// 根据obj的类型判断是新建一个数组还是对象
var newObj = obj instanceof Array ? [] : {};
for(let item in obj) {
// 这一步做一个判定防止拷贝了原型链上的东西
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
var copyobj = copyObj(obj)
copyobj.name = "李四";
console.log(copyobj); // {name: '李四', job:: '学生'}
console.log(obj); // {name: '张三', job:: '学生'}
// 方法二
// ES6的Object.assign Object.assign:用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target),并返回合并后的target
// 用法: Object.assign(target, source1, source2); 所以 copyObj = Object.assign({}, obj); 这段代码将会把obj中的一级属性都拷贝到 {}中,然后将其返回赋给copyObj
var copyobj = Object.assign({},obj)
copyobj.name = '李四'
console.log(copyobj) // {name: '李四', job:: '学生'}
console.log(obj) // {name: '张三', job:: '学生'}
// 方法三
// ES6扩展运算符,扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。
var copyobj = {...obj}
copyobj.name = '李四'
console.log(copyobj)
console.log(obj)
对象-深拷贝
// 方法一
let deep_arr = JSON.parse(JSON.stringify(arr));
JSON.stringify()和JSON.parse() 复制对象
1. 它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。
2. 能正确处理的对象只有Number, String, Boolean, Array, 扁平对象。
// 方法二 递归实现
var deepClone = function(obj) {
if (typeof obj !== 'object') {
return;
}
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}
类数组
1. 不是函数
2. 有 length 属性
3. 且 length 属性值是不大于 Number.MAX_SAFE_INTEGER 的自然数
function isArrayLike(value) {
return value != null && typeof value !== 'function' &&
typeof (value.length) === 'number' && value > -1 && value % 1 == 0
}
给一个数组做去重处理
1. new Set()会将结果转换成对象 , Set()没法去重元素是引用对象的数组
let tempArr = new Set([1,2,3,3,4,4,5])
// => {1,2,3,4,5}
2. _.uniqWith()
import _ from 'lodash';
<script>
var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
_.uniqWith(objects, _.isEqual);
</script>
//=> [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
获取数组中的指定元素
// findIndex() 使用 findIndex()帮我们先获取到所需元素的索引值,拿到索引
let testArr = [{name:'鸣人',age:16},{name:'佐助',age:17},{name:'卡卡西',age:26}]
let index = testArr.findIndex(item => { return item.age > 16 });
// => 1 lodash
let testArr = [{name:'鸣人',age:16},{name:'佐助',age:17},{name:'卡卡西',age:26}]
let index = _.findIndex(testArr, {name:'佐助'});
// => 1
// 方法2: find
let testArr = [{name:'鸣人',age:16},{name:'佐助',age:17},{name:'卡卡西',age:27},{name:'佐助',age:17}]
let result = testArr.find(item => { return item.name == '佐助'});
// => { name:'佐助',age:17 }
用 Array.includes 替代 Array.indexOf
// Array新增的includes方法,它直接返回true或false表示数组是否包含元素。这样是不是直观多了?
'use strict';
const characters = [ '钢铁侠', '黑寡妇', '浩克', '美国队长', '浩克', '雷神'];
console.log(characters.indexOf('浩克'));// 2
console.log(characters.indexOf('蝙蝠侠'));// -1
console.log(characters.includes('浩克'));// true
console.log(characters.includes('蝙蝠侠'));// false
用 Array.find 替代 Array.filter
// 为了在对象数组中查找符合条件的对象,以前的做法是用filter筛选,它会返回符合条件的数组。但我们的目的是查找具体的单个对象,所以使用find更合适:
const characters = [
{ id: 1, name: '钢铁侠' },
{ id: 2, name: '黑寡妇' },
{ id: 3, name: '美国队长' },
{ id: 4, name: '美国队长' },
];
function getCharacter(name) {
return character => character.name === name;
}
console.log(characters.filter(getCharacter('美国队长')));
// [
// { id: 3, name: '美国队长' },
// { id: 4, name: '美国队长' },
// ]
console.log(characters.find(getCharacter('美国队长')));
// { id: 3, name: '美国队长' }
用 Array.some 替代 Array.find
// 有时候我们需要判断对象数组中符合条件的对象是否存在,虽然用find也可以达到目的,但还是不够直接,最好能直接返回true或false。Array.some就是干这个的。
'use strict';
const characters = [
{ id: 1, name: 'ironman', env: 'marvel' },
{ id: 2, name: 'black_widow', env: 'marvel' },
{ id: 3, name: 'wonder_woman', env: 'dc_comics' },
];
function hasCharacterFrom(env) {
return character => character.env === env;
}
console.log(characters.find(hasCharacterFrom('marvel')));
// { id: 1, name: 'ironman', env: 'marvel' }
console.log(characters.some(hasCharacterFrom('marvel')));
// true
用 Array.reduce 替代 Array.filter 和 Array.map
// Array.reduce这货看上去不那么好理解,但熟悉之后你会发现它非常好用。它实际上是一个叠加器,它遍历整个数组,把每个元素传入累加器函数执行一次,并把执行结果作为下一次迭代的输入参数。你可以在叠加器里做任何事,比如数字求和、数组和字符串拼接、对象属性操作等。
比如这样一个需求,在城市数组里筛选属于广东省的,然后给每个对象加上一个地区属性。以往的做法是先用filter筛选出结果数组,再用map构造新的对象数组。这样其实遍历了两次数组,性能不够好。使用Array.reduce可以实现一次遍历就完成了:
'use strict';
const cities= [
{ city: '广州市', province: '广东省' },
{ city: '深圳市', province: '广东省' },
{ city: '石家庄市', province: '河北省' },
];
console.log(
cities
.filter(city=> city.province=== '广东省')
.map(city=> Object.assign({}, city, { region: '华南区' }))
);
// [
// { city: '广州市', province: '广东省', region: '华南区' },
// { city: '深圳市', province: '广东省', region: '华南区' }
// ]
console.log(
cities
.reduce((acc, city) => {
return city.province=== '广东省'
? acc.concat(Object.assign({}, city, { region: '华南区' }))
: acc;
}, [])
)
// [
// { city: '广州市', province: '广东省', region: '华南区' },
// { city: '深圳市', province: '广东省', region: '华南区' }
// ]
前端小白,👋