将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; }