原生JS:Array对象详解

Posted SuriFuture的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原生JS:Array对象详解相关的知识,希望对你有一定的参考价值。

Array对象

创建数组:

  • 数组字面量:var arr1 = [1,2,3];
  • Array构造函数1:var arr2 = new Array(1,2,3);  //[1,2,3]
  • Array构造函数2:var arr3 = new Array(3);  var arr3 = new Array(‘3’);  var arr3 = new Array(‘ol‘);  
  • 错误写法:var arr3 = new Array(3.2);  var arr3 = new Array(-3);  
  • 例:var arr5 = new Array(50) 返回的数组arr5的成员都是空位,虽然读取的时候返回undefined,但实际上该位置没有任何值,虽然可以取到length属性,但是取不到键名( 0 in arr5; //false )

向 Array 构造函数传入一个在 0 到 232-1 之间的整数,将返回一个以此为长度的数组对象。通过 length 属性可以访问这个值。如果传入的唯一参数不是字符串且不是有效的整数数值,则抛出 RangeError 异常。

Array作为构造函数,行为很不一致。因此,不建议使用它生成新数组,直接使用数组字面量是更好的做法。

数组的长度及其中元素的类型都是不固定的。因为数组的长度可读可写,有时数组中的元素也不是在连续的位置,所以javascript 数组不一定是密集的。通常情况下,这是一些方便的特性;如果这些特性不适用于你的特定使用场景,你可以考虑使用固定类型数组

 JavaScript 中访问合法的属性名可以用"."或者"[ ]",但是访问非法的属性x只能用"[ ‘x‘ ]"。比如说,如果你有一个名为 ‘3d’ 的属性,它只能通过方括号的形式进行访问[‘3d‘]。 

当你在 array 上使用一个合法的数组下标,而且该下标超出了当前数组的大小的时候,引擎会根据其值自动增大 length,而减小 array 的length属性会删掉超出的元素。 

Array的属性

Array.length

Array 构造函数的 length 属性,其值为1。

Array.prototype

 允许为所有数组对象附加属性。

Array.prototype[@@unscopables] 只有Firefox支持

Symbol属性 @@unscopable 包含了所有 ES2015 (ES6) 中新定义的且并未被更早的 ECMAScript 标准收纳的属性名。这些属性并不包含在 with 语句绑定的环境中

语法:arr[Symbol.unscopables]

 

Array的静态方法

Array.isArray(obj)  IE9

假如一个变量obj是数组则返回true,否则返回false。下面是通用方法:

var isArray = function(a) {
   return Array.isArray ? Array.isArray(a) : Object.prototype.toString.call(a) === ‘[object Array]‘;
};

Array.from( arrayLike[, mapFn[, thisArg]] ) ES6

将一个类数组对象或可遍历对象转换成真正的数组,返回数组的的实例。在 ES6 中, Class 语法允许我们为内置类型(比如 Array)和自定义类新建子类(比如叫 SubArray)。这些子类也会继承父类的静态方法,比如 SubArray.from(),调用该方法后会返回子类 SubArray 的一个实例,而不是 Array 的实例。

  • arrayLike想要转换成真实数组的类数组对象或可遍历对象。
  • mapFn可选参数,如果指定了该参数,则最后生成的数组会经过该函数的加工处理后再返回。
  • thisArg可选参数,执行 mapFn 函数时 this 的值。

Array.of()  ES6

将它的任意类型的多个参数放在一个数组里并返回该数组。

Polyfill 如果原生不支持的话,在其他代码之前执行以下代码会创建 Array.of() 。

if (!Array.of) {

  Array.of = function() {

    return Array.prototype.slice.call(arguments);

  };

}

Array的实例属性:

Array.prototype.constructor

所有的数组实例都继承了这个属性,它的值就是 Array,表明了所有的数组都是由 Array 构造出来的。

Array.prototype.length

 

Array的实例方法:

 

下面的这些方法会改变调用它们的对象自身的值:

Array.prototype.pop()

删除数组的最后一个元素,并返回这个元素。

 

Array.prototype.push(element1, ..., elementN)

在数组的末尾增加一个或多个元素,并返回数组的新长度length。

  • push 方法有意具有通用性。该方法和 call() 或 apply() 一起使用时,可应用在数组和类似数组的对象上。push 方法根据 length 属性来决定从哪里开始插入给定的值。如果 length 不能被转成一个数值,则插入的元素索引为 0,包括 length 不存在时。当 length 不存在时,将会创建它。
  • 注意:唯一的原生类数组对象是String,它并不适用该方法,因为字符串是不可改变的。
  • 合并两个数组a和b,可以用concat方法,也可以用a.push.apply(a,b);
  • push和pop结合使用,就构成了“后进先出”的栈结构(stack)
  • push和shift结合使用,就构成了“先进先出”的队列结构(queue)

 

Array.prototype.reverse()

颠倒数组中元素的排列顺序,即原先的第一个变为最后一个,原先的最后一个变为第一个。

 

Array.prototype.shift()

移除索引为 0 的元素(即第一个元素),并返回被移除的元素,其他元素的索引值随之减 1。如果 length 属性的值为 0 (长度为 0),则返回 undefined

shift 方法并不局限于数组:该方法亦可通过 call 或 apply 作用于对象上。对于不包含 length 属性的对象,将添加一个值为 0 的 length 属性。

 

Array.prototype.unshift(element1, ..., elementN)

在数组的开头增加一个或多个元素,并返回数组的新的 length 值。

  • unshift 方法会在调用它的类数组(array-like)对象的开始位置插入给定的参数。
  • unshift 特意被设计成具有通用性;这个方法能够通过 call 或 apply 方法作用于类似数组的对象上。不过对于没有 length 属性(代表从0开始的一系列连续的数字属性的最后一个)的对象,调用该方法可能没有任何意义

Array.prototype.sort([compareFunction])

对数组的元素做原地的排序,并返回这个数组。 sort 可能不是稳定的。默认按照字符串的Unicode码位点(code point)排序。

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

  • 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
  • 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。备注: ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本);
  • 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。
  • compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。

