【问题标题】:Why join() does not remove empty strings from array in javascript?为什么join()不会从javascript中的数组中删除空字符串?
【发布时间】:2021-05-20 09:34:19
【问题描述】:

这是一个简单的reactjs 项目的测试用例,在这种情况下,我尝试针对textContent 进行测试。

container 只是一个div 元素,它是我们的渲染目标。而Simple 是返回反应组件的函数。

textContent 是字符串,但分配的内存长度和“逻辑”内存的长度不同。所以,首先我尝试使用trim(),它不起作用并认为它很奇怪,然后我尝试使用split()join(),这不是最好的解决方案,但它应该可以工作。

it("simple test", function () {
  act(function () {
    const Simple = Template.bind({});
    render(Simple(props), container);
  });
  let received = container.textContent.split(""); // ["A", "B", "C", "", ""]
  received = received.join(""); // "ABC"
  console.log(received.length); // but length is still 5
  let expected = values[0].name; // "ABC", with length 3

  expect(received).toBe(expected); // in conclusion, test case fails
});

编辑:可重现的示例

两个文件都在同一个目录中。

// CurrencyTextField.test.js

import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";

import CurrencyTextField from "./CurrencyTextField";

let container = null;
let Template;
let currencies;
let props;
beforeEach(function () {
  container = document.createElement("div");
  document.body.appendChild(container);

  props = {
    currencies,
    current: currencies[0],
    handleValueChange: undefined,
    handleCurrencyChange: undefined,
    style: {
      labelWidth: 50,
      classes: { formControl: "" },
    },
    error: { isError: false, errorText: "" },
  };
});

afterEach(function () {
  unmountComponentAtNode(container);
  container.remove();
  container = null;
});

beforeAll(() => {
  Template = (args) => <CurrencyTextField {...args} />;
  currencies = [
    {
      name: "USD",
      flag: "",
      symbo: "$",
      value: "1.54",
      error: {
        isError: false,
        errorText: "",
      },
    },
  ];
});

it("simple test", function () {
  act(function () {
    const Simple = Template.bind({});
    render(Simple(props), container);
  });
  let received = container.textContent.trim(); // here is the problem mentioned above.
  console.log(received);
  console.log(received.length);
  let expected = currencies[0].name;
  expect(received).toBe(expected);
});
// CurrencyTextField.js

import React from "react";
import TextField from "@material-ui/core/TextField";
import InputAdornment from "@material-ui/core/InputAdornment";
import FormControl from "@material-ui/core/FormControl";
import FormHelperText from "@material-ui/core/FormHelperText";
import InputLabel from "@material-ui/core/InputLabel";
import OutlinedInput from "@material-ui/core/OutlinedInput";
import MenuItem from "@material-ui/core/MenuItem";
import PropTypes from "prop-types";

const CurrencyTextField = (props) => {
  const {
    currencies,
    current,
    handleValueChange,
    handleCurrencyChange,
    style,
  } = props;
  const { classes, labelWidth } = style;
  const { formControl } = classes;
  const { name, value } = current;
  const { errorText, isError } = current.error;

  return (
    <FormControl className={formControl} variant="outlined">
      <InputLabel htmlFor={`${name}-currency-value`}>{name}</InputLabel>
      <OutlinedInput
        id={`${name}-currency-value`}
        value={value}
        onChange={handleValueChange}
        error={isError}
        endAdornment={
          <InputAdornment position="end">
            <TextField select value={name} onChange={handleCurrencyChange}>
              {currencies.map((currency) => (
                <MenuItem key={currency.name} value={currency.name}>
                  {currency.symbol}
                </MenuItem>
              ))}
            </TextField>
          </InputAdornment>
        }
        labelWidth={labelWidth | 55}
      />
      <FormHelperText id={`${name}-helper-text`}>{errorText}</FormHelperText>
    </FormControl>
  );
};

const _c = PropTypes.shape({
  name: PropTypes.string,
  flag: PropTypes.string,
  symbol: PropTypes.string,
  value: PropTypes.string,
  error: PropTypes.shape({
    isError: PropTypes.bool,
    errorText: PropTypes.string,
  }),
});

CurrencyTextField.propTypes = {
  currencies: PropTypes.arrayOf(_c),
  current: _c,
  handleValueChange: PropTypes.func,
  handleCurrencyChange: PropTypes.func,
  style: PropTypes.object,
};

export default CurrencyTextField;

package.json:

{
  "name": "exchange",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@material-ui/core": "4.11.3",
    "@material-ui/icons": "4.11.2",
    "@storybook/cli": "6.1.18",
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "clsx": "1.1.1",
    "money": "0.2.0",
    "nice-color-palettes": "3.0.0",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-scripts": "4.0.2",
    "web-vitals": "^1.0.1"
  },
  "scripts": {
    "start": "BROWSER=none react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "storybook": "BROWSER=none start-storybook -p 6006 -s public",
    "build-storybook": "build-storybook -s public"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@storybook/addon-actions": "^6.1.18",
    "@storybook/addon-essentials": "^6.1.18",
    "@storybook/addon-links": "^6.1.18",
    "@storybook/node-logger": "^6.1.18",
    "@storybook/preset-create-react-app": "^3.1.6",
    "@storybook/react": "^6.1.18"
  }
}

DOM 折叠是因为 OutlinedInput 组件而发生的。

yarn test 失败了。

【问题讨论】:

  • 它不会删除空字符串,因为它不是为此而设计的。您可以使用.filter() 删除不需要的元素,然后在该结果上使用.join()
  • 我想不出在"" 上拆分会导致数组以两个空字符串结尾的任何上下文。尝试提供一个minimal reproducible example,其中包含您对该函数的输入。
  • // but length is still 5 - 不能用您显示的代码真正重现。字符串ABC 几乎不能有长度 5,这没有任何意义。这里唯一可能的解释是您的输入数据与您所说的不同。
  • 收到的textContent 是以两个空格字符结尾的字符串,这是折叠DOM 的结果,就像@AKX 所说的那样,但trim() 应该处理这种情况,不是吗?跨度>
  • “收到的 textContent 是以两个空格字符结尾的字符串” - 然后将其拆分为 "" 不应该像你展示的那样得到一个数组,你会获取两个元素,每个元素包含一个空格字符,而不是两个 empty 字符串。

标签: javascript reactjs jestjs material-ui


【解决方案1】:

没有这样的概念

分配的内存长度和“逻辑”内存的长度不同

在 JavaScript 中,至少对用户而言不是。

您可能正在寻找container.innerText。我认为您在 textContent 中看到的空白是由于存在其他折叠的 DOM 空白,参考。

对于其他节点类型,textContent 返回每个子节点的 textContent 的串联,不包括 cmets 和处理指令。
MDN

【讨论】:

  • 更正空白是折叠 DOM 的结果,但我的问题是为什么我以后不能删除该空白?
  • 好吧,container.textContent.trim() 当然应该删除它。你确定它不起作用吗?
【解决方案2】:

好的,这就是我找到的。

最后收到的两个字符串,我错误地认为是空字符串,实际上是 unicode 字符(每个都有 unicode \u200b),它们是 zero-width space 字符。

所以,这就是 trim()join() 没有按预期工作的原因。

【讨论】:

    猜你喜欢
    • 2016-05-30
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    • 1970-01-01
    相关资源
    最近更新 更多