ESLint代码规范(一)

react/react-in-jsx-scope

当使用 JSX 语法时,React 必须在作用域内(即需要显式导入 React)。

在 React 17 之前,每次使用 JSX 语法时,Babel 会将其转换为 React.createElement() 调用,因此必须导入 React 才能使用 JSX。

举例

index.jsx

javascript 复制代码
export default () => <div>New Page index</div>;

应修改为

javascript 复制代码
import React from 'react';

export default () => <div>New Page index</div>;

max-len

eslint默认最大行长度为100

处理方法:修改eslint配置项

.eslintrc.js

javascript 复制代码
const { strictEslint } = require('@umijs/fabric');
module.exports = {
    ...strictEslint,
    globals: {
        ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,
        page: true,
    },
    rules: {
        ...strictEslint.rules,
        'max-len': ['error', {
            code: 100,     // 最大行长度
            ignoreComments: true,     // 忽略注释行
            ignoreStrings: true,      // 忽略字符串字面量(避免因长 URL 或模板字符串报错)
            ignoreTemplateLiterals: true, // 忽略模板字符串
            ignoreRegExpLiterals: true,    // 忽略正则表达式
            ignoreUrls: true,     // 忽略 URL
        }],
    },
}

注意:如果注释行为JSX注释,将不被eslint视为注释行

在 ESLint 的 max-len 规则中, ignoreComments: true 只适用于 真正的注释 :

  • // 单行注释
  • /* 多行注释 */

而 JSX 中的 {/* ... */} 虽然在语义上是注释,但在 AST(抽象语法树)中,它被解析为:

  • { - JSX 表达式开始
  • /* ... */ - 内部的注释
  • } - JSX 表达式结束

因此,ESLint 的 max-len 规则 不将 JSX 注释视为纯注释行 ,仍然会检查其长度。

举例

javascript 复制代码
const SubmitFormItem = ({ className, ...rest }) => {
    const clsString = classNames(styles.submit, className);
    return (
        <FormItem>
            {/* <Button size="large" className={clsString} type="primary" htmlType="submit" {...rest} /> */}
            <Button size="large" className={clsString} htmlType="submit" {...rest} />
        </FormItem>
    );
};

template literals

ESLint 推荐使用模板字符串(template literals)而不是字符串拼接。

javascript 复制代码
const title={`添加${title}`} // 模态框标题

Parsing error: Expression expected.

javascript 复制代码
 const page = service?.data?.page || {};

在老旧项目中,可选链操作符(``?.`` )是ES2020的特性,可能ESLint的解析器配置没有正确支持这个语法。

修改配置项,添加ES2020的特性支持

.eslintrc.js

javascript 复制代码
const { strictEslint } = require('@umijs/fabric');
module.exports = {
    ...strictEslint,
    rules: {
        ...
    },
    overrides: [
        {
            files: ['*.js', '*.jsx'],
            parser: 'babel-eslint',
            parserOptions: {
                ecmaVersion: 2020,
                ecmaFeatures: {
                    jsx: true,
                },
            },
        },
    ],
};

这样,当执行 npm run lint 命令时,就不会再因为可选链操作符而报错了

变量 is defined but never used

方法1:使用ESLint自动修复
bash 复制代码
# 自动修复所有可修复的问题,包括未使用的变量
npx eslint --fix src/

# 或者使用 yarn
yarn eslint --fix src/

# 或者 npm
npm run lint:fix

注意: 以下未使用对象需手动删除,ESLint 无法确定是否真的不需要

  • 未使用的导入
  • 未使用的函数变量

解决方案: 手动删除、使用代码清理工具

方法2:使用代码清理工具

eslint-plugin-unused-imports :专门用于检测和移除未使用的导入

安装插件

bash 复制代码
# 使用 npm
npm install --save-dev eslint-plugin-unused-imports @typescript-eslint/eslint-plugin @typescript-eslint/parser

# 或使用 yarn
yarn add --dev eslint-plugin-unused-imports @typescript-eslint/eslint-plugin @typescript-eslint/parser

配置.eslintrc.js

javascript 复制代码
module.exports = {
  parser: '@typescript-eslint/parser',
  plugins: [
    '@typescript-eslint',
    'unused-imports'  // 添加插件
  ],
  rules: {
    // 配置未使用导入的规则
    'unused-imports/no-unused-imports': 'error',
    'unused-imports/no-unused-vars': [
      'error',
      {
        vars: 'all',
        varsIgnorePattern: '^_',
        args: 'after-used',
        argsIgnorePattern: '^_'
      }
    ],
    // 其他规则...
  }
};

