JavaScript 代码精简与重构实战指南

作者:小括号

时间:2026-10-30

浏览:617

本文深入解析JavaScript中简化冗余代码的18种核心技巧,涵盖箭头函数、解构赋值、模板字符串及展开运算符等ES6特性。重点探讨复杂条件判断的重构策略,对比三元运算符与Map对象写法的优劣,并演示如何通过函数式编程、闭包私有化及方法链提升代码的可读性与执行效率,帮助开发者写出更优雅、易维护的JS代码。

文章目录

利用箭头函数可以显著简化函数的定义过程,使代码更加简洁。

// 传统函数定义
function add(a, b) {
 return a + b;
 }
 // 箭头函数简化
 const add = (a, b) => a + b;

通过解构赋值语法,可以直接从对象或数组中提取变量,从而简化变量声明的步骤。

// 传统变量声明
const firstName = person.firstName;
const lastName = person.lastName;
// 解构赋值简化
const { firstName, lastName } = person;

采用模板字面量(Template Literals)进行字符串拼接,比传统的字符串连接方式更加直观且易于阅读。

// 传统字符串拼接
const greeting = 'Hello, ' + name + '!';
// 模板字面量简化
const greeting = `Hello, ${name}!`;

展开运算符(Spread Operator)在处理数组合并与对象复制时非常高效,能够简化对数组和对象的操作逻辑。

// 合并数组
const combined = [...array1, ...array2];
// 复制对象
const clone = { ...original };

利用数组的高阶方法(如 map、filter 等)替代传统的循环语句,可以大幅简化数据遍历与处理的操作。

// 遍历数组并返回新数组
const doubled = numbers.map(num => num * 2);
// 过滤数组
const evens = numbers.filter(num => num % 2 === 0);

条件运算符(三元运算符)适用于简单的条件判断,能够用更少的代码行数表达逻辑。

// 传统条件判断
let message;
if (isSuccess) {
 message = 'Operation successful';
} else {
 message = 'Operation failed';
}
// 条件运算符简化
const message = isSuccess ? 'Operation successful' : 'Operation failed';

结合对象解构与默认参数,可以简化函数参数的定义与处理,提高代码的简洁性。

// 传统参数设置默认值
function greet(name) {
 const finalName = name || 'Guest';
 console.log(`Hello, ${finalName}!`);
 }
 // 对象解构和默认参数简化
 function greet({ name = 'Guest' }) {
 console.log(`Hello, ${name}!`);
 }

引入函数式编程概念,如纯函数和函数组合,有助于提升代码的可预测性和可维护性。

// 纯函数
function add(a, b) {
 return a + b;
 }
 // 函数组合
 const multiplyByTwo = value => value * 2;
 const addFive = value => value + 5;
 const result = addFive(multiplyByTwo(3));

使用对象字面量语法可以简化对象的创建与定义过程,使代码更加紧凑。

// 传统对象创建
const person = {
 firstName: 'John',
 lastName: 'Doe',
 age: 30,
 };
 // 对象字面量简化
 const firstName = 'John';
 const lastName = 'Doe';
 const age = 30;
 const person = { firstName, lastName, age };

采用清晰的命名规范与适当的注释,是提升代码可读性的基础手段。

