JavaScript 中的数组

数组 API 汇总

数组分类 改变自身的方法 不改变自身的方法 遍历方法(不改变自身)
ES5 以前 pop,push,reverse,shift,splice,unshift concat,join,slice,toString,toLocateString,indexOf,lastIndexOf forEach,every,some,filter,map,reduce,reduceRight
ES6 及以后 copyWhithi,fill includes,toSource entries,find,findIndex,keys,values

Array 的构造器

js 复制代码
// 使用 Array 构造器,可以自定义长度
var a = Array(6); // [empty × 6]
// 使用对象字面量
var b = [];
b.length = 6; // [undefined × 6]

Array 构造器根据参数长度的不同,有如下两种不同的处理方式:

new Array(arg1, arg2,...),参数长度为 0 或长度大于等于 2 时,传入的参数将按照顺序依次成为新数组的第 0 至第 N 项(参数长度为 0 时,返回空数组);

new Array(len),当 len 不是数值时,处理同上,返回一个只包含 len 元素一项的数组;当 len 为数值时,len 最大不能超过 32 位无符号整型,即需要小于 2 的 32 次方(len 最大为 Math.pow(2,32)),否则将抛出 RangeError。

ES6 新增的构造方法:Array.of 和 Array.from

Array.of 用于将参数依次转化为数组中的一项,然后返回这个新数组,而不管这个参数是数字还是其他。它基本上与 Array 构造器功能一致,唯一的区别就在单个数字参数的处理上

比如,在下面的这几行代码中,你可以看到区别:当参数为两个时,返回的结果是一致的;当参数是一个时,Array.of 会把参数变成数组里的一项,而构造器则会生成长度和第一个参数相同的空数组。

js 复制代码
Array.of(8.0); // [8]
Array(8.0); // [empty × 8]
Array.of(8.0, 5); // [8, 5]
Array(8.0, 5); // [8, 5]
Array.of("8"); // ["8"]
Array("8"); // ["8"]

Array.from 的设计初衷是快速便捷地基于其他对象创建新数组,准确来说就是从一个类似数组的可迭代对象中创建一个新的数组实例。其实就是,只要一个对象有迭代器,Array.from 就能把它变成一个数组(注意:是返回新的数组,不改变原对象)

Array.from 拥有 3 个参数:

  • 类似数组的对象,必选;
  • 加工函数,新生成的数组会经过该函数的加工再返回;
  • this 作用域,表示加工函数执行时 this 的值。
js 复制代码
var obj = { 0: "a", 1: "b", 2: "c", length: 3 };
Array.from(
  obj,
  function(value, index) {
    console.log(value, index, this, arguments.length);
    return value.repeat(3); //必须指定返回值,否则返回 undefined 结果["aaa","bbb","ccc"]
  },
  obj
);

除了上述 obj 对象以外,拥有迭代器的对象还包括 String、Set、Map 等,Array.from 统统可以处理

tip es6 标准入门第三版:任何有 length 属性的对象都可以通过 Array.form 方法转为数组,而这种情况扩展运算符无法转换

js 复制代码
// String
Array.from("abc"); // ["a", "b", "c"]
// Set
Array.from(new Set(["abc", "def"])); // ["abc", "def"]
// Map
Array.from(
  new Map([
    [1, "ab"],
    [2, "de"],
  ])
);
// [[1, 'ab'], [2, 'de']]

Array 的判断

在 ES5 提供该方法之前,我们至少有如下 5 种方式去判断一个变量是否为数组

js 复制代码
var a = [];
// 1.基于instanceof
a instanceof Array;
// 2.基于constructor
a.constructor === Array;
// 3.基于Object.prototype.isPrototypeOf
Array.prototype.isPrototypeOf(a);
// 4.基于getPrototypeOf
Object.getPrototypeOf(a) === Array.prototype;
// 5.基于Object.prototype.toString
Object.prototype.toString.apply(a) === "[object Array]";

ES6 之后新增了一个 Array.isArray 方法,能直接判断数据类型是否为数组

一个 Array.isArray 的 polyfill

js 复制代码
if (!Array.isArray) {
  Array.isArray = function(arg) {
    return Object.prototype.toString.call(arg) === "[object Array]";
  };
}

改变自身的方法