Array.prototype.splice(start, deleteCount[, item1[, item2[, ...]]])

在任意的位置start给数组添加、删除、替换任意个元素。总是返回(由被删除的元素组成的)一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。如果只提供第一个参数,等同于将原数组在指定位置拆分成两个数组。如果只要插入元素,可将第二个参数设为0

  • start 从数组的哪一位开始修改内容。如果超出了数组的长度,则从数组末尾开始添加内容;如果是负值,则表示从数组末位开始的第几位。
  • deleteCount 整数,表示要移除的数组元素的个数。如果 deleteCount 是 0,则不移除元素。这种情况下,至少应添加一个新元素。如果 deleteCount 大于start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。
  • itemN 要添加进数组的元素。如果不指定,则 splice() 只删除数组元素。

Array.prototype.copyWithin()  ES6

在数组内部,将一段元素序列拷贝到另一段元素序列上,覆盖原有的值。

Array.prototype.fill()   ES6

将数组中指定区间的所有元素的值,都替换成某个固定的值。

 

下面的这些方法绝对不会改变调用它们的对象自身的值,只会返回一个新的数组或者返回一个其它的期望值

 

Array.prototype.concat() 

将传入的数组或非数组值与原数组合并,组成一个新的数组并返回,它们是按照顺序放入这个新数组的

var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])

concat 方法并不修改调用它的对象(this 指向的对象) 和参数中的各个数组本身的值,而是将他们的每个元素拷贝一份放在组合成的新数组中,原数组中的元素有两种被拷贝的方式:

  • 对象引用(非对象直接量):concat 方法会复制对象引用放到组合的新数组里,原数组和新数组中的对象引用都指向同一个实际的对象,所以,当实际的对象被修改时,两个数组也同时会被修改.
  • 字符串和数字(是原始值,而不是包装原始值的 String 和 Number 对象): concat 方法会复制字符串和数字的值放到新数组里.

 

Array.prototype.join() 

将数组中所有的数组元素转换成字符串,再用一个分隔符将这些字符串连接起来。如果元素是undefined 或者null, 则会转化成空字符串。

var str = arr.join( [separator = ‘,‘] );

参数separator 可选,用于指定连接每个数组元素的分隔符。分隔符会被转成字符串类型;如果省略的话,默认为一个逗号。如果 seprator 是一个空字符串,那么数组中的所有元素将被直接连接。

 

Array.prototype.slice( [begin[,end]] )

浅复制(shallow copy)数组的一段到一个新的数组中,并返回这个新数组。范围:从begin到end(不含end)

  • 可选参数begin 从该索引处开始复制(省略则为默认为0),若为负数,表示从数组的倒数位置开始(最后一个是-1)
  • 可选参数end  指定结束复制位置的索引,省略则表示提取从begin开始到末尾。
  • 若元素为对象引用(非对象直接量):会复制对象引用放到新数组里,原数组和新数组中的对象引用都指向同一个实际的对象,所以,当实际的对象被修改时,两个数组也同时会被修改.
  • 若元素为字符串和数字(是原始值,而不是包装原始值的 String 和 Number 对象): 会复制字符串和数字的值放到新数组里.
  • slice 方法可以用来将一个类数组(Array-like)对象/集合转换成一个数组。Array.prototype.slice.call(arguments) 或 [].slice.call(arguments)

Array.prototype.toString()

