百忙之中(闲来无事)想抽点时候好好读一下源码,于是就选了Lodash来写一个系列罢。写了几篇笔记今后发明许多函数大批依靠了内部的基本函数,一次性读完有点贫苦,所以照样决议从基本函数(没有或许很少依靠其他函数)看起。
baseGetTag
baseGetTag
,推断变量范例。由于typeof在面临new Number(1)
这类状况时力有不逮,所以lodash重写了范例推断。 javascript隐秘花圃中也提到了JavaScript 规范库 引荐的是Object.prototype.toString.call(value)
这类体式格局来推断范例,不过lodash显著做的更多,前半段是引荐的体式格局,后半段目测是针对Symbol范例做了优化,具体步骤待研讨,有相识的同砚迎接告诉我。
const objectProto = Object.prototype
const hasOwnProperty = objectProto.hasOwnProperty
const toString = objectProto.toString
const symToStringTag = typeof Symbol != 'undefined'
? Symbol.toStringTag
: undefined
function baseGetTag(value) {
if (value == null) {
return value === undefined
? '[object Undefined]'
: '[object Null]'
}
if (!(symToStringTag && symToStringTag in Object(value))) {
return toString.call(value)
}
const isOwn = hasOwnProperty.call(value, symToStringTag)
const tag = value[symToStringTag]
let unmasked = false
try {
value[symToStringTag] = undefined
unmasked = true
} catch (e) {}
const result = toString.call(value)
if (unmasked) {
if (isOwn) {
value[symToStringTag] = tag
} else {
delete value[symToStringTag]
}
}
return result
}
export default baseGetTag
getTag
getTag
是在baseGetTag
基本上的包装,重要是为了兼容IE 11中的 data views, maps, sets, weak maps
和当Node.js < 6时的promises
,这一点在源码解释中已有表现
import baseGetTag from './baseGetTag.js'
/** `Object#toString` result references. */
const dataViewTag = '[object DataView]'
const mapTag = '[object Map]'
const objectTag = '[object Object]'
const promiseTag = '[object Promise]'
const setTag = '[object Set]'
const weakMapTag = '[object WeakMap]'
/** Used to detect maps, sets, and weakmaps. */
const dataViewCtorString = `${DataView}`
const mapCtorString = `${Map}`
const promiseCtorString = `${Promise}`
const setCtorString = `${Set}`
const weakMapCtorString = `${WeakMap}`
let getTag = baseGetTag
// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in
// Node.js < 6.
if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || (getTag(new Map) != mapTag) || (getTag(Promise.resolve()) != promiseTag) || (getTag(new Set) != setTag) || (getTag(new WeakMap) != weakMapTag)) {
getTag = (value) => {
const result = baseGetTag(value)
const Ctor = result == objectTag
? value.constructor
: undefined
const ctorString = Ctor
? `${Ctor}`
: ''
if (ctorString) {
switch (ctorString) {
case dataViewCtorString:
return dataViewTag
case mapCtorString:
return mapTag
case promiseCtorString:
return promiseTag
case setCtorString:
return setTag
case weakMapCtorString:
return weakMapTag
}
}
return result
}
}
export default getTag
isObjectLike
isObjectLike
, 推断是不是是一个对象
function isObjectLike(value) {
return typeof value == 'object' && value !== null
}
export default isObjectLike
isArguments
isArguments
挪用了getTag
和isObjectLike
用来推断参数是不是是一个Arguments对象。
import getTag from './.internal/getTag.js'
import isObjectLike from './isObjectLike'
function isArguments(value) {
return isObjectLike(value) && getTag(value) == '[object Arguments]'
}
export default isArguments
isFlattenable
isFlattenable
挪用isArguments
来推断是不是为一个Arguments对象或数组或是一个能睁开的Symbol
import isArguments from '../isArguments.js'
const spreadableSymbol = Symbol.isConcatSpreadable
function isFlattenable(value) {
return Array.isArray(value) || isArguments(value) ||
!!(spreadableSymbol && value && value[spreadableSymbol])
}
export default isFlattenable
baseFlatten
baseFlatten
能够睁开数组的n层嵌套(扁平处置惩罚),依靠了isFlattenable
// 例:
baseFlatten([[[1,2,3],[2,2,3]],4,5,6], 2) // => [1, 2, 3, 2, 2, 3, 4, 5, 6]
// isStrict == true
baseFlatten([[1,2,3],[2,2,3],4,5,6], 1, null, true) // => [1, 2, 3, 2, 2, 3]
import isFlattenable from './isFlattenable.js'
function baseFlatten(array, depth, predicate, isStrict, result) {
predicate || (predicate = isFlattenable) // predicate参数兜底
result || (result = []) // 返回新数组
if (array == null) {
return result
}
// 递归挪用自身,严厉形式`isStrict = true`直接退出轮回
for (const value of array) {
if (depth > 0 && predicate(value)) {
if (depth > 1) {
// Recursively flatten arrays (susceptible to call stack limits).
baseFlatten(value, depth - 1, predicate, isStrict, result)
} else {
result.push(...value)
}
} else if (!isStrict) {
result[result.length] = value
}
}
return result
}
export default baseFlatten
isLength
isLength
,推断是不是是一个有用数字
const MAX_SAFE_INTEGER = 9007199254740991 // 最大数
function isLength(value) {
// type是number而且大于即是0且小于即是最大数
return typeof value == 'number' &&
value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER
}
export default isLength
isArrayLike
isArrayLike
, 推断是不是是一个数组,依靠了isLength
import isLength from './isLength.js'
function isArrayLike(value) {
// value不为空,不是function且有length属性
return value != null && typeof value != 'function' && isLength(value.length)
}
export default isArrayLike
isArrayLikeObject
isArrayLikeObject
,推断是不是是一个数组或许对象,依靠了isArrayLike
和isObjectLike
import isArrayLike from './isArrayLike.js'
import isObjectLike from './isObjectLike.js'
function isArrayLikeObject(value) {
return isObjectLike(value) && isArrayLike(value)
}
export default isArrayLikeObject
eq
eq
,推断两个值是不是相称。
function eq(value, other) {
return value === other || (value !== value && other !== other)
}
export default eq
||
前面好明白,推断两个值全等||
背面是为了推断 NaN
例:
const object = { 'a': 1 }
const other = { 'a': 1 }
eq(object, object)
// => true
eq(object, other)
// => false
eq('a', 'a')
// => true
eq('a', Object('a'))
// => false
eq(NaN, NaN)
// => true
assocIndexOf
猎取键值对数组中的“键”的索引。例:
assocIndexOf([[1,2],[3,4],[5,6]], 2) // => -1
assocIndexOf([[1,2],[3,4],[5,6]], 3) // => 1
import eq from '../eq.js'
function assocIndexOf(array, key) {
let { length } = array
while (length--) {
if (eq(array[length][0], key)) {
return length
}
}
return -1
}
export default assocIndexOf