基于 ES6,会改变自身值的方法一共有 9 个,分别为 pop、push、reverse、shift、sort、splice、unshift,以及两个 ES6 新增的方法 copyWithin 和 fill

js 复制代码
// pop方法
var array = ["cat", "dog", "cow", "chicken", "mouse"];
var item = array.pop();
console.log(array); // ["cat", "dog", "cow", "chicken"]
console.log(item); // mouse
// push方法
var array = ["football", "basketball", "badminton"];
var i = array.push("golfball");
console.log(array);
// ["football", "basketball", "badminton", "golfball"]
console.log(i); // 4
// reverse方法
var array = [1, 2, 3, 4, 5];
var array2 = array.reverse();
console.log(array); // [5,4,3,2,1]
console.log(array2 === array); // true
// shift方法
var array = [1, 2, 3, 4, 5];
var item = array.shift();
console.log(array); // [2,3,4,5]
console.log(item); // 1
// unshift方法
var array = ["red", "green", "blue"];
var length = array.unshift("yellow");
console.log(array); // ["yellow", "red", "green", "blue"]
console.log(length); // 4
// sort方法
var array = ["apple", "Boy", "Cat", "dog"];
var array2 = array.sort();
console.log(array); // ["Boy", "Cat", "apple", "dog"]
console.log(array2 == array); // true
// splice方法
var array = ["apple", "boy"];
var splices = array.splice(1, 1);
console.log(array); // ["apple"]
console.log(splices); // ["boy"]
// copyWithin方法
var array = [1, 2, 3, 4, 5];
var array2 = array.copyWithin(0, 3);
console.log(array === array2, array2); // true [4, 5, 3, 4, 5]
// fill方法
var array = [1, 2, 3, 4, 5];
var array2 = array.fill(10, 0, 3);
console.log(array === array2, array2);
// true [10, 10, 10, 4, 5], 可见数组区间[0,3]的元素全部替换为10

不改变自身的方法

基于 ES7,不会改变自身的方法也有 9 个,分别为 concat、join、slice、toString、toLocaleString、indexOf、lastIndexOf、未形成标准的 toSource,以及 ES7 新增的方法 includes

js 复制代码
// concat方法
var array = [1, 2, 3];
var array2 = array.concat(4, [5, 6], [7, 8, 9]);
console.log(array2); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(array); // [1, 2, 3], 可见原数组并未被修改
// join方法
var array = ["We", "are", "Chinese"];
console.log(array.join()); // "We,are,Chinese"
console.log(array.join("+")); // "We+are+Chinese"
// slice方法
var array = ["one", "two", "three", "four", "five"];
console.log(array.slice()); // ["one", "two", "three","four", "five"]
console.log(array.slice(2, 3)); // ["three"]
// toString方法
var array = ["Jan", "Feb", "Mar", "Apr"];
var str = array.toString();
console.log(str); // Jan,Feb,Mar,Apr
// tolocalString方法
var array = [{ name: "zz" }, 123, "abc", new Date()];
var str = array.toLocaleString();
console.log(str); // [object Object],123,abc,2016/1/5 下午1:06:23
// indexOf方法
var array = ["abc", "def", "ghi", "123"];
console.log(array.indexOf("def")); // 1
// includes方法
var array = [-0, 1, 2];
console.log(array.includes(+0)); // true
console.log(array.includes(1)); // true
var array = [NaN];
console.log(array.includes(NaN)); // true

其中 includes 方法需要注意的是,如果元素中有 0,那么在判断过程中不论是 +0 还是 -0 都会判断为 True,这里的 includes 忽略了 +0 和 -0。

slice 不改变自身,而 splice 会改变自身,slice 的语法是:arr.slice([start[, end]]),而 splice 的语法是:arr.splice(start,deleteCount[, item1[, item2[, ...]]])。我们可以看到从第二个参数开始,二者就已经有区别了,splice 第二个参数是删除的个数,而 slice 的第二个参数是 end 的坐标(可选)

数组遍历的方法

基于 ES6,不会改变自身的遍历方法一共有 12 个,分别为 forEach、every、some、filter、map、reduce、reduceRight,以及 ES6 新增的方法 entries、find、findIndex、keys、values。

