lodash的工具方法(三)

_.toArray(value)

将value转换成一个数组。

/**
 * @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从而调用不同不同的方法来换成数组。

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具有默认的迭代器行为。

//默认的迭代器行为
var myIterable = {}
yield 1;
yield 2;
yield 3;

};
[...myIterable] // [1, 2, 3]

了解了上边的相关知识,iteratorToArray就很容易理解了。

/**
* 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.其它的逻辑

  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];
  });
}

_.toPlainObject

转换 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不在就会返回一个新的对象)

keysIn

/**
 * 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

arrayLikeKeys

/**
 * 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。

baseKeysIn

/**
 * 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"]

_.toString

将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

该方法是_.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 + ''

_.toSafeInteger(value)

转换 value 为安全整数。 安全整数可以用于比较和准确的表示。

function toSafeInteger(value) {
  return baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER);
}

baseClamp

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

最普通的一个
301 声望41 粉丝

永远不要做你擅长的事。


引用和评论

0 条评论