JavaScript權威指南(7)——陣列

夕陽下的奔跑發表於2019-08-02

陣列

JavaScript陣列是無型別的:

  1. 陣列元素可以是任意型別,並且同一個陣列中的不同元素頁可能有不同的型別。
  2. 陣列的元素甚至也可能是物件或其他陣列
  3. 陣列的索引是基於零的32位數值,從0開始,最大2^32-2
  4. JavaScript陣列可能是稀疏的

建立陣列

var empty = []; // An array with no elements
var primes = [2, 3, 5, 7, 11]; // An array with 5 numeric elements
var misc = [ 1.1, true, "a", ]; // 3 elements of various types + trailing comma

var base = 1024;
var table = [base, base+1, base+2, base+3];

var b = [[1,{x:1, y:2}], [2, {x:3, y:4}]];

var count = [1,,3]; // An array with 3 elements, the middle one undefined.
var undefs = [,,]; // An array with 2 elements, both undefined.

var a = new Array();
var a = new Array(10);
var a = new Array(5, 4, 3, 2, 1, "testing, testing");
複製程式碼

陣列元素的讀和寫

var a = ["world"]; // Start with a one-element array
var value = a[0]; // Read element 0
a[1] = 3.14; // Write element 1
i = 2;
a[i] = 3; // Write element 2
a[i + 1] = "hello"; // Write element 3
a[a[i]] = a[0]; // Read elements 0 and 2, write element 3

o = {}; // Create a plain object
o[1] = "one"; // 使用整數索引

a.length // => 4

a[-1.23] = true; // This creates a property named "-1.23
a["1000"] = 0; // This the 1001st element of the array
a[1.000] // Array index 1. Same as a[1]
複製程式碼

陣列索引僅僅是物件屬性名的一種特殊型別,所以沒有越界錯誤。

稀疏陣列

  1. 稀疏陣列就是包含從0開始的不連續索引的陣列。
  2. 稀疏陣列通常在實現上比稠密的陣列更慢、記憶體利用率更高。
  a = new Array(5); // No elements, but a.length is 5.
  a = []; // Create an array with no elements and length = 0.
  a[1000] = 0; // Assignment adds one element but sets length to 1001.
複製程式碼
  1. 在陣列直接量中省略值時不會建立稀疏陣列。省略的原色在陣列中式存在的,其值為undefined。
   var a1 = [,,,]; // This array is [undefined, undefined, undefined]
   var a2 = new Array(3); // This array has no values at all
   0 in a1 // => true: a1 has an element with index 0
   0 in a2 // => false: a2 has no element with index 0
複製程式碼
  1. 當省略陣列直接量中的值時,如([1,,3]),這時所得的陣列是稀疏陣列,省略掉的值是不存在的
   var a1 = [,,,]; // This array is [undefined, undefined, undefined]
   var a2 = new Array(3); // This array has no values at all
   0 in a1 // => true: a1 has an element with index 0
   0 in a2 // => false: a2 has no element with index 0
複製程式碼

陣列長度

  1. 稠密陣列,length代表陣列中元素的個數。稀疏陣列,length大於元素的個數。
  2. 如果未一個陣列元素賦值,它的索引i大於或等於現有陣列的長度時,length屬性的值將設定為i+1;設定length屬性為一個小於當前長度的非負整數n時,當前陣列中哪些索引值大於或等於n的元素將從中刪除
   a = [1,2,3,4,5]; // Start with a 5-element array.
   a.length = 3; // a is now [1,2,3].
   a.length = 0; // Delete all elements. a is [].
   a.length = 5; // Length is 5, but no elements, like new Array(5)
複製程式碼
  1. ES 5 中陣列的length屬性是隻讀的。

陣列元素的新增和刪除

  1. 為新索引賦值
   a = [] // Start with an empty array.
   a[0] = "zero"; // And add elements to it.
   a[1] = "one";