js 复制代码
// forEach方法
var array = [1, 3, 5];
var obj = { name: "cc" };
var sReturn = array.forEach(function(value, index, array) {
  array[index] = value;
  console.log(this.name); // cc被打印了三次, this指向obj
}, obj);
console.log(array); // [1, 3, 5]
console.log(sReturn); // undefined, 可见返回值为undefined
// every方法
var o = { 0: 10, 1: 8, 2: 25, length: 3 };
var bool = Array.prototype.every.call(
  o,
  function(value, index, obj) {
    return value >= 8;
  },
  o
);
console.log(bool); // true
// some方法
var array = [18, 9, 10, 35, 80];
var isExist = array.some(function(value, index, array) {
  return value > 20;
});
console.log(isExist); // true
// map 方法
var array = [18, 9, 10, 35, 80];
array.map((item) => item + 1);
console.log(array); // [19, 10, 11, 36, 81]
// filter 方法
var array = [18, 9, 10, 35, 80];
var array2 = array.filter(function(value, index, array) {
  return value > 20;
});
console.log(array2); // [35, 80]
// reduce方法
var array = [1, 2, 3, 4];
var s = array.reduce(function(previousValue, value, index, array) {
  return previousValue * value;
}, 1);
console.log(s); // 24
// ES6写法更加简洁
array.reduce((p, v) => p * v); // 24
// reduceRight方法 (和reduce的区别就是从后往前累计)
var array = [1, 2, 3, 4];
array.reduceRight((p, v) => p * v); // 24
// entries方法
var array = ["a", "b", "c"];
var iterator = array.entries();
console.log(iterator.next().value); // [0, "a"]
console.log(iterator.next().value); // [1, "b"]
console.log(iterator.next().value); // [2, "c"]
console.log(iterator.next().value); // undefined, 迭代器处于数组末尾时, 再迭代就会返回undefined
// find & findIndex方法
var array = [1, 3, 5, 7, 8, 9, 10];
function f(value, index, array) {
  return value % 2 == 0; // 返回偶数
}
function f2(value, index, array) {
  return value > 20; // 返回大于20的数
}
console.log(array.find(f)); // 8
console.log(array.find(f2)); // undefined
console.log(array.findIndex(f)); // 4
console.log(array.findIndex(f2)); // -1
// keys方法
[...Array(10).keys()]; // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[...new Array(10).keys()]; // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
// values方法
var array = ["abc", "xyz"];
var iterator = array.values();
console.log(iterator.next().value); //abc
console.log(iterator.next().value); //xyz

有些遍历方法不会返回处理之后的数组,比如 forEach;有些方法会返回处理之后的数组,比如 filter

在 forEach 中用 return 不会返回,函数会继续执行

js 复制代码
let nums = [1, 2, 3];
nums.forEach((item, index) => {
  return; //无效
});

中断方法:

  • 使用 try 监视代码块,在需要中断的地方抛出异常。
  • 官方推荐方法(替换方法):用 every 和 some 替代 forEach 函数。every 在碰到 return false 的时候,中止循环。some 在碰到 return true 的时候,中止循环

reduce 方法也需要重点关注,其参数复杂且多,通常一些复杂的逻辑处理,其实使用 reduce 很容易就可以解决。我们重点看一下,reduce 到底能解决什么问题呢?先看下 reduce 的两个参数。

首先是 callback(一个在数组的每一项中调用的函数,接受四个参数):

  • previousValue(上一次调用回调函数时的返回值,或者初始值)
  • currentValue(当前正在处理的数组元素)
  • currentIndex(当前正在处理的数组元素下标)
  • array(调用 reduce() 方法的数组)

然后是 initialValue(可选的初始值,作为第一次调用回调函数时传给 previousValue 的值)

举个数组求和的

js 复制代码
// 第一种方法:
var arr = [1, 2, 3, 4];
var sum = 0;
arr.forEach(function(e) {
  sum += e;
}); // sum = 10
// 第二种方法
var arr = [1, 2, 3, 4];
var sum = 0;
arr.map(function(obj) {
  sum += obj;
});
// 第三种方法
var arr = [1, 2, 3, 4];
arr.reduce(function(pre, cur) {
  return pre + cur;
});

类数组

类数组有以下几种情况

  • 函数里面的参数对象 arguments;
  • 用 getElementsByTagName/ClassName/Name 获得的 HTMLCollection;
  • 用 querySelector 获得的 NodeList。