运行 以下命令自动修复未使用的导入

bash 复制代码
# 自动修复所有可修复的问题
npx eslint --fix src/

# 或使用 yarn
yarn eslint --fix src/

集成到开发流程

可以将 ESLint 检查添加到项目的 package.json 脚本中:

bash 复制代码
"scripts": {
  "lint": "eslint src/",
  "lint:fix": "eslint --fix src/"
}
方法3:修改ESLint配置(不推荐)

可能导致代码质量下降

配置规则为警告而非错误

javascript 复制代码
  rules: {
        ...strictEslint.rules,
        'eqeqeq': 'off',
        'no-unused-vars': 'off',
        '@typescript-eslint/no-unused-vars': 'warn',
  }

或者

允许忽略特定模式的未使用变量

javascript 复制代码
module.exports = {
    ...strictEslint,
    rules: {
        ...strictEslint.rules,
        '@typescript-eslint/no-unused-vars': ['warn', {
            vars: 'all',
            varsIgnorePattern: '^_|^React$',  // 忽略 React 和以 _ 开头的变量
            args: 'after-used',
            argsIgnorePattern: '^_'
        }],
    },
};

^_ - 忽略以 _ 开头的变量(如 _unused )

^React$ - 忽略 React(因为 JSX 需要)

Unary operator ++ used

意思是禁止使用自增运算符 ++(例如 i++ 或 ++i)

1. 为什么会有这个规则?

这条规则通常出现在追求函数式编程风格代码绝对清晰的项目中(如 Airbnb 风格指南)。主要理由包括:

  • 隐式副作用i++ 不仅返回值,还修改变量 i。在某些复杂的表达式中(如 array[i++] = i),这可能导致代码难以阅读且容易出错。
  • 自动分号插入问题 :在某些极端情况下,++ 紧跟在行尾可能会引起解析歧义(虽然现代工具处理得很好,但这是一个历史遗留顾虑)。
  • 鼓励显式操作 :强制开发者写出更明确的意图,比如 i += 1
2. 如何解决?

配置.eslintrc.js

javascript 复制代码
        'no-plusplus': 'off',

或者

javascript 复制代码
// 显式加 1
i += 1;

// 在循环中
for (let i = 0; i < len; i += 1) {
  // ...
}

no-nested-ternary

不允许嵌套多个三元运算符,代码阅读不友好

可以改为if else

no-underscore-dangle

在代码中使用了以下划线 _ 开头或结尾的标识符(variable/property name),这违反了 ESLint 的 no-underscore-dangle 规则。

no-constant-condition

禁止在控制流语句(如 ifwhilefor、条件运算符 ?:)中使用常量表达式作为条件

javascript 复制代码
// 1. 典型的错误写法
if (a = 5) { // 报错:这是一个赋值表达式,结果永远是 5 (truthy),意图可能是 a == 5
    // ...
}

// 2. 逻辑运算结果恒定
if (foo || true) { // 报错:无论 foo 是什么,结果永远为真
    // ...
}

// 3. 三元运算符中的常量
var a = true ? 'foo' : 'bar'; // 报错:条件恒定为真,'bar' 永远无法执行
为什么要有这条规则?
  1. 防止死循环while (true) 如果没有内部的 break,会导致程序卡死。虽然有时故意写 while(true),但 ESLint 希望你显式地关闭该规则或使用注释说明。
  2. 发现拼写错误 :最常见的是把比较运算符 ===== 误写成了赋值运算符 =。例如 if (x = 5) 实际上是将 5 赋值给 x,然后判断 5(真),这通常不是开发者的本意。
  3. 移除死代码 :如果条件是 if (false),那么里面的代码永远不会执行,这是无用代码。

array-callback-return

map() 方法期望回调函数 返回一个值 来构成新数组,但这里的回调函数没有 return 语句

将map修改为forEach

no-shadow(变量遮蔽)

禁止变量声明遮蔽(Shadowing)外部作用域中已存在的变量

变量遮蔽: 当一个内部作用域(如函数内部、代码块内部)声明了一个与外部作用域同名 的变量时,内部变量就会"遮蔽"外部变量。在内部作用域中,如果你使用该变量名,访问到的将是内部变量,而外部变量变得不可访问。