複製程式碼
  1. push()方法
   a = []; // Start with an empty array
   a.push("zero") // Add a value at the end. a = ["zero"]
   a.push("one", "two") // Add two more values. a = ["zero", "one", "two"]
複製程式碼
  1. unshift()在陣列的首部插入一個元素
  2. 可以使用delete運算子刪除陣列元素
    1. 使用delete不會修改length屬性
    2. 也不會將原元素從高索引處移下來填充已刪除屬性的空白
    3. 刪除一個元素,程式設計稀疏陣列
  3. pop()從尾部刪除元素
  4. shift()從頭部刪除元素
  5. slice()用來插入、刪除或替換陣列元素

陣列遍歷

  1. 使用for迴圈
  var keys = Object.keys(o); // Get an array of property names for object o
  var values = [] // Store matching property values in this array
  for(var i = 0; i < keys.length; i++) { // For each index in the array
      var key = keys[i]; // Get the key at that index
      values[i] = o[key]; // Store the value in the values array
  }
  
複製程式碼
  1. 優化,只查詢一次陣列的長度
  for(var i = 0, len = keys.length; i < len; i++) {
  // loop body remains the same
  }
  
複製程式碼
  1. 遍歷時,需要排除null、undefined和不存在的元素
   for(var i = 0; i < a.length; i++) {
       if (!a[i]) continue; // Skip null, undefined, and nonexistent elements
       // loop body here
   }
   
複製程式碼
  1. 只跳過undefined和不存在的元素
   for(var i = 0; i < a.length; i++) {
       if (a[i] === undefined) continue; // Skip undefined + nonexistent elements
       // loop body here
   }
   
複製程式碼
  1. 只跳過不存在的元素仍要處理存在的undefined元素
  for(var i = 0; i < a.length; i++) {
      if (!(i in a)) continue ; // Skip nonexistent elements
      // loop body here
  }
  
複製程式碼
  1. for/in迴圈處理稀疏陣列
   for(var index in sparseArray) {
       var value = sparseArray[index];
       // Now do something with index and value
   }
   
複製程式碼
  1. for/in能列舉繼承的屬性名,如新增到Array.prototype中的方法。所以在陣列上不應該使用for/in迴圈,除非使用額外的檢測方法來過濾不想要的屬性
   for(var i in a) {
       if (!a.hasOwnProperty(i)) continue; // Skip inherited properties
       // loop body here
   }
   for(var i in a) {
       // Skip i if it is not a non-negative integer
       if (String(Math.floor(Math.abs(Number(i)))) !== i) continue;
   }
   
複製程式碼
  1. 如果陣列同時擁有物件屬性和陣列元素,返回的屬性名很可能是按照建立的順序而非數值的大小順序。如果依賴遍歷的順序,不要使用for/in而用for迴圈
  2. ES 5定義了forEach()
   var data = [1,2,3,4,5]; // This is the array we want to iterate
   var sumOfSquares = 0; // We want to compute the sum of the squares of data
   data.forEach(function(x) { // Pass each element of data to this function
   	sumOfSquares += x*x; // add up the squares
   });
   sumOfSquares // =>55 : 1+4+9+16+25
複製程式碼

函數語言程式設計

多維陣列

  1. JavaScript不支援真正的多維陣列,使用陣列的陣列來近似。

    wo-dimensional array as a multiplication table:
    // Create a multidimensional array
    var table = new Array(10); // 10 rows of the table
    for(var i = 0; i < table.length; i++)
        table[i] = new Array(10); // Each row has 10 columns
        // Initialize the array
        for(var row = 0; row < table.length; row++) {
            for(col = 0; col < table[row].length; col++) {
            	table[row][col] = row*col;
    	}
    }
    // Use the multidimensional array to compute 5*7
    var product = table[5][7]; // 35
    
    複製程式碼

陣列方法

  1. join()——將陣列中的所有元素都轉化為字串並連線在一起,可以指定分隔符,預設為逗號
   var a = [1, 2, 3]; // Create a new array with these three elements
   a.join(); // => "1,2,3"
   a.join(" "); // => "1 2 3"
   a.join(""); // => "123"
   var b = new Array(10); // An array of length 10 with no elements
   b.join('-') // => '---------': a string of 9 hyphens
