翻譯不完整。請協助 翻譯此英文文件

map() 方法會建立一個新的陣列,其內容為原陣列的每一個元素經由回呼函式運算後所回傳的結果之集合。

var numbers = [1, 5, 10, 15];
var doubles = numbers.map(function(x) {
   return x * 2;
});
// doubles is now [2, 10, 20, 30]
// numbers is still [1, 5, 10, 15]

var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
// roots is now [1, 2, 3]
// numbers is still [1, 4, 9]

語法

var new_array = arr.map(function callback(currentValue, index, array) {
    // Return element for new_array
}[, thisArg])

參數

callback
為產生新陣列之元素的回呼函式,可傳入三個參數:
 
currentValue
原陣列目前所迭代處理中的元素。
index
原陣列目前所迭代處理中的元素之索引。
array
呼叫 map 方法的陣列。
thisArg
選擇性的參數。執行 callback 回呼函式的 this 值。

回傳值

一個所有元素皆為回呼函式運算結果的新陣列。

描述

map 會將所有陣列中的元素依序分別傳入一次callback 函式當中,並以此回呼函式每一次被呼叫的回傳值來建構一個新的陣列。callback 函式只會於陣列目前迭代之索引有指派值時(包含 undefined)被調用,而在該陣列索引沒有元素時(即未被設定的索引:已被刪除或從未被賦值)並不會呼叫回呼函式。

callback 函式於被調用時會傳入三個參數:元素值、元素之索引、以及被迭代的陣列物件。

若有提供 thisArg 參數予 map 方法,thisArg 將會被當作回呼函式的 this 值,否則 this 會是 undefinedcallback 的最終 this 值是依據函式的 this 規則來決定。

map 不會修改呼叫它的原始陣列(雖然在 callback 執行時有可能會這麼做)。

map 方法所回傳之新陣列的範圍,於 callback 函式第一次被調用之前就已經被設定。而在呼叫 map 之後才加至原始陣列中的元素,將不會傳入 callback 當中。假如原始陣列中元素的值改變了,則 callback 得到此元素的值將會是 map 傳入元素當下的值。而在呼叫 map 之後、且於被 map 傳入 callback 之前就被刪除的原始陣列元素,並不會被 map 迭代到。

依據規範中定義的演算法,若呼叫 map 方法的原始陣列為一稀疏陣列,則回傳的新陣列也會是在同樣索引中留空的稀疏陣列。

範例

把一個數字陣列轉換成對應的開根號後的數字陣列

以下的程式碼把一個數字陣列(array of numbers) 轉換成一個 新的以該數字陣列裡的一個個數做開根號計算的數字陣列.

var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt); //map會return一個新的array
// roots 現在是 [1, 2, 3]
/* numbers 還是 [1, 4, 9],這證明了map()不會去變動到numbers的值 
   ,map內部是做了immutable的機制,Array.prototype底下的這些高階函式
   大多都具有這樣函數式編程裡非常注重的特性 - immutable,不會去改變資料
   來源本身原有的值 
*/ 

使用 map 將陣列中的物件變更格式

以下程式碼取出一陣列,將其中物件變更格式後建立為一個新的陣列並傳回。

var kvArray = [{key: 1, value: 10}, 
               {key: 2, value: 20}, 
               {key: 3, value: 30}];

var reformattedArray = kvArray.map(function(obj) { 
   var rObj = {};
   rObj[obj.key] = obj.value;
   return rObj;
});

// reformattedArray 現在是 [{1: 10}, {2: 20}, {3: 30}], 

// kvArray 仍然是: 
// [{key: 1, value: 10}, 
//  {key: 2, value: 20}, 
//  {key: 3, value: 30}]

使用帶參數的函式將一數字陣列進行對應

以下程式碼示範如何使用帶有一個參數的函式來操作 map。這個參數會自動地逐一取出原始陣列中各個元素來使用。

var numbers = [1, 4, 9];
var doubles = numbers.map(function(num) {
  return num * 2;
});

// doubles 現在是 [2, 8, 18]
// numbers 仍然是 [1, 4, 9]

使用 map 於泛型陣列

以下範例示範如何將一個 String 陣列轉換為 byte 陣列:

var map = Array.prototype.map;
var a = map.call('Hello World', function(x) { 
  return x.charCodeAt(0); 
});
// a 現在等於 [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]

Using map generically querySelectorAll

This example shows how to iterate through a collection of objects collected by querySelectorAll. In this case we get all selected options on the screen and printed on the console:

var elems = document.querySelectorAll('select option:checked');
var values = Array.prototype.map.call(elems, function(obj) {
  return obj.value;
});

Easier way would be using Array.from() method.

Using map to reverse a string

var str = '12345';
Array.prototype.map.call(str, function(x) {
  return x;
}).reverse().join(''); 

// Output: '54321'
// Bonus: use '===' to test if original string was a palindrome