// 不好的
const x = 10; // 设置x的值为10
function a(b) {
 return b * 2; // 返回b的两倍
}
// 好的
const speed = 10; // 设置速度为10
function double(value) {
 return value * 2; // 返回输入值的两倍

编写优雅的条件判断代码是提升代码质量的关键环节。

对于简单的条件判断逻辑,推荐使用 if else 或者三元运算符,这样代码一目了然,便于理解。然而,如果大量堆叠 if else 和嵌套的三元运算符,将会给后续维护者带来极大的困扰,成为接手项目的噩梦。

以下展示一个三元运算符过度嵌套的实际案例,这在真实项目中确实存在,会导致代码逻辑混乱,甚至影响性能。

<view>{{status===1?'成功': status===2 ? '失败' : status===3 ? '进行中' : '未开始' }}</view>

由于涉及具体项目隐私,此处不便展示完整代码,读者可根据示例理解其逻辑结构。

针对复杂的逻辑判断,推荐使用对象 Map 或字典写法,这更符合人类的思维逻辑,可读性高,代码结构清晰。

第一种情况:普通的 if-else 语句。

let txt = '';
if (falg) {
 txt = "成功"
} else {
 txt = "失败"
}

第二种情况:使用三元运算符。

let txt = flag ? "成功" : "失败";

第三种情况:多个 if-else 嵌套。

// param {status} status 活动状态:1:成功 2:失败 3:进行中 4:未开始
let txt = '';
if (status == 1) {
 txt = "成功";
} else if (status == 2) {
 txt = "失败";
} else if (status == 3) {
 txt = "进行中";
} else {
 txt = "未开始";
}

第四种情况:使用 switch-case 语句。

let txt = '';
switch (status) {
 case 1:
 txt = "成功";
 break;
 case 2:
 txt = "成功";
 break;
 case 3:
 txt = "进行中";
 break;
 default:
 txt = "未开始";
}

第五种情况:使用对象映射表写法。

const statusMap = {
 1: "成功",
 2: "失败",
 3: "进行中",
 4: "未开始"
}
//调用直接 statusMapp[status]

第六种情况:使用 Map 对象写法。

const actions = new Map([
 [1, "成功"],
 [2, "失败"],
 [3, "进行中"],
 [4, "未开始"]
])
// 调用直接 actions.get(status)

封装条件语句是优化代码结构的重要步骤。

与前述观点一致,if 语句中的条件越多,越不利于后续维护者理解,代码可读性下降。多个逻辑判断应当化零为整,进行封装处理。

//大脑:'别来碰我,让我静静'
// 不好的
if (fsm.state === 'fetching' && isEmpty(listNode)) {
 // ...
}
// 好的
shouldShowSpinner(fsm, listNode){
 return fsm.state === 'fetching' && isEmpty(listNode)
}
if(shouldShowSpinner(fsm, listNode)){
 //...doSomething
}

遵循单一职责原则,函数应该只负责完成一件事。

函数式编程推崇 柯里化 思想,即一个函数只实现一个功能,这样既便于拆分也易于组合复用。

// 不好的
function createFile(name, temp) {
 if (temp) {
   fs.create(`./temp/${name}`);
 } else {
   fs.create(name);
 }
}
// 好的
function createFile(name) {
 fs.create(name);
}
function createTempFile(name) {
 createFile(`./temp/${name}`)
}

以下是一个具体的代码示例。

该函数的主要任务包括:

遍历 clients 数组。

在遍历过程中,通过 lookup 函数获取一个新的对象 clientRecord。

判断 clientRecord 对象中 isActive 函数返回的值是否为 true。

若 isActive 返回 true,则执行 email 函数并将当前成员作为参数传递过去。

// 不好的
function emailClients(clients) {
 clients.forEach((client) => {
   const clientRecord = database.lookup(client);
   if (clientRecord.isActive()) {
     email(client);
   }
 });
}
// 好的
function emailClients(clients) {
 clients
   .filter(isClientRecord)
   .forEach(email)
}
function isClientRecord(client) {
 const clientRecord = database.lookup(client);
 return clientRecord.isActive()
}

观察上述不良示例,代码堆积且逻辑晦涩,阅读体验极差,甚至让人产生抵触情绪。

而优化后的示例逻辑清晰,结构分明,易于阅读和理解。

技巧一:巧妙利用 filter 函数,将 filter 的回调逻辑单独提取为一个函数进行条件处理,返回符合条件的数据。

技巧二:对筛选后的数据再次利用 forEach 执行 email 函数。

技巧三:使用 Object.assign 为默认对象赋值,实现默认值的覆盖与合并。

// 不好的
const menuConfig = {
 title: null,
 body: 'Bar',
 buttonText: null,
 cancellable: true
};
function createMenu(config) {
 config.title = config.title || 'Foo';
 config.body = config.body || 'Bar';
 config.buttonText = config.buttonText || 'Baz';
 config.cancellable = config.cancellable === undefined ?
 config.cancellable : true;
}
createMenu(menuConfig);
// 好的
const menuConfig = {
 title: 'Order',
 buttonText: 'Send',
 cancellable: true
};
function createMenu(config) {
 Object.assign({
   title: 'Foo',
   body: 'Bar',
   buttonText: 'Baz',
   cancellable: true 
 }, config)
}
createMenu(menuConfig);

技巧四:函数参数建议控制在两个以下,以减少复杂度。

总而言之,所有这些技巧的核心目的都是为了代码的优雅与高可读性。

// 不好的
function createMenu(title, body, buttonText, cancellable) {
 // ...
}
// 好的
const menuConfig = {
 title: 'Foo',
 body: 'Bar',
 buttonText: 'Baz',
 cancellable: true
};
function createMenu(config){
 // ...
}
createMenu(menuConfig)

技巧五:使用具有解释性的变量名,提升代码自文档化能力。

简而言之,使用扩展运算符不仅提升了代码简洁度,还为了可读性(如 saveCityZipCode(city, zipCode) 所示,参数含义一目了然)。

// 不好的
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
saveCityZipCode(address.match(cityZipCodeRegex)[1], address.match(cityZipCodeRegex)[2]);
// 好的
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
cosnt [, city, zipCode] = address.match(cityZipCodeRegex) || [];
saveCityZipCode(city, zipCode)

当需要对类中的属性进行更自定义的获取、增加或修改操作时,应使用 set/get 访问器。

初次接触此语法的开发者可能感到陌生,可以将其理解为 Vue2 中 defineProperty 的简化版。

Object.defineProperty(data1,'age',{
 set:function(newAge){
   console.log(this.name+'现在'+newAge+'岁')
 },
 get:function(){
   return 18;
 }
})

其机制相同:在赋值时触发 set 方法,在取值时触发 get 方法。

巧妙利用语言自带的属性机制,有助于提升程序性能。

class BankAccount {
 constructor(balance = 1000) {
   this._balance = balance;
 }
 // It doesn't have to be prefixed with `get` or `set` to be a
 //getter/setter
 set balance(amount) {
   console.log('set')
   if (verifyIfAmountCanBeSetted(amount)) {
     this._balance = amount;
   }
 }
 get balance() {
   console.log('get')
   return this._balance;
 }
 verifyIfAmountCanBeSetted(val) {
   // ...
 }
}
const bankAccount = new BankAccount();
// Buy shoes...
bankAccount.balance -= 100;
// Get balance
let balance = bankAccount.balance;

技巧六:通过闭包实现对象的私有成员,确保数据封装性。

闭包机制天然适合实现私有化逻辑。

// 不好的
const Employee = function(name) {
 this.name = name;
};
Employee.prototype.getName = function getName() {
 return this.name;
};
const employee = new Employee('John Doe');
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
delete employee.name;
console.log(`Employee name: ${employee.getName()}`); // Employee name: undefined
// 好的
const Employee = function(name){
 this.getName = function(){
   return name
 }
}
const employee = new Employee('John Doe');
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
delete employee.name;
console.log(`Employee name: ${employee.getName()}`); // Employee name: undefined

以下是第一个示例代码。

该方案的优点在于:

通过原型链共享方法,有效节省了内存空间。所有实例对象共享同一个 getName 方法,而非为每个实例单独创建独立的方法副本。

该方案的缺点在于:

在构造函数内部无法直接定义私有属性或方法,导致所有属性和方法都暴露在原型链上,缺乏封装性。

以下是第二个示例代码。

该方案的优点在于:

可以在构造函数内部定义私有属性和方法,这些成员不会暴露在对象的原型链上,从而提供了更好的封装性与安全性。

该方案的缺点在于:

每次创建实例对象时,都会重新创建一个独立的方法,每个实例对象都拥有自己的 getName 方法副本,从而占用更多的内存空间。

技巧七:使用方法链(Method Chaining)提升代码流畅度。

链式写法也是实现代码优雅的重要方式之一。

注:发明这种写法的程序员可能具有后端背景,这种风格在 PHP 的 CI 框架中较为常见。

// 不好的
class Car {
 constructor() {
   this.make = 'Honda';
   this.model = 'Accord';
   this.color = 'white';
 }
 setMake(make) {
   this.make = make;
 }
 save() {
   console.log(this.make, this.model, this.color);
 }
}
const car = new Car();
car.setMake('Ford');
car.save();
// 好的
class Car {
 constructor() {
   this.make = 'Honda';
   this.model = 'Accord';
   this.color = 'white';
 }
 setMake(make) {
   this.make = make;
   // NOTE: return this是为了用链式写法
   return this;
 }
 save() {
   console.log(this.make, this.model, this.color);
   // NOTE:return this是为了用链式写法
   return this;
 }
}
const car = new Car()
 .setMake('Ford')
 .save();

阅读完上述诸多示例后,相信读者的思路已更加清晰,建议在项目中尝试应用这些技巧。

以上即为 JavaScript 优化冗余代码技巧的详细内容,更多关于 JS 优化的资料请关注本站其他相关文章!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章