Array 对象覆盖了 Object.prototype.toString() 方法。对于数组对象,toString 方法返回一个字符串,该字符串由数组中的每个元素的 toString() 返回值经调用 join() 方法连接(由逗号隔开)组成。当一个数组被作为文本值或者进行字符串连接操作时,将会自动调用其 toString 方法。

 

Array.prototype.toLocaleString()

返回一个由所有数组元素组合而成的本地化后的字符串。遮蔽了原型链上的 Object.prototype.toLocaleString() 方法。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 ",")隔开:

Array.prototype.indexOf(searchElement[, fromIndex = 0])  IE9

返回数组中第一个与指定值searchElement相等(使用严格相等)的元素的索引,如果找不到这样的元素,则返回 -1。

参数fromIndex 开始查找的位置,其默认值为0。如果该索引值大于或等于数组长度,意味着不会在数组里查找,返回-1。可以为负值。

 

Array.prototype.lastIndexOf(searchElement[, fromIndex = arr.length - 1])  IE9

返回数组中最后一个(从右边数第一个)与指定值相等(使用严格相等)的元素的索引,如果找不到这样的元素,则返回 -1。从数组的后面向前查找,从 fromIndex 处开始,若大于等于默认值arr.length - 1,即在整个数组中查找。如果为负值,将其视为从数组末尾向前的偏移。即使该值为负,数组仍然会被从后向前查找。如果该值为负时,其绝对值大于数组长度,则方法返回 -1,即数组不会被查找。

Array.prototype.includes()  ES7

判断当前数组是否包含某指定的值,如果是返回 true,否则返回 false

 

遍历方法

在下面的众多遍历方法中,有很多方法都需要指定一个回调函数callback作为参数。在回调函数执行之前,数组的长度会被缓存在某个地方,所以,如果你在回调函数中为当前数组添加了新的元素,那么那些新添加的元素是不会被遍历到的。此外,如果在回调函数中对当前数组进行了其它修改,比如改变某个元素的值或者删掉某个元素,那么随后的遍历操作可能会受到未预期的影响。总之,不要尝试在遍历过程中对原数组进行任何修改

Array.prototype.forEach(callback[, thisArg])  IE9

为数组中的每个元素执行一次回调函数。 

  • forEach 方法按升序为数组中含有效值的每一项执行一次callback 函数,那些已删除(使用delete方法等情况)或者从未赋值的项将被跳过(但不包括哪些值为 undefined 的项)。
  • forEach 遍历的范围在第一次调用 callback 前就会确定。调用forEach 后添加到数组中的项不会被 callback 访问到。如果已经存在的值被改变,则传递给 callback 的值是 forEach 遍历到他们那一刻的值。已删除的项不会被遍历到。
  • 没有办法中止或者跳出 forEach 循环,除了抛出一个异常。如果你需要这样,使用forEach()方法是错误的,你可以用一个简单的循环作为替代。如果您正在测试一个数组里的元素是否符合某条件,且需要返回一个布尔值,那么可使用 Array.every 或 Array.some

callback ( currentValue, index, array )回调函数,接收三个参数:currentValue数组当前项的值,index当前项的索引,array数组对象本身。

thisArg 可选参数。用来当作callback 函数内this的值的对象。如果 thisArg 值为 undefined 或 null,函数的 this 值取决于当前执行环境是否为严格模式(严格模式下为 undefined,非严格模式下为全局对象)。

 

Array.prototype.every(callback[, thisArg])  IE9

如果数组中的每个元素都满足测试函数,则返回 true,否则,在遇到第一个不满足测试函数时就立即返回 false。

callback ( currentValue, index, array ) (会跳过空元素)只会为那些已经被赋值的索引调用,不会为那些被删除或从来没被赋值的索引调用。

  • every 不会改变原数组。
  • every 遍历的元素范围在第一次调用 callback 之前就已确定了。在调用 every 之后添加到数组中的元素不会被callback 访问到。
  • 如果数组中存在的元素被更改,则他们传入 callback 的值是 every 访问到他们那一刻的值。那些被删除的元素或从来未被赋值的元素将不会被访问到。

 

 

Array.prototype.some(callback[, thisArg])  IE9

如果数组中至少有一个元素满足测试函数,直到找到第一个满足callback时才立即返回 true,否则返回 false。其它和every方法一致

 

Array.prototype.filter(callback[, thisArg])  IE9

将所有在过滤函数中 callback(element, index, array) 中返回 true或等价于 true 的值的数组元素element放进一个新数组中并返回。同forEach、every、some一样,filter方法也会会跳过空值,开始遍历时,也确定了范围。

 

Array.prototype.map(callback[, thisArg])  IE9

返回一个由原数组中的每个元素调用一个指定方法后的返回值组成新数组。

map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数。callback 每次执行后的返回值组合起来形成一个新数组。 map方法也会跳过空值,其它同以上方法一样。