javascript 复制代码
let message = "Hello";

function printMessage(message) { // 报错:参数 'message' 遮蔽了外部的 'message'
    console.log(message); // 这里打印的是参数,而不是外部的 "Hello"
}
为什么 ESLint 要禁止它?
  1. 代码可读性差 :阅读代码时,很难分清当前使用的是内部变量还是外部变量,容易造成混淆。
  2. 潜在的逻辑错误 :开发者可能本意是想修改外部变量,结果不小心声明了一个新的局部变量,导致外部变量未被更新,引发难以察觉的 Bug。
  3. 维护困难 :当代码嵌套层级较深时,追踪变量的来源变得非常困难。

no-empty-pattern

禁止在解构赋值(Destructuring Assignment)中使用空的对象模式或空的数组模式

这条规则防止你写出像

javascript 复制代码
// 1. 空对象解构
const {} = foo; // 报错:Unexpected empty object pattern

// 2. 空数组解构
const [] = bar; // 报错:Unexpected empty array pattern

// 3. 函数参数中的空解构
function process({}) { // 报错
  // ...
}

// 4. 嵌套中的空解构
const { a: {} } = data; // 报错:a 对应的值是空对象模式

这样的代码。这种写法在 JavaScript 中虽然语法合法,但通常没有任何实际意义(它不会提取任何变量,也不会报错,只是单纯地"路过"了一下数据),往往是复制粘贴错误逻辑遗漏导致的。

javascript 复制代码
const { a: {} } = data;

在上述代码中,如果 a 不存在,你想让它默认为一个空对象 {}

javascript 复制代码
// ✅ 正确写法:如果 data.a 是 undefined,则 obj 默认为 {}
const { a: obj = {} } = data;

console.log(obj); // 如果 data 中没有 a,这里输出 {}

或者,如果 a 不存在,你只想忽略它,不需要任何变量

javascript 复制代码
// ✅ 正确写法:只提取 a,不做嵌套匹配
const { a } = data; 

// 或者如果你连变量 a 都不想要,可以直接忽略
// (这种写法通常没必要,除非是为了触发某些副作用,但一般直接不写就行)

或者,如果 a 存在,你想从 a 里面提取具体的属性(比如 name

javascript 复制代码
// ✅ 正确写法:嵌套解构 + 默认值
// 含义:从 data 中找 a,如果 a 不存在,视为 {},然后从结果中找 name,如果 name 也不存在,默认为 'Unknown'
const { a: { name = 'Unknown' } = {} } = data;

console.log(name); 
// 情况 A: data = { a: { name: 'Alice' } } -> 输出 'Alice'
// 情况 B: data = { a: {} }             -> 输出 'Unknown'
// 情况 C: data = {}                    -> 输出 'Unknown' (因为 a 缺失,用了默认值 {})
意图 ❌ 错误写法 (会报错/崩溃) ✅ 正确写法
给默认空对象 const { a: {} } = data; const { a: obj = {} } = data;
提取内部属性 const { a: { name } } = data; (若 a 缺失则崩溃) const { a: { name } = {} } = data;
仅仅检查/忽略 const { a: {} } = data; const { a } = data;
相关推荐
流星雨在线2 小时前
大前端通用性能优化(高频场景专项)
前端·性能优化
酉鬼女又兒2 小时前
零基础快速入门前端JavaScript Array 常用方法详解与实战(可用于备赛蓝桥杯Web应用开发)
开发语言·前端·javascript·chrome·蓝桥杯
January12072 小时前
Vue3打卡计时器:完整实现与优化方案
前端·javascript·css
GISer_Jing2 小时前
React全解析:从入门到精通实战指南
前端·react.js·前端框架
happymaker06262 小时前
web前端学习日记——DAY07(js交互编程)
前端·javascript·学习
lizi662 小时前
uniapp uview-plus 自定义动态验证
前端·vue.js·微信小程序
尘世中一位迷途小书童2 小时前
npm 包入口指南:package.json 中的 main、module、exports
前端·javascript·架构
●VON2 小时前
Flutter 入门指南:从基础组件到状态管理核心机制
前端·学习·flutter·von
gCode Teacher 格码致知2 小时前
Javascript提高:JavaScript Promise 超通俗解释-由Deepseek产生
开发语言·javascript