lodash里的is系列(三)

153 阅读4分钟

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

前言

本篇章主要讲解lodash里的三个内部方法,分别为isKey、isKeyable和isTypeArray,其中isTypeArray方法在实现上会借助内部封装的几个方法,在这里我们也会顺带讲解其源码实现。

isKey

isKey方法是lodash里内部使用的方法,该方法主要是检查参数value是否是属性名称而不是属性路径。

传参说明:

第一个参数为value,第二个参数为查询键的对象。如果 value 是属性名称,则返回 true,否则返回 false

使用说明:

isKey('a')
// => true

isKey('a.b')
// => false

isKey('a?.b')
// => false

isKey('a!.b')
// => false

isKey("a?.b!.c")
// => false

该方法在实现上借助isArray 方法判断键值value是否属于非数组,而isSymbol则判断键值value是否属于symbol类型的数据。

第一个参数value作为键值可以是number类型、symbol类型、boolean类型、或者可为null,一般情况第一个参数value可为string类型,但是为了排除是链式调用的情况,即排除属性路径,所以需要对参数value进行正则判断。

reIsDeepProp 匹配链式调用的字符串,而reIsPlainProp 则是匹配以单词开头和结尾的有效值。

源码如下:

import isArray from './isArray.js';
import isSymbol from './isSymbol.js';

var reIsDeepProp = /.|[(?:[^[]]*|(["'])(?:(?!\1)[^\]|\.)*?\1)]/,
    reIsPlainProp = /^\w*$/;

function isKey(value, object) {
  if (isArray(value)) {
    return false;
  }
  var type = typeof value;
  if (type == 'number' || type == 'symbol' || type == 'boolean' ||
      value == null || isSymbol(value)) {
    return true;
  }
  return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
    (object != null && value in Object(object));
}

isKeyable

isKeyable方法主要是检查参数value 是否适合用作唯一对象键。isKeyable方法在使用上比isKey方法宽松,对于形如链式调用的字符串属于合法的范围。

使用如下:

isKeyable('a')
// => true

isKeyable()
// => false

isKeyable([])
// => false

isKeyable('a.b')
// => true

isKeyable('a?.b')
// => true

isKeyable在是实现上使用typeof,对于string、number、symbol、boolean、null等基本数据类型验证通过,但是对于string类型,其值不能等于__proto__,因为由于原型链查找,该属性会覆盖查找。

源码如下:

function isKeyable(value) {
  var type = typeof value;
  return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
    ? (value !== '__proto__')
    : (value === null);
}

isTypeArray

isTypeArray方法是内部使用的方法,该方法主要是检查参数value是否为类型化的数组。

使用如下:

_.isTypedArray(new Uint8Array);
// => true

_.isTypedArray([]);
// => false

_.isTypedArray({})
// => false

该方法实现上需要借助内部封装的baseIsTypedArray方法、baseUnary方法和nodeUtil变量。 让我们先看看各个工具方法的实现。

baseIsTypedArray

baseIsTypedArray方法是isTypeArray方法的核心,内部实现需要借助baseGetTag方法获取数据的类型标签,需要借助isLength方法判断目标数据的length是否属于有效的长度,通过isObjectLike方法判断目标数据是否属于类对象。

在实现上,通过声明各种类型标签去判断。 源码如下:

import baseGetTag from './_baseGetTag.js';
import isLength from './isLength.js';
import isObjectLike from './isObjectLike.js';

var argsTag = '[object Arguments]',
    arrayTag = '[object Array]',
    boolTag = '[object Boolean]',
    dateTag = '[object Date]',
    errorTag = '[object Error]',
    funcTag = '[object Function]',
    mapTag = '[object Map]',
    numberTag = '[object Number]',
    objectTag = '[object Object]',
    regexpTag = '[object RegExp]',
    setTag = '[object Set]',
    stringTag = '[object String]',
    weakMapTag = '[object WeakMap]';

var arrayBufferTag = '[object ArrayBuffer]',
    dataViewTag = '[object DataView]',
    float32Tag = '[object Float32Array]',
    float64Tag = '[object Float64Array]',
    int8Tag = '[object Int8Array]',
    int16Tag = '[object Int16Array]',
    int32Tag = '[object Int32Array]',
    uint8Tag = '[object Uint8Array]',
    uint8ClampedTag = '[object Uint8ClampedArray]',
    uint16Tag = '[object Uint16Array]',
    uint32Tag = '[object Uint32Array]';

var typedArrayTags = {};
typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
typedArrayTags[uint32Tag] = true;
typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
typedArrayTags[errorTag] = typedArrayTags[funcTag] =
typedArrayTags[mapTag] = typedArrayTags[numberTag] =
typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
typedArrayTags[setTag] = typedArrayTags[stringTag] =
typedArrayTags[weakMapTag] = false;

function baseIsTypedArray(value) {
  return isObjectLike(value) &&
    isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
}

isTypeArray

借助封装的baseIsTypedArray方法即可实现isTypedArray方法,为了兼容不同环境下的方法调用,通过nodeUtil变量判断宿主环境并获取node环境工具方法中的isTypedArray方法,通过baseUnary的调用返回一个新的函数方法。

import baseIsTypedArray from './_baseIsTypedArray.js';
import baseUnary from './_baseUnary.js';
import nodeUtil from './_nodeUtil.js';

var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;

var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;

小结

本篇章我们主要讲解isKey、isKeyable和isTypeArray方法,其中通过isTypeArray方法我们认识了baseUnary方法、nodeUtil变量以及核心实现baseIsTypedArray方法。

可见lodash为了兼容版本以及环境,内部做了多数封装和的兼容判断。