资讯专栏INFORMATION COLUMN

JS淬炼: Array进阶

jimhs / 334人阅读

摘要:的这种实现方式导致了一些尴尬问题,比如删除元素元素遍历。后面的参数被忽略掉了,表示并没有要插入的元素。其实,的本质是跟踪中的,并始终保持值是。这时候,虽然不大可能,可能会在中间某个中被用户重新定义。但是在上进行这种操作是很糟糕的。

在Javascript中,array是一个类数组的object。顾名思义,它能够在一个变量上存储多个值。

数组是值的有序集合。每个值叫做一个元素,而每个元素在数组中有一个位置,以数字表示,称为索引。JavaScript数组是无类型:数组元素可以是任意类型,并且同一个数组中的不同元素也可能有不同的类型。 --《JavaScript权威指南(第六版)》

array在一般Javascript object基础上,有自己额外的属性。它采用numbered index作为的key,有一个length property跟踪数组长度,还有如push/popshift/unshift等数组特有操作。

本质是object

作为一个object,我们可以在array上面进行所有object的合法操作,比如设置一个named key。

var test = [];
test.fruit = "APPLE";
console.log(test.fruit); // APPLE

上面仅仅把array作为一个普通的Javascript object使用,等价于var test = {}。在这种场合,我们应该选择普通的Javascirpt object,而非array。

Numbered index

Javascript中的 array object 采用了一个很朴素的思想来实现数组 —— 用数字来充当object的keys。这样在表面上延续了我们在C++/Java上使用数组的编程体验。

{ 
    0 : item0, 
    1 : item1, 
    2 : item2
}

array的这种实现方式导致了一些尴尬问题,比如删除元素、元素遍历。我们会在后面谈到这些问题。

删除元素 delete operator(不推荐)

和一般Javascript object一样,我们可以使用delete来删除object中的property。

var arr = ["a", "b", "c", "d"];
delete arr[1];
console.log(arr);
console.log(arr[1]);
// [ "a", , "c", "d" ]
// undefined

当我们使用delete来删除某一个元素arr[1]时,arr中key 1 和value b之间的连接被切断,key 1对应的值被重置为undefined。注意,这时候,array中其他元素并没有改变自身的index来填补这key 1这个空洞,而是保持原值。这样,key 1就变成了arr中的一个洞了!

除非有特殊需求,比如需要用到sparse array,一般情况下并不推荐使用delete operator来删除array中的元素。

splice() (推荐)
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(0, 1); // Removes the first element of fruits

第一个参数 (0) 定义新元素要从哪个位置插入。第二个参数 (1) 定义新元素插入位置开始有多少元素要被删除。后面的参数被忽略掉了,表示并没有要插入的元素。

filter()(推荐)
var fruits = ["Banana", "Orange", "Apple", "Mango"];
var toDelete = "Apple";
fruits = fruits.filter(function(value) { 
    return value != toDelete;
});
// [ "Banana", "Orange", "Mango" ]
理解length

length是array object的一个property, 根据名字来看,似乎是记录array的长度。其实,length的本质是跟踪array中的max_index,并始终保持值是max_index + 1

这和记录长度有什么区别呢?

还记得使用delete来删除元素的情形吧?中间元素被删了,但是其他元素没有改变自身的index来填补空间。这时候即使delete了多个元素,数组的length可能并没有发生变化。

var array_object = [1, 2, 3];
console.log(array_object.length); // 3
delete array_object[1];
console.log(array_object.length); // 3!
Array 遍历

如果array中没有“洞”, for loop和forEach两种遍历方式区别不大。在array有洞的情况下,两者略有不同,其中forEach会跳过这些洞,而传统的for loop并不会。

var array_object = [1, 2, 3];
delete array_object[1];