Easier way would be using String.split() method (see Reversing a String using split() example).

Tricky use case

(inspired by this blog post)

It is common to use the callback with one argument (the element being traversed). Certain functions are also commonly used with one argument, even though they take additional optional arguments. These habits may lead to confusing behaviors.

// Consider:
['1', '2', '3'].map(parseInt);
// While one could expect [1, 2, 3]
// The actual result is [1, NaN, NaN]

// parseInt is often used with one argument, but takes two.
// The first is an expression and the second is the radix.
// To the callback function, Array.prototype.map passes 3 arguments: 
// the element, the index, the array
// The third argument is ignored by parseInt, but not the second one,
// hence the possible confusion. See the blog post for more details

function returnInt(element) {
  return parseInt(element, 10);
}

['1', '2', '3'].map(returnInt); // [1, 2, 3]
// Actual result is an array of numbers (as expected)

// Same as above, but using the concise arrow function syntax
['1', '2', '3'].map( str => parseInt(str) );

// A simpler way to achieve the above, while avoiding the "gotcha":
['1', '2', '3'].map(Number); // [1, 2, 3]
// but unlike `parseInt` will also return a float or (resolved) exponential notation:
['1.1', '2.2e2', '3e300'].map(Number); // [1.1, 220, 3e+300]

Polyfill

map was added to the ECMA-262 standard in the 5th edition; as such it may not be present in all implementations of the standard. You can work around this by inserting the following code at the beginning of your scripts, allowing use of map in implementations which do not natively support it. This algorithm is exactly the one specified in ECMA-262, 5th edition, assuming Object, TypeError, and Array have their original values and that callback.call evaluates to the original value of Function.prototype.call.

// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.io/#x15.4.4.19
if (!Array.prototype.map) {

  Array.prototype.map = function(callback/*, thisArg*/) {

    var T, A, k;

    if (this == null) {
      throw new TypeError('this is null or not defined');
    }

    // 1. Let O be the result of calling ToObject passing the |this| 
    //    value as the argument.
    var O = Object(this);

    // 2. Let lenValue be the result of calling the Get internal 
    //    method of O with the argument "length".
    // 3. Let len be ToUint32(lenValue).
    var len = O.length >>> 0;

    // 4. If IsCallable(callback) is false, throw a TypeError exception.
    // See: http://es5.github.com/#x9.11
    if (typeof callback !== 'function') {
      throw new TypeError(callback + ' is not a function');
    }

    // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
    if (arguments.length > 1) {
      T = arguments[1];
    }

    // 6. Let A be a new array created as if by the expression new Array(len) 
    //    where Array is the standard built-in constructor with that name and 
    //    len is the value of len.
    A = new Array(len);

    // 7. Let k be 0
    k = 0;

    // 8. Repeat, while k < len
    while (k < len) {

      var kValue, mappedValue;

      // a. Let Pk be ToString(k).
      //   This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the HasProperty internal 
      //    method of O with argument Pk.
      //   This step can be combined with c
      // c. If kPresent is true, then
      if (k in O) {

        // i. Let kValue be the result of calling the Get internal 
        //    method of O with argument Pk.
        kValue = O[k];

        // ii. Let mappedValue be the result of calling the Call internal 
        //     method of callback with T as the this value and argument 
        //     list containing kValue, k, and O.
        mappedValue = callback.call(T, kValue, k, O);

        // iii. Call the DefineOwnProperty internal method of A with arguments
        // Pk, Property Descriptor
        // { Value: mappedValue,
        //   Writable: true,
        //   Enumerable: true,
        //   Configurable: true },
        // and false.

        // In browsers that support Object.defineProperty, use the following:
        // Object.defineProperty(A, k, {
        //   value: mappedValue,
        //   writable: true,
        //   enumerable: true,
        //   configurable: true
        // });

        // For best browser support, use the following:
        A[k] = mappedValue;
      }
      // d. Increase k by 1.
      k++;
    }

    // 9. return A
    return A;
  };
}

規範

Specification Status Comment
ECMAScript 5.1 (ECMA-262)
The definition of 'Array.prototype.map' in that specification.
Standard Initial definition. Implemented in JavaScript 1.6.
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Array.prototype.map' in that specification.
Standard  
ECMAScript Latest Draft (ECMA-262)
The definition of 'Array.prototype.map' in that specification.
Living Standard  

瀏覽器相容性

FeatureChromeEdgeFirefoxInternet ExplorerOperaSafari
Basic Support (Yes) (Yes)1.59 (Yes) (Yes)
FeatureAndroidChrome for AndroidEdge mobileFirefox for AndroidIE mobileOpera AndroidiOS Safari
Basic Support (Yes) (Yes) (Yes)1 (Yes) (Yes) (Yes)

參見

文件標籤與貢獻者

標籤: 
 此頁面的貢獻者: jackblackevo, jWorker, akari0624
 最近更新: jackblackevo,