林大妈的JavaScript基础知识(三):JavaScript编程(4)数组
数组,是一段线性分配的,具有非常高性能的数据结构。简单地说,数组以连续的空间存储,通过整数地计算偏移量访问其中的元素,将读取修改的时间复杂度降低至O(1),我们称之为猝发式存取。是不是非常期待?没错,像这样的好东西,JavaScript没有。
1. Array简介
但作为替代,JavaScript设计者想出了一个更方便但性能相对较低的方案,打印观察Array.prototype,会发现,设计者为我们提供的是一个array-like(类数组)的对象。在检索和更新属性上,Array就和普通的对象一模一样(也就是说要遍历所有属性),只是多了一个不可枚举的属性length来记录这个对象所表示的数组的长度。尽管Array对象的性能明显比数组要差,但是搭配上弱类型的JavaScript语言(当然,JavaScript中不存在传统的数组一部分原因也是因为这一点),它在使用上非常的方便。更贴心的是,设计者还为我们提供了许多内置的方法,可以快速解决其他语言费很大劲才能解决的问题。
2. 声明
数组的声明跟对象的声明很类似。我们可以用两种方法初始化一个数组:① 直接用 var array = []; 我们称之为数组字面量的方式来初始化;② 使用构造函数 var array = new Array(); 如果参数填入一个数字,则返回一个长度为这个数字的空数组,如果参数填入多个值,则返回一个按顺序保存了这些值的Array对象。
3. 修改
上面我们已经搞清楚了Array对象总体的结构,这样修改一个数组就可以转化为我们以前学到的修改一个对象属性的知识了。由于JavaScript的灵活性,除非你定义一个大到Infinity的数组,其他情况下均不会因为越界报错(Runtime Error也许是很多人的噩梦,反正是我的噩梦)。因此,假如我们现在有这样一个数组:
var myArray = [0, '1', true]
利用JavaScript会帮我们维护length属性这一特点(但为了编写易维护的代码,不推荐这些简单粗暴的做法),我们也可以做一些在别的语言中看起来不可思议的操作,例如:① myArray[8] = undefined 会直接把Array的长度扩展到8;② myArray.length = 0; 能直接清空数组。除了可以这样清空数组,还可以通过Array.prototype.splice方法完成清空,因此我们把目光放到数组的原型方法上来。
4. 原型方法(均以上面的myArray举例)
① indexOf
indexOf方法同时存在于Array.prototype和String.prototype中,可以用它来检测数组或字符串中是否存在对应的元素,如果存在,则返回它的下标,如果不存在,则返回-1:
console.log(myArray.indexOf(0)); //0
console.log(myArray.indexOf(1)); //-1
由于在数组中,1和'1'是两个不同的值,因此第二句返回结果-1。
② push、pop、unshift、shift
push朝数组末尾推入若干新元素,返回加入后数组的length。
pop弹出数组末尾的一个元素,返回被弹出的元素。
unshift朝数组开头推入若干新元素,返回加入后数组的length。
shift弹出数组开头的一个元素,返回被弹出的元素。
console.log(myArray.push('A', 'B')); //
console.log(myArray.pop()); //'B'
console.log(myArray.unshift('A', 'B')); //
console.log(myArray.shift()); //'A'
③ sort(这时候我们重新定义一下 myArray = [5, 2, 0, 10, 17, 25]; )
sort方法在原数组上动刀,这里我们期望将数组中的数按从小到大的顺序排列,sort函数可以帮我们做到这一点,但需要注意的是,sort函数默认把这些元素转化为字符串进行比较。因此这个数组排序以后的结果是这样的:
console.log(myArray.sort()); // [0, 10, 17, 2, 25, 5]
因此通常需要填入一个比较判断函数作为参数,下面传入一个箭头函数,按照我所定义的这个函数进行判断大小再排序:
console.log(myArray.sort((x, y)=>{return x - y;})); // [0, 2, 5, 10, 17, 25]
④ reverse和join
reverse方法在原数组上动刀,返回跟原来相反的数组;join方法相当于String.prototype.split方法的反函数,填入一个字符串参数,以这个参数将每个元素分隔开,合并成一个字符串并返回。这两个方法可以搭配使用来处理反向输出字符串的问题:
var str = "Hello world!";
console.log(str.split('').reverse().join(''));
//"!dlrow olleH"
console.log(str.split(' ').reverse().join(' '));
//"world! Hello"
这里由于每个函数返回值都是与其相对应的数组或字符串,可以直接在这个返回值上进行操作,因此我们还用到了链式调用的技巧。
⑤ slice和splice
这两个方法的区别和使用非常重要,又由于它们名字之间只差一个字母,缺少练习时我们很容易会将其混淆。
slice方法可以类比String.prototype.substring。指定一个参数n,它将返回一个新数组,这个数组中含有原数组下标从n到末尾的所有元素。指定两个参数a和b时,它将返回一个新数组,这个数组含有原数组下标从a到b的所有元素(不得不说,用中文来描述真的非常蹩脚):
var myArray = [1, 2, 3, 4, 5, 6, 7, 8]; var aNewArray = myArray.slice(3);
var aNewNewArray = myArray.slice(3, 5); console.log(aNewArray);
//[4, 5, 6, 7, 8]
console.log(aNewNewArray);
//[4, 5]
当然了,这两种操作都是含头不含尾的。如果不指定参数地使用slice,它将返回一个跟原数组一模一样的数组,利用这一点,我们可以用一句代码复制一个数组。
splice是修改一个数组的“万能方法”,要注意它将直接在原数组上动刀,返回值是被删除的元素组成的数组:
var myArray = ['CapAmerica', 'IronMan', 'Hulk', 'Thor'];
// param: 从第4个元素开始操作,删除0个元素,加入新元素'BlackWidow'
myArray.splice(3, 0, 'BlackWidow');
// 由于删除0个元素,它将返回一个空数组 console.log(myArray);
// ['CapAmerica', 'IronMan', 'Hulk', 'Thor', 'BlackWidow'] // param:从第二个元素开始,删除三个元素,加入这些新元素
myArray.splice(2, 3, 'ScarletWitch', 'Vision', 'CapMarvel');
//返回['Hulk', 'Thor', 'BlackWidow'] console.log(myArray);
//['CapAmerica', 'IronMan', 'ScarletWitch', 'Vision', 'CapMarvel']
⑥ concat
concat方法不会动原数组,而是返回新数组。它返回一个将原数组和所有你填入的参数都合并在一起的新数组,因此我们想到了可以用它搭配splice方法来实现一个JavaScript版本的快速排序:
function quickSort(arr) {
if(arr.length <=1) return arr;
var pivotIndex = Math.floor(arr.length / 2);
var pivot = arr.splice(pivotIndex, 1)[0];
var left = [], right = [];
for(var i = 0; i < arr.length; i++) {
if(arr[i] < pivot) left.push(arr[i]);
else right.push(arr[i]);
};
return quickSort(left).concat(pivot, quickSort(right));
}
拓展:1. ES6 Map
我们都知道,在Array对象中,每个元素就是一个对象,通过键值对存储数据。但其中的键只能是字符串类型。我们渴求能用类似Number或其他基本数据类型作为键,这样的表达会更清晰。因此ES6为我们带来了Map数据结构,它还具有极高的查询效率。且看它的使用语法:
var myMap = new Map([['name', 'MotherLyn'],['score', 51]]);
观察发现,我们完全可以把它当做是一个两列n行的,对数据类型有规范的二维Array。它还有许多内置方法:set、get、has、delete。
要注意的是,Map中所有的键类似数据库中的primary key,也就是他们都是不可重复的,填入相同的键不同的值只会把以往的数据冲掉。
2. ES6 Set
Set与Map类似但又十分不同。说它相同是因为Set对数据类型也是存在划分的(3和‘3’是不同的两个键);说它不同是因为Set只一个值而不是一个键值对。因此使用Set时只需要传入一个一维的Array即可:
var mySet = new Set(['MotherLyn', 51]);
通过使用内置方法add、delete和has可以进行增删查改操作。
3. ES6 for of遍历方法
前面我们提到,使用for in遍历会将可枚举的原型属性一块遍历到。为了解决这个问题,ES6提出了for of遍历。它在使用上和for in是相同的,只是把in改成of而已。
总结:① JavaScript中的Array对象只是一个内建的对象,并不是传统意义上的数组,它在内存中不是连续的空间,因此只能遍历元素来进行查找修改,性能较差但灵活性非常好。
② Array.prototype中有非常多的方法,常用的有以上这些:indexOf、push、pop、unshift、shift、sort、reverse、join、slice、splice和concat。还有很多其他的方法,要善用这些方法只能靠多练习,慢慢积累。
③ ES6中的Map和Set都是类似Array的数据结构,它们都严格管理数据类型,但区别是Map以键值对的方式存储,Set只能存储值而不能存储键。
林大妈的JavaScript基础知识(三):JavaScript编程(4)数组的更多相关文章
- JavaScript基础知识整理(1)数组
第一:创建. 1,var arr= new Array(); //数组为空.长度为0. arr[0]="apple"; arr[1]="orange"; arr ...
- 【javascript基础知识】javascript中的转义序列和特殊数值常量
javascript的转义序列 \0 NUL字符(\u0000) \b 退格符(\u0008) \t 水平制表符(\u0009) \n 换行符(\u000A) \v 垂直制表符(\u000B) \f ...
- Javascript 基础知识学习--javascript中的参数传递都是按值传递的
ECMAScript中所有函数的参数传递都是按值传递的,无论参数是值类型还是引用类型的.过去我跟大多数人一样觉得跟传值类型相关. 自己写了一个测试的例子,确实如此 function add(a) { ...
- 学习javascript基础知识系列第二节 - this用法
通过一段代码学习javascript基础知识系列 第二节 - this用法 this是面向对象语言中的一个重要概念,在JAVA,C#等大型语言中,this固定指向运行时的当前对象.但是在javascr ...
- 学习javascript基础知识系列第三节 - ()()用法
总目录:通过一段代码学习javascript基础知识系列 注意: 为了便于执行和演示,建议使用chrome浏览器,按F12,然后按Esc(或手动选择)打开console,在console进行执行和演示 ...
- Javascript基础知识总结一
Javascript基础知识总结一 <!DOCTYPE html> <html> <head lang="en"> <meta chars ...
- JavaScript基础知识(一)
一.JavaScript基础 1.JavaScript用法: HTML 中的脚本必须位于 <script> 与 </script> 标签之间. 脚本可被放置在 HTML 页面的 ...
- JavaScript基础(三)
十三.JS中的面向对象 创建对象的几种常用方式 1.使用Object或对象字面量创建对象 2.工厂模式创建对象 3.构造函数模式创建对象 4.原型模式创建对象 1.使用Object或对象字面量创建对象 ...
- javascript 基础知识学习1
JavaScript 是脚本语言.浏览器会在读取代码时,逐行地执行脚本代码.而对于传统编程来说,会在执行前对所有代码进行编译.基础知识:1).JavaScript 对大小写敏感.JavaScript ...
- JavaScript 基础知识 - BOM篇
前言 本篇文章是JavaScript基础知识的BOM篇,如果前面的<JavaScript基础知识-DOM篇>看完了,现在就可以学习BOM了. 注意: 所有的案例都在这里链接: 提取密码密码 ...
随机推荐
- Java NIO 学习笔记(五)----路径、文件和管道 Path/Files/Pipe
目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...
- NumPy基础操作
NumPy基础操作(1) (注:记得在文件开头导入import numpy as np) 目录: 数组的创建 强制类型转换与切片 布尔型索引 结语 数组的创建 相关函数 np.array(), np. ...
- Git项目迁移
代码项目迁移步骤 1.将原有项目重命名,old 2.新建一个项目,名字为原本的项目名称,new 3.使用特殊方式克隆代码 # old.git为原项目重命名后的git链接 git clone --mir ...
- golang切片和数组的区别
好久的没有写博客了,这段时间没事研究了下go这门语言. 我们先介绍下go中的数组和切片的区别和用法 说了这么多 我们先来看段代码吧 var arr1 [3]int var arr2 [3]int = ...
- 使用SQL行转列函数pivot遇到的问题
背景:对投票的结果按照单位进行汇总统计,数据库中表记录的各个账号对各个选项的投票记录.马上想到一个解决方案,先根据单位和选项进行Group By,然后再行转列得出单位对各个选项的投票情况. with ...
- cat more less 命令混用
在Linux系统中有三种命令可以用来查阅全部的文件,分别是cat.more和less命令.它们查阅文件的使用方法也比较简单都是 命令 文件名 ,但是三者又有着区别. 1.cat命令可以一次显示整个文件 ...
- 机器学习读书笔记(二)使用k-近邻算法改进约会网站的配对效果
一.背景 海伦女士一直使用在线约会网站寻找适合自己的约会对象.尽管约会网站会推荐不同的任选,但她并不是喜欢每一个人.经过一番总结,她发现自己交往过的人可以进行如下分类 不喜欢的人 魅力一般的人 极具魅 ...
- Git使用小技巧之挑拣合并
先想想一个情况,现在我们有一个功能急需要发布到线上,但是这个功能相关的代码所在的测试分(test)支有很多不应该发布的代码,那么这个时候我们就需要将与这个代码相关的提交选择性的合并到master上并发 ...
- Keep It Simple
The KISS principle, or Keep It Simple, Stupid, spans many trades, industries, and professions. The m ...
- C++学习书籍推荐《Effective C++ 第三版》下载
百度云及其他网盘下载地址:点我 编辑推荐 <Effective C++:改善程序与设计的55个具体做法(第3版)(中文版)(双色)>前两个版本抓住了全世界无数程序员的目光.原因十分明显:S ...