// 不跳过洞
for(var i=0; i

遍历array的方法还有其他,更多方法可以参考这篇StackOverflow问答。

[] vs. new Array( )

当新建一个array时候,我们有下面两种方式: array literal [] 或 array constructor new Array(arg)

var arrayA = [];
var arrayB = new Array();

当使用[]时候, JS engine会直接调用global Array的constructor新建一个array变量并返回。当使用new Array()时候, JS engine会沿着Execution Context往上追溯到名为Array的constructor function,并据此生成一个object。这时候,虽然不大可能,Array可能会在中间某个Execution Context中被用户重新定义。下面是coderjoe在StackOverflow中提出的例子。在例子中,我们最后得到的并不是我们期待的原生Array。

function Array() { 
    this.is = "SPARTA";
}
var a = new Array();
var b = [];
alert(a.is); 
// => "SPARTA"
alert(b.is); 
// => undefineda.push("Woa"); 
// => TypeError: a.push is not a functionb.push("Woa"); 
// => 1 (OK)

大部分Javascirpt社区推荐使用[]来新建array。

You never need to use new Object() in JavaScript. Use the object literal {} instead. Similarly, don’t use new Array(), use the array literal [] instead. Arrays in JavaScript work nothing like the arrays in Java, and use of the Java-like syntax will confuse you. LINK

Array 复制 浅度复制
var arr1 = ["a", "b", "c"];
var arr2 = arr1; 
arr2[0] = 1; // 对数组arr2的元素进行修改
console.log(arr1); // [1, "b", "c"]
深度复制
var arr1 = ["a", "b", "c", "d", "e"];
var arr2 = arr1.concat(); // 使用concat()方法,返回新的数组
arr2[0] = 1; 
console.log(arr1); // => ["a", "b", "c", "d", "e"]:数组arr1的元素没变更
console.log(arr2); // => [ 1, "b", "c", "d", "e"]:数组arr2的元素发生了变更
Associate Array

在计算机科学中,采用named index而非numbered index的数组被称为Associative Array。

var associative_array = new Array();
associative_array["one"] = "Lorem";
associative_array["two"] = "Ipsum";
associative_array["three"] = "dolor";

for (i in associative_array) { 
    console.log(i);
};
// one two three 

上面操作可以应用在任何Javascript object上,array object也不例外。但是在Javascript array上进行这种操作是很糟糕的。当需要使用named string作为key时候,我们应该使用一般的object,而非array。

Javascript里面并不支持named index的array。

If you use a named index, JavaScript will redefine the array to a standard object. After that, all array methods and properties will produce incorrect results... In JavaScript, arrays always use numbered indexes. LINK

Reference

Iterating over an array with “holes” in JavaScript

Create an empty object in JavaScript with {} or new Object()?

What’s the difference between “Array and “[]” while declaring a JavaScript array?

JavaScript Array对象

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91198.html

相关文章

  • JS淬炼: Syntax Parser

    摘要:语法分析利用词法分析的结果建立上下文关系语法树。一般情况下,我们不会直接和语法树打交道,但会在进行代码压缩语法高亮重编译关键字匹配和作用域判断时间接涉及到。传统的引擎直接根据语法树的的结果进行解释执行,导致效率比较为低下。 一门语言的执行,大致经历下面这些过程:词法分析 -- 语法分析 -- 语义分析 -- 中间代码生成 -- 优化代码 -- 代码生成。 在Javascript中,Sy...

    wuaiqiu 评论0 收藏0
  • JS淬炼: Primitive vs. Object

    摘要:值传递引用传递是值传递,是引用传递。但这影响会根据父类是属于还是而有微妙差别。我们设想有一个父类,和两个继承了他的子类和。这时,子类修改该不会影响到父类本身,更不会传递到其他子类上。 Javascript有两种基本数据类型,Primitive和Object。Object是properties的聚合,其property可以是Object也可以是Primitive。Primitive只有v...

    Hancock_Xu 评论0 收藏0
  • 进阶3-3期】深度解析 call 和 apply 原理、使用场景及实现

    摘要:之前文章详细介绍了的使用,不了解的查看进阶期。不同的引擎有不同的限制,核心限制在,有些引擎会抛出异常,有些不抛出异常但丢失多余参数。存储的对象能动态增多和减少,并且可以存储任何值。这边采用方法来实现,拼成一个函数。 之前文章详细介绍了 this 的使用,不了解的查看【进阶3-1期】。 call() 和 apply() call() 方法调用一个函数, 其具有一个指定的 this 值和分...

    godlong_X 评论0 收藏0
  • js基础进阶--编码实用技巧(一)

    摘要:我的个人博客前言在平时的开发中,编码技巧很重要,会让你少写很多代码,起到事倍功半的效果。下面总结几种简单的技巧,大家共同学习一下利用将字符串转换为整数型这个方法试用于将字符串类型的数字转换为整数型,如果带字母就会返回。 我的个人博客:http://www.xiaolongwu.cn 前言 在平时的开发中,编码技巧很重要,会让你少写很多代码,起到事倍功半的效果。 下面总结几种简单的技巧,...

    U2FsdGVkX1x 评论0 收藏0
  • JS进阶篇5---JS数组去重的n种方式

    1、利用 indexOf() 方法之一 Array.prototype.unique = function(){ var temp = []; for (var i = 0;i < this.length;i++){ // 如果当前数组的第 i 项已经保存到了临时数组,那么跳过 if(temp.indexOf( this[i] ) == -1){ ...

    baihe 评论0 收藏0

发表评论

0条评论

jimhs

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<