將value轉換成一個數組。javascript
/** * @example * * _.toArray({ 'a': 1, 'b': 2 }); * // => [1, 2] * * _.toArray('abc'); * // => ['a', 'b', 'c'] * * _.toArray(1); * // => [] * * _.toArray(null); * // => [] */ function toArray(value) { if (!value) { return []; } if (isArrayLike(value)) { return isString(value) ? stringToArray(value) : copyArray(value); } if (iteratorSymbol && value[iteratorSymbol]) { return iteratorToArray(value[iteratorSymbol]()); } var tag = getTag(value), func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); return func(value); }
1.isArrayLike
,字符串也是能夠經過這個判斷的。因此內部又判斷是不是字符串。
2。字符串的話,調用stringToArray
。字符串中有區分了Unicode
從而調用不一樣不一樣的方法來換成數組。java
function stringToArray(string) { return hasUnicode(string) ? unicodeToArray(string) : asciiToArray(string); }
3.數組的話,調用copyArray
,一目瞭然。遍歷source,將source中的元素copy到array中並返回數組
function copyArray(source, array) { var index = -1, length = source.length; array || (array = Array(length)); while (++index < length) { array[index] = source[index]; } return array; }
4.到了iteratorSymbol&& value[iteratorSymbol]
安全
在這裏,咱們先補充一點Symbol.iterator的知識
工具
Symbol.iterator 爲每個對象定義了默認的迭代器。該迭代器能夠被 for...of 循環使用。Array,TypedArray,String,Map,Set具備默認的迭代器行爲。this
//默認的迭代器行爲 var myIterable = {}
yield 1; yield 2; yield 3;
};
[...myIterable] // [1, 2, 3]spa
瞭解了上邊的相關知識,iteratorToArray
就很容易理解了。prototype
/** * terator.next() 返回的是一個對象{value: xxx,done:false | true} * 若是done爲true證實已經結束 */ function iteratorToArray(iterator) { var data, result = []; while (!(data = iterator.next()).done) { result.push(data.value); } return result; }
5.其它的邏輯code
var tag = getTag(value), func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); return func(value); /** * Converts `set` to an array of its values. * 將set轉換成values數組。 * @private * @param {Object} set The set to convert. * @returns {Array} Returns the values. */ function setToArray(set) { var index = -1, result = Array(set.size); // 獲取set的長度 set.forEach(function(value) { result[++index] = value; // 長度push到result的數組裏 }); return result; } function values(object) { // keys方法,獲取可列舉的屬性(非prototype) return object ? baseValues(object, keys(object)) : []; } // 獲取object對應key上的值,,並返回 function baseValues(object, props) { return arrayMap(props, function(key) { return object[key]; }); }
轉換 value 爲普通對象。 包括繼承的可枚舉屬性。
/** * @returns {Object} Returns the converted plain object. * @example * * function Foo() { * this.b = 2; * } * * Foo.prototype.c = 3; * * _.assign({ 'a': 1 }, new Foo); * // => { 'a': 1, 'b': 2 } * * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); * // => { 'a': 1, 'b': 2, 'c': 3 } */ function toPlainObject(value) { return copyObject(value, keysIn(value)); }
copyObject
咱們在baseAssign中有過描述。它將value的keys,copy到第三個參數object上。(object不在就會返回一個新的對象)orm
/** * Creates an array of the own and inherited enumerable property names of `object`. * 建立一個數組成員爲自身的屬性,或者繼承的可枚舉的屬性。 * **Note:** Non-object values are coerced to objects. 非對象會被強制轉換爲對象 * * @static * @memberOf _ * @since 3.0.0 * @category Object * @param {Object} object The object to query. * @returns {Array} Returns the array of property names. * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.keysIn(new Foo); * // => ['a', 'b', 'c'] (iteration order is not guaranteed) */ function keysIn(object) { return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);// 類數組和不一樣的走兩種。 }
lodash對於arraylike
,首先不是數組,而且value。length
大於等於0,小於 Number.MAX_SAFE_INTEGER
.
若是是類數組,會調用arrayLikeKeys(object, true)
返回keys。非類數組調用baseKeysIn
/** * Creates an array of the enumerable property names of the array-like `value`. * 建立並返回一個數組。成員是類數組屬性名。 * @private * @param {*} value The value to query. * @param {boolean} inherited Specify returning inherited property names. * @returns {Array} Returns the array of property names. */ function arrayLikeKeys(value, inherited) { // Safari 8.1 makes `arguments.callee` enumerable in strict mode. // Safari 9 makes `arguments.length` enumerable in strict mode. /*數組等格式,經過baseTimes,返回一個數組,經過string轉換成字符串["0","1",...]*/ var result = (isArray(value) || isArguments(value)) ? baseTimes(value.length, String) : []; var length = result.length, skipIndexes = !!length; // value數組狀況下,這裏爲true,isIndex一般返回true,不會走到push這裏 || value字符串這裏爲false,,isIndex一般返回false。,字符串會走到push這裏。 for (var key in value) { // case0 -若是是繼承 或者 這個,value沒有key這個屬性。 // case1 - key不能是length屬性,好比argument有length這個屬性,是不能push到返回的。 // isIndex返回它是不是一個類數組的key,若是是就須要返回的。 if ((inherited || hasOwnProperty.call(value, key)) && !(skipIndexes && (key == 'length' || isIndex(key, length)))) { result.push(key); } } return result; } // - 這裏調用時,iteratee使用的是String,將n轉成字符串類型 function baseTimes(n, iteratee) { // n若是爲4,iteratee => String, => ["0","1","2","3"] var index = -1, result = Array(n); while (++index < n) { result[index] = iteratee(index); } return result; } /** * value是不是一個有效的array-like的index */ function isIndex(value, length) { length = length == null ? MAX_SAFE_INTEGER : length; return !!length && (typeof value == 'number' || reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length); } // (typeof value == 'number' || reIsUint.test(value)) value必須是number 或者"012313"這種。 //(value > -1 && value % 1 == 0 && value < length) value必須是大於-1的整數,並且要小於length。
/** * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. * `_.keysIn`的基本實現,它不將稀疏數組視爲密集。 * @private * @param {Object} object The object to query. * @returns {Array} Returns the array of property names. */ function baseKeysIn(object) { if (!isObject(object)) { return nativeKeysIn(object); } var isProto = isPrototype(object), result = []; for (var key in object) { if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { // key若是是'constructor'這裏避免,自身有了一個本身定義的constructor,只有這種狀況下,咱們會返回constructor result.push(key); } } return result; }
這裏的if判斷相對簡單些。key等於constructor
這種狀況,咱們要排除自身未重寫這個屬性。
以下,會返回
function Foo() { this.a = 1; this.b = 2; this.constructor=3; } Foo.prototype.c = 3; (function (){ console.log(keysIn( new Foo() )) })() // => Array(4) ["a", "b", "constructor", "c"]
將value轉成字符串。若是value是null或者undefined返回空字符串。-0 將被轉換爲字符串"-0"。
/** * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to process. * @returns {string} Returns the string. * @example * * _.toString(null); * // => '' * * _.toString(-0); * // => '-0' * * _.toString([1, 2, 3]); * // => '1,2,3' */ function toString(value) { return value == null ? '' : baseToString(value); }
該方法是_.baseString
的基礎實現,它不會將nullish值轉換爲空字符串。
function baseToString(value) { // Exit early for strings to avoid a performance hit in some environments. if (typeof value == 'string') { return value; } if (isSymbol(value)) { return symbolToString ? symbolToString.call(value) : ''; } var result = (value + ''); // 對象 =>[object object], [1,2,3] => "1,2,3" return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; }
(result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
,容許-0
,只value爲-0
時,返回-0
,其它狀況返回result = value + ''
轉換 value 爲安全整數。 安全整數能夠用於比較和準確的表示。
function toSafeInteger(value) { return baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER); }
The base implementation of _.clamp
which doesn't coerce arguments.
該方法對number的最大值最小值設定了範圍,超出就返回邊界值。
function baseClamp(number, lower, upper) { if (number === number) { // not NaN if (upper !== undefined) { // number = number <= upper ? number : upper; } if (lower !== undefined) { number = number >= lower ? number : lower; } } return number; }