问答

[已解决]Lodash源码之isFlattenable的一个疑问

作者:admin 2021-09-24 我要评论

业务背景 看他这个源码,感觉是个bug,但是这个库怎么会有bug呢,肯定是自己哪里搞错了,但实在是不知道错在哪儿 疑问 baseFlatten 函数的一个参数 predicate 默认值...

在说正事之前,我要推荐一个福利:你还在原价购买阿里云、腾讯云、华为云服务器吗?那太亏啦!来这里,新购、升级、续费都打折,能够为您省60%的钱呢!2核4G企业级云服务器低至69元/年,点击进去看看吧>>>)

业务背景

看他这个源码,感觉是个bug,但是这个库怎么会有bug呢,肯定是自己哪里搞错了,但实在是不知道错在哪儿

疑问

  • baseFlatten函数的一个参数predicate默认值是一个函数isFlattenable
  • isFlattenable通过判断数组/类数组/Symbol.isConcatSpreadable来确定对象是否可以被解构...

但是

复现

var b = [2, 3];
console.log([].push(...b)); // => [2, 3];
b[Symbol.isConcatSpreadable] = false;
console.log([].push(...b)); // => [2, 3]

源代码
https://github.com/ranwawa/lo...

isFlattenable

import isArguments from '../isArguments.js';
const spreadableSymbol = Symbol.isConcatSpreadable;

function isFlattenable(value) {
  return Array.isArray(value) || isArguments(
    value) || !!(value && value[spreadableSymbol]);
}

baseFlatten
注意倒数第7行



// 深度合并数组的操作
function baseFlatten(array, depth, predicate, isStrict, result) {
  predicate || (predicate = isFlattenable)
  result || (result = [])

  if (array == null) {
    return result
  }

  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 {
        // 即使value的Symbol.isConcatSpreadable为false,也可以被解构啊
        result.push(...value)
      }
    } else if (!isStrict) {
      result[result.length] = value
    }
  }
  return result
}

问题

我是直接看的master分支,难道是因为我看的分支出错的原因?

###

因为 isFlattenable 是给 flatten 族函数用的。而 flatten 的实现是按照 tc39/flat 提案实现的,在规范中 flat 中并没有使用 @@iterator

有一个非常简单的解释:因为字符串也是可迭代的。比如下面代码:

['hello', 'world'].flat()

如果输出的结果是 ['h', 'e', 'l', 'l', ...] 是不是很怪异。

因为 Array 的大多数方法的出现都比 @@iterator 要早,所以如果你去看数组函数,Array.from 可能是目前唯一一个是用了 @@iterator 的函数。

所以,这个函数没有 bug 吗?并不是。

这个函数的实现和规范并不兼容,但是问题不是在于 @@iterator,而是在于 @@isConcatSpreadable。根据规范,flat 函数是不检查 @@isConcatSpreadable 的。

官方的意见是,我们是按照 tc39/flat 提案实现的这个函数,但是后来提案变了。

如果 lodash 改变了这个函数,就会导致一个 break change。

如果你真想研究规范是如何用 js 实现的,推荐看看 core-js 源码,真是教科书式的源码。而 lodash 毕竟是第三方工具库,看 lodash 源码就先忽略规范,只关注他的奇技淫巧就够了。

###

能解构不代表一定要展开。策略问题,默认仅展开数组拼接(concat)时会展开的那些元素。如果要把所有能展开的全部展开,可以自定义判断函数。

版权声明:本文转载自网络,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本站转载出于传播更多优秀技术知识之目的,如有侵权请联系QQ/微信:153890879删除

相关文章
  • [已解决]Lodash源码之isFlattenable的

    [已解决]Lodash源码之isFlattenable的

  • sql,同表关联,如何将查询结果在一行

    sql,同表关联,如何将查询结果在一行

  • Mysql唯一约束字段某个值删除后再添加

    Mysql唯一约束字段某个值删除后再添加

  • javascript事件流的一个问题

    javascript事件流的一个问题

腾讯云代理商
海外云服务器