|
| 1 | +与 Java 、PHP 等语言不同,在 JavaScript 中,数组其实是一种特殊的对象。 |
| 2 | +#### 数组的创建与读写 |
| 3 | +以下两种方式都可创建数组: |
| 4 | +``` |
| 5 | +// 字面量方式,常用 |
| 6 | +var num = [1,5,6,10]; |
| 7 | +print(num.length); // 4 |
| 8 | +
|
| 9 | +// 构造函数方式 |
| 10 | +var num = new Array(1,5,6,10); |
| 11 | +print(num.length); // 4 |
| 12 | +``` |
| 13 | +值得注意的是,JavaScript 中的数组数据可以是不同类型,它的语法相对宽松,例如可以指定不同类型数据`var example = [1,"Mike",true,null];`另外,可以通过`Array.isArray()`来判断一个对象是否是数组,例如: |
| 14 | +``` |
| 15 | +var num = [1,5,6,10]; |
| 16 | +print(Array.isArray(num)); // true |
| 17 | +``` |
| 18 | +如何读写数组呢?可以使用循环。 |
| 19 | +``` |
| 20 | +var num = [1,5,6,10]; |
| 21 | +for (var i = 0; i < num.length; i++) { |
| 22 | + console.log(num[i]+" "); |
| 23 | +} |
| 24 | +``` |
| 25 | +#### 数组的深复制与浅复制 |
| 26 | +当我们把数组赋给另外一个数组,然后改变其中一个数组的值,另一数组也会随之改变,这就是数组的浅复制。而深复制指的就是不改变原来的数组而去创建一个新的数组,这种情况是经常使用的,为了不破坏原数组。下面的代码展示了这两种复制 |
| 27 | +``` |
| 28 | +// 浅复制 |
| 29 | +var num = [1,2,3,4,5]; |
| 30 | +var newNum = num; |
| 31 | +num[0] = 10; |
| 32 | +console.log(newNum[0]); // 10 |
| 33 | +
|
| 34 | +// 深复制 |
| 35 | +function copy (arr1,arr2) { |
| 36 | + for(var i=0;i<arr1.length;i++){ |
| 37 | + arr2[i] = arr1[i]; |
| 38 | + } |
| 39 | +} |
| 40 | +var num = [1,5,6,7,9]; |
| 41 | +var newNum = []; |
| 42 | +copy(num,newNum); |
| 43 | +num[0] = 10; |
| 44 | +console.log(newNum[0]); // 仍然为 1 |
| 45 | +``` |
| 46 | +#### 存取函数 |
| 47 | +JavaScript 提供了一组用来访问数组元素的函数,叫存取函数。最常用的存取函数就是 indexOf() 函数,该函数返回指定查找的值在目标值中是否存在,如果存在,返回该值在数组中的索引,不存在则返回 -1。 |
| 48 | +``` |
| 49 | +var word = ["A","B","C","D"]; |
| 50 | +var result = word.indexOf("A"); |
| 51 | +console.log(result); // 0 |
| 52 | +var test = word.indexOf("F"); |
| 53 | +console.log(test); // -1 |
| 54 | +``` |
| 55 | +除此之外,还有 join 和 toString 函数,concat 和 splice 函数。前两个函数可以将数组转化为字符串,后面两个函数可以通过已有的数组创建新数组,其中 concat 方法通过合并多个数组来形成新数组,而 splice 方法是截取一个数组的子集作为一个新数组。它们的使用示例如下 |
| 56 | +``` |
| 57 | +var arr = ["Mike","John","Hexo"]; |
| 58 | +console.log(arr.join()); // Mike,John,Hexo |
| 59 | +console.log(arr.toString()); // Mike,John,Hexo |
| 60 | +
|
| 61 | +var arr1 = [1,10,"Mike"]; |
| 62 | +var arr2 = [8,7,6]; |
| 63 | +var cat = arr1.concat(arr2); |
| 64 | +console.log(cat); // [1, 10, "Mike", 8, 7, 6] |
| 65 | +var num = [1,2,3,4,5,6,7]; |
| 66 | +var a = num.splice(3,2); // 3 表示索引,2 表示删除 2 个 |
| 67 | +console.log(num); // [1, 2, 3, 6, 7] |
| 68 | +``` |
| 69 | +#### 可变函数 |
| 70 | +不去引用数组中的某个元素,就能改变数组内容,这种函数称它为可变函数。 |
| 71 | +###### push() 和 unshift()、pop() 和 shift() |
| 72 | +push() 方法可以在数组末尾添加元素,而 unshift() 方法可以在数组开头添加元素;相对应的,pop 可以删除数组末尾的元素,而 shift 删除数组的第一个元素。 |
| 73 | +``` |
| 74 | +var nums = [9,58,15,16,23]; |
| 75 | +nums.push(111); |
| 76 | +console.log(nums); // 9, 58, 15, 16, 23, 111 |
| 77 | +nums.unshift(1); |
| 78 | +console.log(nums); // 1, 9, 58, 15, 16, 23, 111 |
| 79 | +nums.pop(); |
| 80 | +console.log(nums); // 1, 9, 58, 15, 16, 23 |
| 81 | +nums.shift(); |
| 82 | +console.log(nums); // 9, 58, 15, 16, 23 |
| 83 | +``` |
| 84 | +###### splice()、sort()、reverse() |
| 85 | +前面提到的 splice 不仅可以用来删除元素,还可以添加元素进数组。用 sort 可以为数组排序,reverse 将数组内的元素翻转。 |
| 86 | +``` |
| 87 | +var num = [98,99,100,101]; |
| 88 | +num.splice(1,0,89); // 1 表示索引,0 表示不删除元素,89 表示将 89 这个元素添加进数组 |
| 89 | +console.log(num); // 98, 89, 99, 100, 101 |
| 90 | +num.reverse(); |
| 91 | +console.log(num); // 101, 100, 99, 89, 98 |
| 92 | +``` |
| 93 | +关于 sort 方法非常有意思,它只能对那些字符串类型的元素排列得比较准确,但如果是数字,结果就不那么令人满意了。看看例子. |
| 94 | +``` |
| 95 | +var str = ["hello","client","zero"]; |
| 96 | +str.sort(); |
| 97 | +console.log(str); // ["client", "hello", "zero"] 按照字母 a-z 排列准确 |
| 98 | +var nums = [1,200,51,66,88]; |
| 99 | +nums.sort(); |
| 100 | +console.log(nums); // [1, 200, 51, 66, 88] 有趣的事情来了,因为 200 的 2 比 51 的 5 先,所以 200 排在 51 前头 |
| 101 | +``` |
| 102 | +那如何解决这种排序的错误呢?方法就是在调用 sort() 的时候传入一个函数,该函数可以比较出大小。 |
| 103 | +``` |
| 104 | +function compare(num1,num2){ |
| 105 | + return num1 - num2; |
| 106 | +} |
| 107 | +var nums = [3,1,2,100,4,200]; |
| 108 | +nums.sort(compare); |
| 109 | +console.log(nums); // 1, 2, 3, 4, 100, 200 |
| 110 | +``` |
| 111 | +可以看到,已经排序正确了,compare 函数就是利用了两数相减,如果结果为正,那么被减数大于减数,如果结果为 0,则两数相等,而如果结果为负,说明被减数小于减数。 |
| 112 | +#### 迭代器方法 |
| 113 | +迭代函数通过对数组中的元素逐个应用,来操作返回相应的值。 |
| 114 | +###### 不返回新数组的 forEach() 、every()、some()、reduce() |
| 115 | +``` |
| 116 | +// 用 forEach 开方 |
| 117 | +function square(num) { |
| 118 | + console.log(num,num*num); |
| 119 | +} |
| 120 | +var num = [1,2,3,4,5]; |
| 121 | +num.forEach(square); |
| 122 | +console.log(num); |
| 123 | +/* 1 1 |
| 124 | + 2 4 |
| 125 | + 3 9 |
| 126 | + 4 16 |
| 127 | + 5 25 |
| 128 | +*/ |
| 129 | +``` |
| 130 | +``` |
| 131 | +/* |
| 132 | +every() 返回值为布尔类型,对于应用的所有元素,该函数返回 true,则该方法返回 true |
| 133 | +*/ |
| 134 | +function isEven(num){ |
| 135 | + return num % 2 == 0; |
| 136 | +} |
| 137 | +var num = [2,4,6,8,10]; |
| 138 | +var even = num.every(isEven); |
| 139 | +if(even){ |
| 140 | + console.log("所有的数字都是偶数"); |
| 141 | +}else{ |
| 142 | + console.log("不是所有的数字都是偶数"); |
| 143 | +} |
| 144 | +``` |
| 145 | +``` |
| 146 | +/* |
| 147 | +some() 与 every() 的不同就是只要有一个元素使改函数返回 true ,那么该方法就返回 true |
| 148 | +*/ |
| 149 | +function isEven(num){ |
| 150 | + return num % 2 == 0; |
| 151 | +} |
| 152 | +var num = [1,2,3,4,5,6,7,8]; |
| 153 | +var someEven = num.some(isEven); |
| 154 | +if(even){ |
| 155 | + console.log("有些数字是偶数"); |
| 156 | +}else{ |
| 157 | + console.log("没有数字是偶数"); |
| 158 | +} |
| 159 | +``` |
| 160 | +``` |
| 161 | +/* |
| 162 | +reduce() 有两个功能,一是可以对数组元素进行求和,二是将数组元素连接成字符串。 |
| 163 | +*/ |
| 164 | +fucntion add(num1,num2){ |
| 165 | + return num1 + num2; |
| 166 | +} |
| 167 | +var num = [1,2,3,4]; |
| 168 | +var sum = num.reduce(add); |
| 169 | +console.log(sum); // 10 |
| 170 | +
|
| 171 | +function concat(str,i) { |
| 172 | + return str + i; |
| 173 | +} |
| 174 | +var words = ["I am ","a ","coder "]; |
| 175 | +var re = words.reduce(concat); |
| 176 | +console.log(re); // I am a coder |
| 177 | +``` |
| 178 | +###### 返回新数组的 map() 和 filter() |
| 179 | +map 的作用与 forEach 是一样的,区别就是 map 函数返回的是一个新数组。 |
| 180 | +``` |
| 181 | +function addFive(grade){ |
| 182 | + return grade += 5; |
| 183 | +} |
| 184 | +var grade = [77,82,88,95,90]; |
| 185 | +var result = grade.map(addFive); |
| 186 | +console.log(result); // 82, 87, 93, 100, 95 |
| 187 | +``` |
| 188 | +而 filter 和 every 相似,区别在于当所有的元素使改函数为 true 时,它并不返回布尔类型,而是返回一个新数组。下面这个例子十分有趣,它随机产生10个 0 到 100 的数字作为分数,然后把大于 60 的及格分数筛选出来。 |
| 189 | +``` |
| 190 | +function passing(num){ |
| 191 | + return num >= 60; |
| 192 | +} |
| 193 | +var grades = []; |
| 194 | +for(var i = 0;i < 11;i++){ |
| 195 | + grade[i] = Math.floor(Math.random() * 101); |
| 196 | +} |
| 197 | +var pass = grades.filter(passing); |
| 198 | +console.log("随机产生的 10 个同学的分数为:"); |
| 199 | +console.log(grades); |
| 200 | +console.log("及格的分数有:"); |
| 201 | +console.log(pass); |
| 202 | +``` |
| 203 | +上述代码的输出结果为 |
| 204 | +> 随机产生的 10 个同学的分数为: |
| 205 | +21, 4, 89, 45, 5, 51, 71, 7, 46, 53, 47 |
| 206 | +及格的分数有: |
| 207 | +89, 71 |
| 208 | +#### 二维数组 |
| 209 | +JavaScript 可以通过在数组里在嵌套一个数组来形成二维数组。 |
| 210 | +``` |
| 211 | +var grades = [[88,86,82],[91,82,83],[77,72,79]]; |
| 212 | +console.log(grades[1][2]); // 83 |
| 213 | +``` |
| 214 | +#### 处理二维数组 |
| 215 | +对于二维数组的处理可以分为两种,一种按列访问,一种是按行访问。 |
| 216 | +按列访问,外层循环对应行,内层循环对应列。例如,上述的数组,每一行对应一个学生的成绩记录,可以通过相加所有成绩,然后除以科目数来得到该生的平均成绩。 |
| 217 | +``` |
| 218 | +var grades = [[88,86,82],[91,82,83],[77,72,79]]; |
| 219 | +var total = 0; |
| 220 | +var average = 0.0; |
| 221 | +for(var row = 0;row<grades.length;++row){ |
| 222 | + for(var col = 0;col<grades[row].length;++col){ |
| 223 | + total += grades[row][col]; |
| 224 | + } |
| 225 | + average = total/grades[row].length; |
| 226 | + console.log("student "+parseInt(row+1)+" average: "+average.toFixed(2)); // toFixed 表示按照 2 位来保留小数 |
| 227 | + total = 0; |
| 228 | + average = 0.0; |
| 229 | +} |
| 230 | +``` |
| 231 | +上述代码的输出结果为 |
| 232 | +> student 1 average: 85.33 |
| 233 | +student 2 average: 85.33 |
| 234 | +student 3 average: 76.00 |
| 235 | + |
| 236 | + |
| 237 | +对于按行访问,则外层循环对应列,内城循环对应行,例如还是上述数组,现在的数组表示一个学生各科的分数,我们来求其平均成绩 |
| 238 | +``` |
| 239 | +var grades = [[88,86,82],[91,82,83],[77,72,79]]; |
| 240 | +var total = 0; |
| 241 | +var average = 0.0; |
| 242 | +for(var col = 0;col <grades.length;++col ){ |
| 243 | + for(var row= 0;row<grades[col ].length;++row){ |
| 244 | + total += grades[row][col]; |
| 245 | + } |
| 246 | + average = total/grades[col ].length; |
| 247 | + console.log("exam "+parseInt(col +1)+" average: "+average.toFixed(2)); |
| 248 | + total = 0; |
| 249 | + average = 0.0; |
| 250 | +} |
| 251 | +``` |
| 252 | +输出结果为: |
| 253 | +> exam 1 average: 85.33 |
| 254 | +exam 2 average: 80.00 |
| 255 | +exam 3 average: 81.33 |
| 256 | + |
| 257 | +其实只要调整 for 循环的顺序就可以控制是按行还是按列来输出,此外,JavaScript 还可以处理一些参差不齐的数组,比如一个二维数组中的数组,有的是两个元素,有的是四个元素,并不是都相同,在这种情况下,JavaScript 依然可以处理运行而不报错,这是因为不管多或少,都可以通过 length 属性来计算。 |
| 258 | +#### 对象数组 |
| 259 | +如果你有阅读到这里,你应该可以发现上面的所有例子里数据类型都是基本数据类型,不是数字就是字符串。对象数组,顾名思义,就是数组里面的元素可以是对象,这个与 java 的语法很相似,基本上所有的编程语言都是相通的。看看下面这个例子: |
| 260 | +``` |
| 261 | +function point(x,y){ |
| 262 | + this.x = x; |
| 263 | + this.y = y; |
| 264 | +} |
| 265 | +function show(arr){ |
| 266 | + for(var i=0;i<arr.length;i++){ |
| 267 | + console.log(arr[i].x + ", "+arr[i].y); |
| 268 | + } |
| 269 | +} |
| 270 | +var p1 = new Point(1,2); |
| 271 | +var p2 = new Point(2,4); |
| 272 | +var p3 = new Point(8,1); |
| 273 | +var p4 = new Point(2,9); |
| 274 | +var point = [p1,p2,p3,p4]; |
| 275 | +for(var i=0;i<point.lengh;i++){ |
| 276 | + console.log("Point "+parseInt(i+1)+": "+point[i].x+", "+point[i].y); |
| 277 | +} |
| 278 | +``` |
| 279 | +上述程序的输出结果为: |
| 280 | +> Point 1: 1, 2 |
| 281 | +Point 2: 2, 4 |
| 282 | +Point 3: 8, 1 |
| 283 | +Point 4: 2, 9 |
| 284 | + |
| 285 | +也可以用之前的 puh() 等操作方法来操作对象数组 |
| 286 | +``` |
| 287 | +var p5 = new Point(11,13); |
| 288 | +point.push(p5); |
| 289 | +console.log("添加了 p5 后:"); |
| 290 | +show(point); |
| 291 | +point.shift(); |
| 292 | +console.log("删除第一个元素后:") |
| 293 | +show(point); |
| 294 | +``` |
| 295 | +输出结果为: |
| 296 | +> 添加了 p5 后: |
| 297 | +1,2 |
| 298 | +2,4 |
| 299 | +8,1 |
| 300 | +2,9 |
| 301 | +11,13 |
| 302 | +删除第一个元素后: |
| 303 | +2,4 |
| 304 | +8,1 |
| 305 | +2,9 |
| 306 | +11,13 |
0 commit comments