複製程式碼
  1. reverse()——陣列逆序,在原陣列中重新排列,不生成新陣列
   var a = [1,2,3];
   a.reverse().join() // => "3,2,1" and a is now [3,2,1]
複製程式碼
  1. sort()——排序,預設以字母表順序排序
   var a = new Array("banana", "cherry", "apple");
   a.sort();
   var s = a.join(", "); // s == "apple, banana, cherry"
複製程式碼

可傳比較函式

   var a = [33, 4, 1111, 222];
   a.sort(); // Alphabetical order: 1111, 222, 33, 4
   a.sort(function(a,b) { // Numerical order: 4, 33, 222, 1111
   	return a-b; // Returns &lt; 0, 0, or &gt; 0, depending on order
   });
   a.sort(function(a,b) {return b-a}); // Reverse numerical order
   
複製程式碼

例子:字串陣列不區分大小寫排序

   a = ['ant', 'Bug', 'cat', 'Dog']
   a.sort(); // case-sensitive sort: ['Bug','Dog','ant',cat']
   a.sort(function(s,t) { // Case-insensitive sort
           var a = s.toLowerCase();
           var b = t.toLowerCase();
           if (a < b) return -1;
           if (a > b) return 1;
       	return 0;
       }); // => ['ant','Bug','cat','Dog']
   
複製程式碼
  1. concat()——返回一個新陣列,元素包括呼叫concat()的原始陣列的元素和concat()的每個引數
   var a = [1,2,3];
   a.concat(4, 5) // Returns [1,2,3,4,5]
   a.concat([4,5]); // Returns [1,2,3,4,5]
   a.concat([4,5],[6,7]) // Returns [1,2,3,4,5,6,7]
   a.concat(4, [5,[6,7]]) // Returns [1,2,3,4,5,[6,7]]
   
複製程式碼
  1. slice()——返回指定陣列的一個片段或子陣列,指定開始和結束的位置,負數表示相對於陣列中最後一個元素的位置
   var a = [1,2,3,4,5];
   a.slice(0,3); // Returns [1,2,3]
   a.slice(3); // Returns [4,5]
   a.slice(1,-1); // Returns [2,3,4]
   a.slice(-3,-2); // Returns [3]
複製程式碼
  1. splice()——在陣列中插入或刪除元素,splice()能夠從陣列中刪除元素、插入元素到陣列中或者同事完成這兩種操作。
   var a = [1,2,3,4,5,6,7,8];
   a.splice(4); // Returns [5,6,7,8]; a is [1,2,3,4]
   a.splice(1,2); // Returns [2,3]; a is [1,4]
   a.splice(1,1); // Returns [4]; a is [1]
複製程式碼

splice()的前兩個引數指定了需要刪除的元素,緊隨的任意個數的引數制定了需要插入到陣列中的原色,從第一個引數指定位置開始插入

   var a = [1,2,3,4,5];
   a.splice(2,0,'a','b'); // Returns []; a is [1,2,'a','b',3,4,5]
   a.splice(2,2,[1,2],3); // Returns ['a','b']; a is [1,2,[1,2],3,3,4,5]
   
複製程式碼

splice()會插入陣列本身而不是陣列的元素 7. push()和pop()——將陣列當成棧來使用,兩者都是替換原始陣列而非生成一個新的陣列

   var stack = []; // stack: []
   stack.push(1,2); // stack: [1,2] Returns 2
   stack.pop(); // stack: [1] Returns 2
   stack.push(3); // stack: [1,3] Returns 2
   stack.pop(); // stack: [1] Returns 3
   stack.push([4,5]); // stack: [1,[4,5]] Returns 2
   stack.pop() // stack: [1] Returns [4,5]
   stack.pop(); // stack: [] Returns 1
