Skip to content

Latest commit

 

History

History
111 lines (74 loc) · 4.28 KB

isKey.md

File metadata and controls

111 lines (74 loc) · 4.28 KB

lodash源码分析之isKey

本文为读 lodash 源码的第六十五篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash

gitbook也会同步仓库的更新,gitbook地址:pocket-lodash

依赖

import isSymbol from '../isSymbol.js'

《lodash源码分析之isSymbol》

源码分析

isKey 的作用是用来判断传入的 value 是否为合法的属性名(注意:不是规范中认定的合法属性名,lodash 会做一些收敛),但是在检测的时候会将 lodash 支持的嵌套属性的写法排除,如传入 a.b.c 或者 a[0].b.c 可能会返回 false

源码如下:

const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/
const reIsPlainProp = /^\w*$/
function isKey(value, object) {
  if (Array.isArray(value)) {
    return false
  }
  const type = typeof value
  if (type === 'number' || type === 'boolean' || value == null || isSymbol(value)) {
    return true
  }
  return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
    (object != null && value in Object(object))
}

排除数组

if (Array.isArray(value)) {
  return false
}

如果传入的是数组,在 lodash 中,不会当作是属性名,直接排除,返回 false。但其实我们是可以用数组作为 key 的,用数组作为 key 时,数组会首先会转换成 string 类型,再作为对象的属性。 在 lodashisKey 函数中,不允许这种行为。

常规属性名

const type = typeof value
if (type === 'number' || type === 'boolean' || value == null || isSymbol(value)) {
  return true
}

接下来,检测 value 是否为数字、布尔值、null 值和是否为 symbol 类型,上述类型,除了 symbol 外,作为属性值时,都会隐式转换成 string 类型,也可以作为合法的属性名。而 symboles6 中,本身就允许作为对象的属性,不需要转换成 string 类型。

处理字符串类型

return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
    (object != null && value in Object(object))

现在还剩下字符串和对象没有处理,但是以上的条件中,对象也会隐式转换成字符串来处理,所以这里看字符串的处理即可。

处理单词

const reIsPlainProp = /^\w*$/
reIsPlainProp.test(value)

\w 是匹配a-z、A-Z、0-9,以及下划线的单词字符,resIsPlainProp 是用来匹配包含一个或多个这些字符的单词,也即类似于 a1aba-b 这类的字符串,如果是这些字符串,则返回 true

处理属性路径

const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/
!reIsDeepProp.test(value)

lodash 中,像 a.b.ca[0].b.c 这种可能会被当作属性路径对待,像 get 这些的函数支持传入这样的路径来获取嵌套对象的值。

reIsDeepProp 这个正则比较复杂,主要就是用来匹配这种深层属性路径的,在 isKey 检测时,会将这些字符串排除。

除此之外的字符串,返回的都是 true

本来有这个条件就可以,为什么在这个条件之前还要有 reIsPlainProp.test(value) 这个条件呢?

因为这个正则比较复杂,性能会比较差,所以先匹配 reIsPlainProp 在大部分场景下性能会更加好。

处理属性路径的特例

如果在某些场景中,真的要用属性路径来作为属性名怎么办呢?

这种情况下,使用 isKey 函数时,就需要传入第二个参数 object 了。

object != null && value in Object(object)

如果有传 object,并且 valueobject 的属性名,也会返回 true 。这就解决了属性路径作为属性名的问题。

License

署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)

最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:

作者:对角另一面