lodash里的toPairsIn方法实现

265 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情

前言

lodash里的toPairsIn方法可以创建一个object对象自身和继承的可枚举属性的键值对数组。这个数组可以通过_.fromPairs撤回。如果object 是 map 或 set,将返回其条目。

使用如下:

function Foo() {
  this.a = 1;
  this.b = 2;
}
 
Foo.prototype.c = 3;
 
_.toPairsIn(new Foo);
// => [['a', 1], ['b', 2], ['c', 3]]

在上篇文章《 lodash里的toLength和toPairs 》中我们了解到toPairs的实现,在实现上其借助了createToPairs工厂函数。

toPairsIn在实现上也将借助该方法,并且将借助另一个封装方法,keysIn方法。

keysIn

keysIn方法是lodash对外导出的方法,该方法创建一个 object 自身 和 继承的可枚举属性名为数组。

使用如下:

function Foo() {
  this.a = 1;
  this.b = 2;
}
 
Foo.prototype.c = 3;
 
_.keysIn(new Foo);
// => ['a', 'b', 'c'] (iteration order is not guaranteed)

keysIn方法实现上,通过isArray方法判断参数是否是数组,是的话调用arrayLikeKeys方法,否则调用baseKeysIn方法。

源码如下:

import arrayLikeKeys from './_arrayLikeKeys.js';
import baseKeysIn from './_baseKeysIn.js';
import isArrayLike from './isArrayLike.js';

function keysIn(object) {
  return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
}

arrayLikeKeys

arrayLikeKeys方法是一个内部方法,该方法返回属性名称的数组。其中,该方法接收两个参数,第一个参数是源数据,第二个参数表示是否继承指定返回继承的属性名称。

实现的处理逻辑如下:

  • 先对参数进行初始化判断,如果是数组类型、Argument类型、Buffer类型、typeArray类型,会调用baseTimes方法,否则赋值为空数组,然后将结果赋值给result变量。
  • 其次进行for in遍历,不满足条件的话在遍历中不处理,如果满足的话,会讲遍历中的keypush到初始化的结果上。
  • 返回result结果。
import baseTmes from './_baseTimes.js';
import isArguments from './isArguments.js';s
import isArray from './isArray.js';
import isBuffer from './isBuffer.js';
import isIndex from './_isIndex.js';
import isTypedArray from './isTypedArray.js';

var objectProto = Object.prototype;

var hasOwnProperty = objectProto.hasOwnProperty;

function arrayLikeKeys(value, inherited) {
  var isArr = isArray(value),
      isArg = !isArr && isArguments(value),
      isBuff = !isArr && !isArg && isBuffer(value),
      isType = !isArr && !isArg && !isBuff && isTypedArray(value),
      skipIndexes = isArr || isArg || isBuff || isType,
      result = skipIndexes ? baseTimes(value.length, String) : [],
      length = result.length;

  for (var key in value) {
    if ((inherited || hasOwnProperty.call(value, key)) &&
        !(skipIndexes && (
           // Safari 9有可枚举的参数。严格模式下的“长度”。
           key == 'length' ||
           // Node 0.10在缓冲区上具有可枚举的非索引属性
           (isBuff && (key == 'offset' || key == 'parent')) ||
           // PhantomJS 2在类型化数组上具有可枚举的非索引属性
           (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
           // 跳过索引属性
           isIndex(key, length)
        ))) {
      result.push(key);
    }
  }
  return result;
}

baseTimes

baseTimes 是一个内部方法,该方法可以返回一个数组。baseTimes方法的第一个参数是迭代的次数,第二个参数是每次迭代时调用的方法。

function baseTimes(n, iteratee) {
  var index = -1,
      result = Array(n);

  while (++index < n) {
    result[index] = iteratee(index);
  }
  return result;
}

baseKeysIn

baseKeysIn方法是keysIn 的基本实现,它不会将稀疏数组视为密集数组,实现上借助isObject 判断对象类型,借助isPrototype 方法判断是否是原型对象,该方法返回属性名称的数组。

实现的处理逻辑如下:

  • 如果不是参数不是对象,直接返回nativeKeysIn的调用结果。
  • 通过for in循环遍历参数,在每一次循环中判断,只有参数不是某一个原型对象时才输出该参数对象的每一个键,其他情况则输出空数组。
import isObject from './isObject.js';
import isPrototype from './_isPrototype.js';
import nativeKeysIn from './_nativeKeysIn.js';

var objectProto = Object.prototype;

var hasOwnProperty = objectProto.hasOwnProperty;

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)))) {
      result.push(key);
    }
  }
  return result;
}

isPrototype

isPrototype方法是lodash里的一个内部方法,该方法主要检查参数是否可能是原型对象。

var objectProto = Object.prototype;

function isPrototype(value) {
  var Ctor = value && value.constructor,
      proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;

  return value === proto;
}

nativeKeysIn

nativeKeysIn是lodash里的一个内部方法,该方法类似于Object.keys可获得一组包含对象的键的数组。

function nativeKeysIn(object) {
  var result = [];
  if (object != null) {
    for (var key in Object(object)) {
      result.push(key);
    }
  }
  return result;
}

toPairsIn

toPairsIn方法实现上主要借助copyObject工厂函数和keysIn方法。 源码如下:

import createToPairs from './_createToPairs.js';
import keysIn from './keysIn.js';

var toPairsIn = createToPairs(keysIn);

小结

本篇章我们认识了keysIn方法和toPairsIn方法的实现,其中toPairsIn方法的实现依赖keysIn方法和createToPairs工厂函数。

在实现keysIn过程中我们也认识了baseTimes和baseKeysIn等内部方法的实现,了解源码的过程中关注其内部封装及依赖的方法实现。