arguments 的对象只定义在函数体中,包括了函数的参数和其他属性

js 复制代码
function foo(name, age, sex) {
  console.log(arguments);
  // Arguments(3)
  // 0: "jack"
  // 1: "18"
  // 2: "male"
  // callee: ƒ foo(name, age, sex)
  // length: 3
  // Symbol(Symbol.iterator): ƒ values()
  // __proto__: Object
  console.log(typeof arguments); //object
  console.log(Object.prototype.toString.call(arguments)); //[object Arguments]
}
foo("jack", "18", "male");

typeof 这个 arguments 返回的是 object,通过 Object.prototype.toString.call 返回的结果是 '[object arguments]',可以看出来返回的不是 '[object array]',说明 arguments 和数组还是有区别的

js 复制代码
function foo(name, age, sex) {
  console.log(arguments.callee);
}
foo("jack", "18", "male");

输出的就是函数自身,如果在函数内部直接执行调用 callee 的话,那它就会不停地执行当前函数,直到执行到内存溢出

arguments.callee 从 ES5 严格模式中删除了,原因看这里

HTMLCollection 简单来说是 HTML DOM 对象的一个接口,这个接口包含了获取到的 DOM 元素集合,返回的类型是类数组对象,如果用 typeof 来判断的话,它返回的是 'object'。它是及时更新的,当文档中的 DOM 变化时,它也会随之变化

NodeList 对象是节点的集合,通常是由 querySlector 返回的。NodeList 不是一个数组,也是一种类数组。虽然 NodeList 不是一个数组,但是可以使用 for...of 来迭代。在一些情况下,NodeList 是一个实时集合,也就是说,如果文档中的节点树发生变化,NodeList 也会随之变化

类数组的应用场景

遍历参数操作:

在函数内部可以直接获取 arguments 这个类数组的值,那么也可以对于参数进行一些操作,比如将函数的参数默认进行求和操作

js 复制代码
function add() {
    var sum =0,
        len = arguments.length;
    for(var i = 0; i < len; i++){
        sum += arguments[i];
    }
    return sum;
}
add()                           // 0
add(1)                          // 1
add(1,2)                       // 3
add(1,2,3,4);                   // 10

定义链接字符串函数:

js 复制代码
function myConcat(separa) {
  var args = Array.prototype.slice.call(arguments, 1);
  return args.join(separa);
}
myConcat(", ", "red", "orange", "blue");
// "red, orange, blue"
myConcat("; ", "elephant", "lion", "snake");
// "elephant; lion; snake"
myConcat(". ", "one", "two", "three", "four", "five");
// "one. two. three. four. five"

这段代码说明了,你可以传递任意数量的参数到该函数,并使用每个参数作为列表中的项创建列表进行拼接。从这个例子中也可以看出,我们可以在日常编码中采用这样的代码抽象方式,把需要解决的这一类问题,都抽象成通用的方法,来提升代码的可复用性

传递参数使用:

js 复制代码
// 使用 apply 将 foo 的参数传递给 bar
function foo() {
  bar.apply(this, arguments);
}
function bar(a, b, c) {
  console.log(a, b, c);
}
foo(1, 2, 3); //1 2 3

通过在 foo 函数内部调用 apply 方法,用 foo 函数的参数传递给 bar 函数,这样就实现了借用参数的妙用

如何将类数组转换成数组

类数组借用数组方法转数组:

用 call 的方法来借用 Array 原型链上的 push 方法,可以实现一个类数组的 push 方法,给 arrayLike 添加新的元素

js 复制代码
var arrayLike = {
  0: "java",
  1: "script",
  length: 2,
};
Array.prototype.push.call(arrayLike, "jack", "lily");
console.log(typeof arrayLike); // 'object'
console.log(arrayLike);
// {0: "java", 1: "script", 2: "jack", 3: "lily", length: 4}

数组的 push 方法满足了我们想要实现添加元素的诉求。我们再来看下 arguments 如何转换成数组

js 复制代码
function sum(a, b) {
  let args = Array.prototype.slice.call(arguments);
  // let args = [].slice.call(arguments); // 这样写也是一样效果
  console.log(args.reduce((sum, cur) => sum + cur));
}
sum(1, 2); // 3
function sum(a, b) {
  let args = Array.prototype.concat.apply([], arguments);
  console.log(args.reduce((sum, cur) => sum + cur));
}
sum(1, 2); // 3