["1", "2", "3"].map(parseInt);

// 你可能觉的会是[1, 2, 3]  // 但实际的结果是 [1, NaN, NaN]

map方法在调用callback函数时,会自动给它传递三个参数:当前正在遍历的元素, 元素索引, 原数组本身.第三个参数parseInt会忽视, 但第二个参数不会,也就是说,parseInt把传过来的索引值当成进制数来使用.从而返回了NaN.这时应该使用自定义回调函数来包装function callback(element){ return parseInt(element,10); }

Array.prototype.reduce(callback,[initialValue])  IE9

从左到右为每个数组元素执行一次回调函数,并把上次回调函数的返回值放在一个暂存器中传给下次回调函数,并返回最后一次回调函数的返回值。即:接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始合并,最终为一个值。它也会跳过空元素

callback(previousValue,currentValue,index,array)  

  • previousValue 上一次调用回调返回的值,或者是提供的初始值(initialValue)
  • currentValue 数组中当前被处理的元素
  •  index 当前元素在数组中的索引

  •  array 调用 reduce 的数组

initialValue 作为第一次调用 callback 的第一个参数(提供的初始值)

  • 回调函数第一次执行时,previousValue 和 currentValue 可以是一个值,如果 initialValue 在调用 reduce 时被提供,那么第一个 previousValue 等于 initialValue ,并且currentValue 等于数组中的第一个值;如果initialValue 未被提供,那么previousValue 等于数组中的第一个值,currentValue等于数组中的第二个值。
  • 如果数组为空并且没有提供initialValue, 会抛出TypeError 。
  • 如果数组仅有一个元素(无论位置如何)并且没有提供initialValue, 或者有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行。

Array.prototype.reduceRight()  IE9

从右到左为每个数组元素执行一次回调函数,并把上次回调函数的返回值放在一个暂存器中传给下次回调函数,并返回最后一次回调函数的返回值。其它同reduce方法

Array.prototype.entries()  ES6  IE无

 

返回一个数组迭代器对象Array Iterator ,该迭代器对象会包含所有数组元素的键值对

Array.prototype.find(callback[, thisArg])  ES6 IE无

找到第一个满足测试函数的元素并返回那个元素的,如果找不到,则返回 undefined

  • 调用callback函数带有3个参数:当前元素的值、当前元素的索引,以及数组本身
  • find方法对数组中的每一项元素执行一次callback 函数,直至有一个callback返回true。当找到了这样一个元素后,该方法会立即返回这个元素的值,否则返回undefined
  • callback回调函数也会跳过空值,其它同every、some等方法

Array.prototype.findIndex()  ES6 只有Firefox支持

找到第一个满足测试函数的元素并返回那个元素的索引,如果找不到,则返回 -1

Array.prototype.keys()  ES6  IE无

 

返回一个数组迭代器对象,该迭代器会包含所有数组元素的。索引迭代器会包含那些没有对应元素的索引

迭代器的执行原理

var arr = ["a", "b", "c"];

var iterator = arr.keys();

console.log(iterator.next()); // { value: 0, done: false }

console.log(iterator.next()); // { value: 1, done: false }

console.log(iterator.next()); // { value: 2, done: false }

 

console.log(iterator.next()); // { value: undefined, done: true }

Array.prototype.values()  ES6 只有Firefox、Safari支持

返回一个新的 Array Iterator 迭代器对象,该迭代器会包含所有数组元素的

使用 for...of 循环进行迭代

var arr = [‘w‘, ‘y‘, ‘k‘, ‘o‘, ‘p‘];

var eArr = arr.values();

您的浏览器必须支持 for..of 循环,以及 let —— 将变量作用域限定在 for 循环中

for (let letter of eArr) {

  console.log(letter);

}

另一种迭代方式

var arr = [‘w‘, ‘y‘, ‘k‘, ‘o‘, ‘p‘];

var eArr = arr.values();

console.log(eArr.next().value); // w

console.log(eArr.next().value); // y

console.log(eArr.next().value); // k

console.log(eArr.next().value); // o

 

console.log(eArr.next().value); // p

 

Array.prototype[@@iterator]()  ES6 IE、Safari无

 

数组的@@iterator属性和 values() 属性的初始值均为同一个函数对象。@@iterator属性返回数组的 iterator 方法,默认情况下与 values() 返回值相同

var arr = [‘w‘, ‘y‘, ‘k‘, ‘o‘, ‘p‘];

var eArr = arr[Symbol.iterator]();

 

 

 

 

 

 

以上是关于原生JS:Array对象详解的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript原生对象属性和方法详解——Array对象 转载

怎么将json对象添加进json数组中

js中prototype与__proto__的关系详解

js代码片段: utils/lcoalStorage/cookie

怎么把json字符串转成数组对象

原生JS:String对象详解