当前位置:网站首页>Common skills of JS array

Common skills of JS array

2020-11-10 10:44:00 Ji Qingyun

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

版权声明
本文为[Ji Qingyun]所创,转载请带上原文链接,感谢