複製程式碼
  1. unshift()和shift()——在陣列的頭部進行元素的插入和刪除操作
   var a = []; // a:[]
   a.unshift(1); // a:[1] Returns: 1
   a.unshift(22); // a:[22,1] Returns: 2
   a.shift(); // a:[1] Returns: 22
   a.unshift(3,[4,5]); // a:[3,[4,5],1] Returns: 3
   a.shift(); // a:[[4,5],1] Returns: 3
   a.shift(); // a:[1] Returns: [4,5]
   a.shift(); // a:[] Returns: 1
複製程式碼

當使用多個引數呼叫unshift()時,引數是一次性插入的,而非一次一個地插入 9. toString()和toLocaleString()

   [1,2,3].toString() // Yields '1,2,3'
   ["a", "b", "c"].toString() // Yields 'a,b,c'
   [1, [2,'c']].toString() // Yields '1,2,c
複製程式碼

ecmascript 5中的陣列方法

  1. forEach()——從頭至尾,為每個元素呼叫指定的函式,無法提前終止遍歷,只能try丟擲異常
   function foreach(a,f,t) {
       try { a.forEach(f,t); }
       catch(e) {
           if (e === foreach.break) return;
           else throw e;
       }
   }
   foreach.break = new Error("StopIteration");
複製程式碼
  1. map()——需要有返回值
   a = [1, 2, 3];
   b = a.map(function(x) { return x*x; }); // b is [1, 4, 9]
複製程式碼
  1. fliter()——返回陣列的一個子集,根據傳遞的函式返回的是true或false;會跳過稀疏陣列中缺少的元素,返回的陣列總是稠密的
   a = [5, 4, 3, 2, 1];
   smallvalues = a.filter(function(x) { return x < 3 }); // [2, 1]
   everyother = a.filter(function(x,i) { return i%2==0 }); // [5, 3, 1]
複製程式碼

為了壓縮稀疏陣列的空缺:

   var dense = sparse.filter(function() { return true; });
複製程式碼

壓縮空缺並刪除undefined和null元素

   a = a.filter(function(x) { return x !== undefined && x != null; });
複製程式碼
  1. every()和some()——對陣列元素應用指定的函式進行判定
   a = [1,2,3,4,5];
   a.every(function(x) { return x < 10; }) // => true: all values < 10.
   a.every(function(x) { return x % 2 === 0; }) // => false: not all values even.
複製程式碼
   a = [1,2,3,4,5];
   a.some(function(x) { return x%2===0; }) // => true a has some even numbers.
   a.some(isNaN) // => false: a has no non-numbers.
複製程式碼
  1. reduce()和reduceRight()——使用指定的函式將陣列元素進行組合
   var a = [1,2,3,4,5]
   var sum = a.reduce(function(x,y) { return x+y }, 0); // Sum of values
   var product = a.reduce(function(x,y) { return x*y }, 1); // Product of values
   var max = a.reduce(function(x,y) { return (x>y)?x:y; }); // Largest value
複製程式碼

reduce()第一個引數是執行化簡操作的函式;第二個引數是一個傳遞給函式的初始值 如果省略初始值,將使用陣列的第一個元素作為初始值 空陣列,不帶初始值引數呼叫reduce()將導致型別錯誤異常 reduceRight()是按照陣列索引從高到低處理陣列

   var a = [2, 3, 4]
   // Compute 2^(3^4). Exponentiation has right-to-left precedence
   var big = a.reduceRight(function(accumulator,value) {
   	return Math.pow(value,accumulator);
   })
複製程式碼

union計算陣列並集

   var objects = [{x:1}, {y:2}, {z:3}];
   var merged = objects.reduce(union); // => {x:1, y:2, z:3}
   
   var objects = [{x:1,a:1}, {y:2,a:2}, {z:3,a:3}];
   var leftunion = objects.reduce(union); // {x:1, y:2, z:3, a:1}
   var rightunion = objects.reduceRight(union); // {x:1, y:2, z:3, a:3}