借用 Array 原型链上的各种方法,来实现 sum 函数的参数相加的效果。一开始都是将 arguments 通过借用数组的方法转换为真正的数组,最后都又通过数组的 reduce 方法实现了参数转化的真数组 args 的相加,最后返回预期的结果

利用 concat+apply

js 复制代码
function sum(a, b) {
  let args = Array.prototype.concat.apply([], arguments); //apply方法会把第二个参数展开
  console.log(args.reduce((sum, cur) => sum + cur)); //args可以调用数组原生的方法啦
}
sum(1, 2); //3

ES6 的方法转数组:

可以使用 ES6 新增的 Array.from 方法以及展开运算符

js 复制代码
function sum(a, b) {
  let args = Array.from(arguments);
  console.log(args.reduce((sum, cur) => sum + cur));
}
sum(1, 2); // 3
function sum(a, b) {
  let args = [...arguments];
  console.log(args.reduce((sum, cur) => sum + cur));
}
sum(1, 2); // 3
function sum(...args) {
  console.log(args.reduce((sum, cur) => sum + cur));
}
sum(1, 2); // 3
方法 数组 类数组
自带方法 多个方法
length 属性
callee 属性

实现数组扁平化

这里介绍六种扁平化的方式:

普通的递归实现

普通的递归思路很容易理解,就是通过循环递归的方式,一项一项地去遍历,如果每一项还是一个数组,那么就继续往下遍历,利用递归程序的方法,来实现数组的每一项的连接。

js 复制代码
var a = [1, [2, [3, 4, 5]]];
function flatten(arr) {
  let result = [];

  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      result = result.concat(flatten(arr[i]));
    } else {
      result.push(arr[i]);
    }
  }
  return result;
}
flatten(a); //  [1, 2, 3, 4,5]

核心就是循环遍历过程中的递归操作,就是在遍历过程中发现数组元素还是数组的时候进行递归操作,把数组的结果通过数组的 concat 方法拼接到最后要返回的 result 数组上,那么最后输出的结果就是扁平化后的数组

利用 reduce 函数迭代

从上面普通的递归函数中可以看出,其实就是对数组的每一项进行处理,那么我们其实也可以用 reduce 来实现数组的拼接,从而简化第一种方法的代码

js 复制代码
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
  return arr.reduce(function(prev, next) {
    return prev.concat(Array.isArray(next) ? flatten(next) : next);
  }, []);
}
console.log(flatten(arr)); //  [1, 2, 3, 4,5]

扩展运算符实现

这个方法的实现,采用了扩展运算符和 some 的方法,两者共同使用,达到数组扁平化的目的

js 复制代码
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
  while (arr.some((item) => Array.isArray(item))) {
    arr = [].concat(...arr);
  }
  return arr;
}
console.log(flatten(arr)); //  [1, 2, 3, 4,5]

先用数组的 some 方法把数组中仍然是组数的项过滤出来,然后执行 concat 操作,利用 ES6 的展开运算符,将其拼接到原数组中,最后返回原数组,达到了预期的效果

split 和 toString 共同处理

也可以通过 split 和 toString 两个方法,来共同实现数组扁平化,由于数组会默认带一个 toString 的方法,所以可以把数组直接转换成逗号分隔的字符串,然后再用 split 方法把字符串重新转换为数组

js 复制代码
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
  return arr.toString().split(",");
}
console.log(flatten(arr)); //  [1, 2, 3, 4,5]

通过这两个方法可以将多维数组直接转换成逗号连接的字符串,然后再重新分隔成数组

调用 ES6 中的 flat

还可以直接调用 ES6 中的 flat 方法,可以直接实现数组扁平化

js 复制代码
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
  return arr.flat(Infinity);
}
console.log(flatten(arr)); //  [1, 2, 3, 4,5]

arr.flat([depth])

其中 depth 是 flat 的参数,depth 是可以传递数组的展开深度(默认不填、数值是 1),即展开一层数组。那么如果多层的该怎么处理呢?参数也可以传进 Infinity,代表不论多少层都要展开

在编程过程中,发现对数组的嵌套层数不确定的时候,最好直接使用 Infinity,可以达到扁平化

正则和 JSON 方法共同处理

