'use strict'; var iteratorSymbol = require('es6-symbol').iterator , isArguments = require('../../function/is-arguments') , isFunction = require('../../function/is-function') , toPosInt = require('../../number/to-pos-integer') , callable = require('../../object/valid-callable') , validValue = require('../../object/valid-value') , isString = require('../../string/is-string') , isArray = Array.isArray, call = Function.prototype.call , desc = { configurable: true, enumerable: true, writable: true, value: null } , defineProperty = Object.defineProperty; module.exports = function (arrayLike/*, mapFn, thisArg*/) { var mapFn = arguments[1], thisArg = arguments[2], Constructor, i, j, arr, l, code, iterator , result, getIterator, value; arrayLike = Object(validValue(arrayLike)); if (mapFn != null) callable(mapFn); if (!this || (this === Array) || !isFunction(this)) { // Result: Plain array if (!mapFn) { if (isArguments(arrayLike)) { // Source: Arguments l = arrayLike.length; if (l !== 1) return Array.apply(null, arrayLike); arr = new Array(1); arr[0] = arrayLike[0]; return arr; } if (isArray(arrayLike)) { // Source: Array arr = new Array(l = arrayLike.length); for (i = 0; i < l; ++i) arr[i] = arrayLike[i]; return arr; } } arr = []; } else { // Result: Non plain array Constructor = this; } if (!isArray(arrayLike)) { if ((getIterator = arrayLike[iteratorSymbol]) !== undefined) { // Source: Iterator iterator = callable(getIterator).call(arrayLike); if (Constructor) arr = new Constructor(); result = iterator.next(); i = 0; while (!result.done) { value = mapFn ? call.call(mapFn, thisArg, result.value, i) : result.value; if (!Constructor) { arr[i] = value; } else { desc.value = value; defineProperty(arr, i, desc); } result = iterator.next(); ++i; } l = i; } else if (isString(arrayLike)) { // Source: String l = arrayLike.length; if (Constructor) arr = new Constructor(); for (i = 0, j = 0; i < l; ++i) { value = arrayLike[i]; if ((i + 1) < l) { code = value.charCodeAt(0); if ((code >= 0xD800) && (code <= 0xDBFF)) value += arrayLike[++i]; } value = mapFn ? call.call(mapFn, thisArg, value, j) : value; if (!Constructor) { arr[j] = value; } else { desc.value = value; defineProperty(arr, j, desc); } ++j; } l = j; } } if (l === undefined) { // Source: array or array-like l = toPosInt(arrayLike.length); if (Constructor) arr = new Constructor(l); for (i = 0; i < l; ++i) { value = mapFn ? call.call(mapFn, thisArg, arrayLike[i], i) : arrayLike[i]; if (!Constructor) { arr[i] = value; } else { desc.value = value; defineProperty(arr, i, desc); } } } if (Constructor) { desc.value = null; arr.length = l; } return arr; };