在循环中声明的函数包含对变量的不安全引用 ESLint

Function declared in a loop contains unsafe references to variable(s) ESLint

我得到了以下函数,它接受一个对象和一个词,returns 一个对象,方法是用另一个字符串替换所有出现的传递的词。相同的函数将计算单词被替换的次数,并将其包含在替换的字符串中。

例如,考虑以下内容:

  let noOfReplacements = 0;
  const reg = new RegExp(`\bplease\b`, "gi");

  const data = [
    {
      name: "please, I said please",
      title: "Test One",
      more: [
        {
          name: "another name",
          title: "please write something. I said please."
        }
      ]
    },
    { name: "testTwo", title: "Test Two" },
    { name: "testThree", title: "Test Three" },
    { name: "testFour", title: "Test Four" }
  ];

  const replace = (obj, reg) => {
    for (const key in obj) {
      if (typeof obj[key] === "object" && obj[key] !== null) {
        replace(obj[key], reg);
      } else if (key === "title") {
        obj[key] = obj[key].replace(reg, function () {
          noOfReplacements += 1;
          return `repalced${noOfReplacements}`;
        });
      }
    }
    return obj;
  };

  const result = replace(data, reg)

  console.log("number of replacements", noOfReplacements);
  console.log("result", result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

这很好用。但是,我收到 ESlint 警告:

Function declared in a loop contains unsafe references to variable(s) 'noOfReplacements'

在这种情况下,我如何安全地更新 noOfReplacements

我看过这个 ,但该解决方案的问题是它没有考虑单独的句子和单独替换的单词。所以在上面的例子中,虽然它会成功替换所有的单词,但它只会将计数增加 1,因为两个单词都在相同的 属性 中。因此,noOfReplacements 应为 2 时仍为 1。

您可以简单地按照规则的标题 (no-loop-func) 在循环外声明您的函数,然后在循环中调用它。

const replace = (object, reg) => {
  const incrementAndReplace = () => {
    noOfReplacements += 1;
    return `repalced${noOfReplacements}`;
  };

  for (const key in object) {
    if (typeof object[key] === 'object' && object[key] !== null) {
      replace(object[key], reg);
    } else if (key === 'title') {
      object[key] = object[key].replace(reg, incrementAndReplace);
    }
  }

  return object;
};

let noOfReplacements = 0;
const reg = /\bplease\b/gi;

const data = [
  {
    name: 'please, I said please',
    title: 'Test One',
    more: [
      {
        name: 'another name',
        title: 'please write something. I said please.',
      },
    ],
  },
  {name: 'testTwo', title: 'Test Two'},
  {name: 'testThree', title: 'Test Three'},
  {name: 'testFour', title: 'please Test Four'},
];

const replace = (object, reg) => {
  const incrementAndReplace = () => {
    noOfReplacements += 1;
    return `repalced${noOfReplacements}`;
  };

  for (const key in object) {
    if (typeof object[key] === 'object' && object[key] !== null) {
      replace(object[key], reg);
    } else if (key === 'title') {
      object[key] = object[key].replace(reg, incrementAndReplace);
    }
  }

  return object;
};

replace(data, reg);

console.log('number of replacements', noOfReplacements);
console.log('result', data);

无论如何,我总是会选择一种递归实现的、特定于标题的替换函数对任何外部范围都是不可知的方法。相反,它会 运行 在具有例如特征的绑定引用的上下文中。 a replacementCount 属性 将在内部进行跟踪。更新由 replacer 回调.

处理

下一个提供的递归实现还具有 Array 项目和 Object 条目特定迭代,以便仅处理 object 自己的属性,这与 OP 的 for...in 不同也迭代原型属性的循环。

function recursivelyReplaceTitleAndTrackBoundCount(data, regX) {
  let { replacementCount: count } = this;

  const boundRecursiveReplacer =
    recursivelyReplaceTitleAndTrackBoundCount.bind(this);

  const getTrackedCount = (/*match*/) => `repalced_${ ++count }`;

  if (Array.isArray(data)) {
    data.forEach(dataItem =>
      boundRecursiveReplacer(dataItem, regX)
    );
  } else {
    Object
      .entries(data)
      .forEach(([key, value]) => {
        if (value && (typeof value === 'object')) {

          boundRecursiveReplacer(value, regX);

        } else if ((key === 'title') && regX.test(value)) {

          data[key] = value.replace(regX, getTrackedCount);

          this.replacementCount = count;
        }
      });
  }
}

const data = [{
  name: "please, I said please",
  title: "Test One",
  more: [{
    name: "another name",
    title: "please write something. I said please.",
  }],
}, {
  name: "testTwo",
  title: "Test Two",
  even: {
    some: {
      more: {
        name: "another name",
        title: "please write something. I said please.",
      },
    },
  },
}, {
  name: "testThree",
  title: "Test Three",
}, {
  name: "testFour",
  title: "Test Four, if you ...please?",
}];

const tracker = { replacementCount: 0 };

recursivelyReplaceTitleAndTrackBoundCount
  .call(tracker, data, /\bplease\b/gi);

const { replacementCount } = tracker;

console.log({ data, replacementCount });
.as-console-wrapper { min-height: 100%!important; top: 0; }