使用JSON.stringify 的方法先转换为字符串,然后通过正则表达式过滤掉字符串中的数组的方括号,最后再利用 JSON.parse 把它转换成数组

js 复制代码
let arr = [1, [2, [3, [4, 5]]], 6];
function flatten(arr) {
  let str = JSON.stringify(arr);
  str = str.replace(/(\[|\])/g, "");
  str = "[" + str + "]";
  return JSON.parse(str);
}
console.log(flatten(arr)); //  [1, 2, 3, 4,5]

关于排序

sort 方法是对数组元素进行排序,默认排序顺序是先将元素转换为字符串,然后再进行排序

当不传递参数时:

js 复制代码
const months = ["March", "Jan", "Feb", "Dec"];
months.sort();
console.log(months);
// ["Dec", "Feb", "Jan", "March"]
const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1);
// [1, 100000, 21, 30, 4]

当传递参数时:

js 复制代码
const array1 = [1, 30, 4, 21, 100000];
array1.sort((a, b) => b - a);
console.log(array1); // [100000, 30, 21, 4, 1]
const array1 = [1, 30, 4, 21, 100000];
array1.sort((a, b) => a - b);
console.log(array1); // [1, 4, 21, 30, 100000]

arr.sort([compareFunction])

其中 compareFunction 用来指定按某种顺序进行排列的函数,如果省略不写,元素按照转换为字符串的各个字符的 Unicode 位点进行排序

如果指明了 compareFunction 参数 ,那么数组会按照调用该函数的返回值排序,即 a 和 b 是两个将要被比较的元素:

  • 如果 compareFunction(a, b)小于 0,那么 a 会被排列到 b 之前;
  • 如果 compareFunction(a, b)等于 0,a 和 b 的相对位置不变;
  • 如果 compareFunction(a, b)大于 0,b 会被排列到 a 之前。

底层实现

sort 方法在 V8 内部相较于其他方法而言是一个比较难的算法,对于很多边界情况结合排序算法做了反复的优化

如果要排序的元素个数是 n 的时候,那么就会有以下几种情况:

  • n<=10 时,采用插入排序;
  • n>10 时,采用三路快速排序;
  • 10<n <=1000,采用中位数作为哨兵元素;
  • n>1000,每隔 200~215 个元素挑出一个元素,放到一个新数组中,然后对它排序,找到中间位置的数,以此作为中位数。

为什么元素个数少的时候要采用插入排序

虽然插入排序理论上是平均时间复杂度为 O(n^2) 的算法,快速排序是一个平均 O(nlogn) 级别的算法。但是别忘了,这只是理论上平均的时间复杂度估算,但是它们也有最好的时间复杂度情况,而插入排序在最好的情况下时间复杂度是 O(n)。

在实际情况中两者的算法复杂度前面都会有一个系数,当 n 足够小的时候,快速排序 nlogn 的优势会越来越小。倘若插入排序的 n 足够小,那么就会超过快排。而事实上正是如此,插入排序经过优化以后,对于小数据集的排序会有非常优越的性能,很多时候甚至会超过快排。因此,对于很小的数据量,应用插入排序是一个非常不错的选择。

为什么要花这么大的力气选择哨兵元素

因为快速排序的性能瓶颈在于递归的深度,最坏的情况是每次的哨兵都是最小元素或者最大元素,那么进行 partition(一边是小于哨兵的元素,另一边是大于哨兵的元素)时,就会有一边是空的。如果这么排下去,递归的层数就达到了 n , 而每一层的复杂度是 O(n),因此快排这时候会退化成 O(n^2) 级别。

这种情况是要尽力避免的,那么如何来避免?就是让哨兵元素尽可能地处于数组的中间位置,让最大或者最小的情况尽可能少。这时候,你就能理解 V8 里面所做的各种优化了

相关推荐
虾球xz2 分钟前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇8 分钟前
HTML常用表格与标签
前端·html
疯狂的沙粒11 分钟前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员27 分钟前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐29 分钟前
前端图像处理(一)
前端
程序猿阿伟36 分钟前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒38 分钟前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪1 小时前
AJAX的基本使用
前端·javascript·ajax
力透键背1 小时前
display: none和visibility: hidden的区别
开发语言·前端·javascript
程楠楠&M1 小时前
node.js第三方Express 框架
前端·javascript·node.js·express