js Array common skills
Pseudo array to true array
Array of slice
Method can Array like objects
( such as document.getElementsByName('li')
) Become a real array .
Generally, we need to use the method of array to do down conversion .
var arr = Array.prototype.slice.call(arrayLike);
var arr = [].slice.call( arrayLike);
You can also use es6
Of Array.from
.
var arr = Array.from(arrayLike);
therefore ,Array.from
In fact, it can be implemented as simple as this :
Array.from = function(arr){
return Array.prototype.slice.call(arr);
}
But it's not that simple , such as Set
Data of type cannot be converted in this way . It needs more complicated processing .
Get the last element of the array
What most people do :
var arr = [123, 456, 789];
var len = arr.length;
var end = arr[len-1]
console.log('end:', end) // 'end:' 789
An optimization method :
var array = [1, 2, 3, 4, 5, 6];
console.log( array.slice(-1) ); // [6]
console.log( array.slice(-1)[0] ); // 6
console.log( array.slice(-2) ); // [5,6]
console.log( array.slice(-3) ); // [4,5,6]
You can encapsulate a function :
Array.prototype.last = function(){
return this.slice(-1)[0];
};
When the number of arrays is larger , The greater the difference in performance . Here's a test method
let arr1 = Array.from(new Array(100000000), (x, index)=>{
return Math.random();
});
// Time consuming 7.923ms
console.time('a');
console.log(arr1[arr1.length-1]);
console.timeEnd('a');
// Time consuming 0.075ms
console.time('b');
console.log(arr1.slice(-1)[0]);
console.timeEnd('b');
Truncated array
such as , When the array contains 10
Elements , And you just want to get the first 5
If you want to , You can truncate arrays , By setting array.length = 5
Make it smaller .
var array = [1, 2, 3, 4, 5, 6];
console.log( array.length ); // 6
array.length = 3;
console.log( array.length ); // 3
console.log( array ); // [1,2,3]
Merge array
Generally, if you combine two arrays , You usually use Array.concat()
.
var array1 = [1, 2, 3];
var array2 = [4, 5, 6];
console.log(array1.concat(array2)); // [1,2,3,4,5,6];
However , This function does not apply to merging large arrays , Because it needs to create a new array , And that consumes a lot of memory .
At this time , You can use Array.prototype.push.apply( arr1, arr2 )
Instead of creating a new array , It can merge the second array into the first , Thus less memory consumption :
var array1 = [1, 2, 3];
var array2 = [4, 5, 6];
Array.prototype.push.apply(array1, array2);
console.log(array1); // [1,2,3,4,5,6];
about es6
, You can use the extender :
var array1 = [1, 2, 3];
var array2 = [4, 5, 6];
array1.push(...array2);
console.log(array1); // [1,2,3,4,5,6];
Random ordering of arrays
Method 1 :
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function randSort1(arr){
for(var i = 0,len = arr.length;i < len; i++ ){
var rand = parseInt(Math.random()*len);
var temp = arr[rand];
arr[rand] = arr[i];
arr[i] = temp;
}
return arr;
}
console.log(randSort1(arr));
Method 2 :
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function randSort2(arr){
var mixedArray = [];
while(arr.length > 0){
var randomIndex = parseInt(Math.random()*arr.length);
mixedArray.push(arr[randomIndex]);
arr.splice(randomIndex, 1);
}
return mixedArray;
}
console.log(randSort2(arr));
Method 3 :
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr.sort(function () {
return Math.random() - 0.5;
});
console.log(arr);
Flattening arrays
To complete a flatten
Function of , Realization Beat flat
One Multidimensional arrays
by A one-dimensional
. Examples are as follows :
var testArr1 = [[0, 1], [2, 3], [4, 5]];
var testArr2 = [0, [1, [2, [3, [4, [5]]]]]];
flatten(testArr1) // [0, 1, 2, 3, 4, 5]
flatten(testArr2) // [0, 1, 2, 3, 4, 5]
solution 1
Let's start with the simplest solution :
flatten = (arr) => arr.toString().split(',').map((val) => parseInt(val));
It's using arrays toString
The particularity of , It's very clever to deal with .
solution 2
Another kind of :
flatten2 = function (arr) {
return arr.reduce(function (pre, val) {
if (!Array.isArray(val)) {
pre.push(val);
} else {
pre.push(...flatten2(val));
}
return pre;
}, []);
};
It can also be abbreviated as :
flatten2 = (arr) => arr.reduce((pre, val) => pre.concat(Array.isArray(val) ? flatten2(val) : val), []);
solution 3
Now? es6
There is already built-in flat
Method :
var testArr1 = [[0, 1], [2, 3], [4, 5]];
testArr1.flat() // [0, 1, 2, 3, 4, 5]
var testArr2 = [0, [1, [2, [3, [4, [5]]]]]];
testArr2.flat() // [0, 1, [2, [3, [4, [5]]]]]
We see ,testArr2
Only one level of Liberation . Why? ?
It turns out that this function has a default parameter depth
, We can call it depth , The default is 1
, When you don't pass parameters , Deal with only one layer .
If you want to spread it all out , Need to pass parameters Infinity
, Such as testArr1.flat(Infinity)
.
Here's my simple implementation .
Array.prototype.flat = function (depth = 1) {
var arr = [];
for (var i = 0; i < this.length; i++) {
if (Array.isArray(this[i]) && depth > 0) {
arr.push(...this[i].flat(depth-1));
} else {
arr.push(this[i]);
}
}
return arr;
};
includes And indexOf The difference between
Array has 2 A way to determine whether an element is included ,includes
And indexOf
, The latter has been around for a long time , The former is es6
Just added .
Many people think 2 The difference is that the former returns bool
, The latter returns the index number , It's more than that , The key point is to NaN
The judgment of the .
indexOf
I don't know NaN
Of . such as :
var arr = [1, 2, 3, NaN];
console.log(arr.includes(NaN)); // true
console.log(arr.indexOf(NaN)); // -1
therefore , We want to achieve includes
When , It needs to be like this :
Array.prototype.includes = function (item) {
for (var i = 0; i < this.length; i++) {
// if (this[i] === item || (this[i] !== this[i] && item !== item)) {
if (this[i] === item || (isNaN(this[i]) && isNaN(item))) {
return true;
}
}
return false;
};
among , The line I commented out , Namely isNaN
An implementation of , It is js
The only one is not equal to itself .
Implementation of array loop method
Most methods of arrays can use native for
Cycle to achieve , And the loop traversal method of array , It's almost the same , There are 2 Parameters , The first is callback
function , The second is to change the front callback
Scoped .
Through the implementation of these functions , Can better understand and remember how to use .
forEach
With the simplest forEach
For example , That's how it works :
Array.prototype.forEach = function (callback, scope) {
for (var i = 0; i < this.length; i++) {
callback.call(scope, this[i], i, this);
}
}
map
map
And forEach
The difference is that there is only a return value :
Array.prototype.map = function (callback, scope) {
var arr = [];
for (var i = 0; i < this.length; i++) {
arr.push(callback.call(scope, this[i], i, this));
}
return arr;
};
some
some
When the conditions are satisfied , Just go back to true
, Return when none is satisfied false
Array.prototype.some = function (callback, scope) {
for (var i = 0; i < this.length; i++) {
if(callback.call(scope, this[i], i, this)){
return true;
}
}
return false;
};
every
every
And some
Just the opposite , When one of the conditions is not met , Just go back to false
, Return only when you are satisfied true
Array.prototype.every = function (callback, scope) {
for (var i = 0; i < this.length; i++) {
if(!callback.call(scope, this[i], i, this)){
return false;
}
}
return true;
};
find
find
It's finding the right elements :
Array.prototype.find = function (callback, scope) {
for (var i = 0; i < this.length; i++) {
if(callback.call(scope, this[i], i, this)){
return this[i];
}
}
};
findIndex
findIndex
It's the index to find the elements that match the criteria :
Array.prototype.findIndex = function (callback, scope) {
for (var i = 0; i < this.length; i++) {
if(callback.call(scope, this[i], i, this)){
return i;
}
}
return -1;
};
reduce Usage of
Array of reduce
The method is special , Its parameters are not like other loop traversal methods , It's a little different .
The usage is like this :
var arr = [1, 2, 3, 4];
var callbackfn = function (pre, cur, index, arr) {
console.log(pre, cur, index);
return pre + cur;
};
var res = arr.reduce(callbackfn);
console.log(res); // 10
var res2 = arr.reduce(callbackfn, 5);
console.log(res2); // 15
In its callback function , The first 1 Parameters are the last time callback
The results of the implementation of .
The first time , If you don't pass on the first 2 Parameters , At this point, it uses the first element of the array , It will also traverse from the second element .
It will return the last execution result .
The common use scenario is to do accumulation .
There is also such a situation , First filter the condition , Reuse map
Returns a new array .
var res3 = arr.filter(item => item > 2).map(i => i * 2);
console.log(res3);
There is a drawback to this , Will be carried out in 2 Secondary cycle . The best is to use native for
To deal with , You can also use it reduce
.
var res4 = arr.reduce(function (pre, cur) {
if (cur > 2) {
pre.push(cur * 2);
}
return pre;
}, []);
console.log(res4);
We can do this :
Array.prototype.reduce = function (callbackfn, preItem) {
var i = 0;
if (preItem === undefined) { // If there is no pre pass value , The default is the first element , From 2 Elements start traversing
preItem = this[0];
i++;
}
for (var len = this.length; i < len; i++) {
preItem = callbackfn(preItem, this[i], i, this);
}
return preItem;
};
join
join
Is to merge arrays into strings .
Array.prototype.join = function (sep = ',') {
var str = '';
for (var i = 0; i < this.length; i++) {
str += this[i] + (i === this.length - 1 ? '' : sep);
}
return str;
};
Multi-storey for How to jump out of the peripheral loop when looping
As an interview question, ask the interviewer , Few people can answer . Maybe it's the reason why there are fewer and fewer usage scenarios now .
In a function ,return
Keywords can naturally jump out of the loop , But to continue with the following logic , Just use break
.
For nested loops , Just put a label on the outside of the loop that needs to be interrupted ( Any string will do ), You can continue to use break
Keyword to break the loop .
a: for(var i = 0; i < 10; i++){
for(var j = 10; j < 100; j++){
if(j == 10){
break a;
}
}
}
More updates will be available in here