複製程式碼
  1. indexOf()和lastIndexOf()——搜尋陣列中具有給定值的元素
   a = [0,1,2,1,0];
   a.indexOf(1) // => 1: a[1] is 1
   a.lastIndexOf(1) // => 3: a[3] is 1
   a.indexOf(3) // => -1: no element has value 3
   
   // Find all occurrences of a value x in an array a and return an array
   // of matching indexes
   function findall(a, x) {
       var results = [], // The array of indexes we'll return
           len = a.length, // The length of the array to be searched
           pos = 0; // The position to search from
       while(pos < len) { // While more elements to search...
           pos = a.indexOf(x, pos); // Search
           if (pos === -1) break; // If nothing found, we're done.
           results.push(pos); // Otherwise, store index in array
           pos = pos + 1; // And start next search at next element
       }
       return results; // Return array of indexes
   }
複製程式碼

第一個引數是需要搜尋的值 第二個引數是指定陣列的一個索引,從那裡開始搜尋。第二個引數也可以是負數,代表相對陣列末尾的偏移量

陣列型別

  1. ES 5中用Array.isArray()判斷是否為陣列
  2. ES 3中使用以下程式碼檢測:
   var isArray = Function.isArray || function(o) {
       return typeof o === "object" &&
       Object.prototype.toString.call(o) === "[object Array]";
   };
複製程式碼

類陣列物件

  1. 類陣列物件
   var a = {}; // Start with a regular empty object
   // Add properties to make it "array-like"
   var i = 0;
   while(i < 10) {
       a[i] = i * i;
       i++;
   }
   a.length = i;
   // Now iterate through it as if it were a real array
   var total = 0;
   for(var j = 0; j < a.length; j++)
   	total += a[j
複製程式碼
  1. 檢測類陣列物件
   // Determine if o is an array-like object.
   // Strings and functions have numeric length properties, but are
   // excluded by the typeof test. In client-side JavaScript, DOM text
   // nodes have a numeric length property, and may need to be excluded
   // with an additional o.nodeType != 3 test.
   function isArrayLike(o) {
       if (o && // o is not null, undefined, etc.
           typeof o === "object" && // o is an object
           isFinite(o.length) && // o.length is a finite number
           o.length >= 0 && // o.length is non-negative
           o.length===Math.floor(o.length) && // o.length is an integer
           o.length < 4294967296) // o.length < 2^32
       	return true; // Then o is array-like
       else
       	return false; // Otherwise it is not
   }
複製程式碼
  1. 類陣列物件沒有繼承Array.prototype,不能直接呼叫陣列方法,可以用Function.call來呼叫
   var a = {"0":"a", "1":"b", "2":"c", length:3}; // An array-like object
       Array.prototype.join.call(a, "+") // => "a+b+c"
       Array.prototype.slice.call(a, 0) // => ["a","b","c"]: true array copy
       Array.prototype.map.call(a, function(x) {
       return x.toUpperCase();
   }) // => ["A","B","C"]
複製程式碼
  1. 相容
   Array.join = Array.join || function(a,sep) {
   	return Array.prototype.join.call(a,sep);
   };
   Array.slice = Array.slice || function(a,from,to) {
   	return Array.prototype.slice.call(a,from,to);
   };
   Array.map = Array.map || function(a, f, thisArg) {
   	return Array.prototype.map.call(a, f, thisArg);
   }
複製程式碼

作為陣列的字串

  1. 字串的行為類似於只讀的陣列,Array.isArray()會返回false
  2. 陣列方法可以應用到字串上:
   s = "JavaScript"
   Array.prototype.join.call(s, " ") // => "J a v a S c r i p t"
   Array.prototype.filter.call(s, // Filter the characters of the string
       function(x) {
           return x.match(/[^aeiou]/); // Only match nonvowels
       }).join("") // => "JvScrpt"
複製程式碼
  1. 字串只讀,push,sort,reverse和splice在字串上無效

相關文章