一篇文章教你写出干净的JavaScript代码

目录
  • 1. 变量
    • 使用有意义的名称
    • 避免添加不必要的上下文
    • 避免硬编码值
  • 2. 函数
    • 使用有意义的名称
    • 使用默认参数
    • 限制参数的数量
    • 避免在一个函数中做太多事情
    • 避免使用布尔标志作为参数
    • 避免写重复的代码
    • 避免副作用
  • 3. 条件语句
    • 使用非负条件
    • 尽可能使用简写
    • 避免过多分支
    • 优先使用 map 而不是 switch 语句
  • 4.并发
    • 避免回调
  • 5. 错误处理
  • 6.注释
    • 只注释业务逻辑
    • 使用版本控制
  • 总结

一段干净的代码,你在阅读、重用和重构的时候都能非常轻松。编写干净的代码非常重要,因为在我们日常的工作中,你不是仅仅是在为自己写代码。实际上,你还需要考虑一群需要理解、编辑和构建你的代码的同事。

1. 变量

使用有意义的名称

变量的名称应该是可描述,有意义的, JavaScript 变量都应该采用驼峰式大小写 ( camelCase) 命名。

// Don't ❌
const foo = "JDoe@example.com";
const bar = "John";
const age = 23;
const qux = true;

// Do ✅
const email = "John@example.com";
const firstName = "John";
const age = 23;
const isActive = true

布尔变量通常需要回答特定问题,例如:

isActive
didSubscribe
hasLinkedAccount

避免添加不必要的上下文

当对象或类已经包含了上下文的命名时,不要再向变量名称添加冗余的上下文。

// Don't ❌
const user = {
  userId: "296e2589-7b33-400a-b762-007b730c8e6d",
  userEmail: "JDoe@example.com",
  userFirstName: "John",
  userLastName: "Doe",
  userAge: 23,
};

user.userId;

// Do ✅
const user = {
  id: "296e2589-7b33-400a-b762-007b730c8e6d",
  email: "JDoe@example.com",
  firstName: "John",
  lastName: "Doe",
  age: 23,
};

user.id;

避免硬编码值

确保声明有意义且可搜索的常量,而不是直接插入一个常量值。全局常量可以采用 SCREAMING_SNAKE_CASE 风格命名。

// Don't ❌
setTimeout(clearSessionData, 900000);

// Do ✅
const SESSION_DURATION_MS = 15 * 60 * 1000;

setTimeout(clearSessionData, SESSION_DURATION_MS);

2. 函数

使用有意义的名称

函数名称需要描述函数的实际作用,即使很长也没关系。函数名称通常使用动词,但返回布尔值的函数可能是个例外 — 它可以采用 是或否 问题的形式,函数名也应该是驼峰式的。

// Don't ❌
function toggle() {
  // ...
}

function agreed(user) {
  // ...
}

// Do ✅
function toggleThemeSwitcher() {
  // ...
}

function didAgreeToAllTerms(user) {
  // ...
}

使用默认参数

默认参数比 && || 或在函数体内使用额外的条件语句更干净。

// Don't ❌
function printAllFilesInDirectory(dir) {
  const directory = dir || "./";
  //   ...
}

// Do ✅
function printAllFilesInDirectory(dir = "./") {
  // ...
}

限制参数的数量

尽管这条规则可能有争议,但函数最好是有3个以下参数。如果参数较多可能是以下两种情况之一:

  • 该函数做的事情太多,应该拆分。
  • 传递给函数的数据以某种方式相关,可以作为专用数据结构传递。
// Don't ❌
function sendPushNotification(title, message, image, isSilent, delayMs) {
  // ...
}

sendPushNotification("New Message", "...", "http://...", false, 1000);

// Do ✅
function sendPushNotification({ title, message, image, isSilent, delayMs }) {
  // ...
}

const notificationConfig = {
  title: "New Message",
  message: "...",
  image: "http://...",
  isSilent: false,
  delayMs: 1000,
};

sendPushNotification(notificationConfig);

避免在一个函数中做太多事情

一个函数应该一次做一件事,这有助于减少函数的大小和复杂性,使测试、调试和重构更容易。

/ Don't ❌
function pingUsers(users) {
  users.forEach((user) => {
    const userRecord = database.lookup(user);
    if (!userRecord.isActive()) {
      ping(user);
    }
  });
}

// Do ✅
function pingInactiveUsers(users) {
  users.filter(!isUserActive).forEach(ping);
}

function isUserActive(user) {
  const userRecord = database.lookup(user);
  return userRecord.isActive();
}

避免使用布尔标志作为参数

函数含有布尔标志的参数意味这个函数是可以被简化的。

// Don't ❌
function createFile(name, isPublic) {
  if (isPublic) {
    fs.create(`./public/${name}`);
  } else {
    fs.create(name);
  }
}

// Do ✅
function createFile(name) {
  fs.create(name);
}

function createPublicFile(name) {
  createFile(`./public/${name}`);
}

避免写重复的代码

如果你写了重复的代码,每次有逻辑改变,你都需要改动多个位置。

// Don't ❌
function renderCarsList(cars) {
  cars.forEach((car) => {
    const price = car.getPrice();
    const make = car.getMake();
    const brand = car.getBrand();
    const nbOfDoors = car.getNbOfDoors();

    render({ price, make, brand, nbOfDoors });
  });
}

function renderMotorcyclesList(motorcycles) {
  motorcycles.forEach((motorcycle) => {
    const price = motorcycle.getPrice();
    const make = motorcycle.getMake();
    const brand = motorcycle.getBrand();
    const seatHeight = motorcycle.getSeatHeight();

    render({ price, make, brand, nbOfDoors });
  });
}

// Do ✅
function renderVehiclesList(vehicles) {
  vehicles.forEach((vehicle) => {
    const price = vehicle.getPrice();
    const make = vehicle.getMake();
    const brand = vehicle.getBrand();

    const data = { price, make, brand };

    switch (vehicle.type) {
      case "car":
        data.nbOfDoors = vehicle.getNbOfDoors();
        break;
      case "motorcycle":
        data.seatHeight = vehicle.getSeatHeight();
        break;
    }

    render(data);
  });
}

避免副作用

在 JavaScript 中,你应该更喜欢函数式模式而不是命令式模式。换句话说,大多数情况下我们都应该保持函数纯。副作用可能会修改共享状态和资源,从而导致一些奇怪的问题。所有的副作用都应该集中管理,例如你需要更改全局变量或修改文件,可以专门写一个 util 来做这件事。

// Don't ❌
let date = "21-8-2021";

function splitIntoDayMonthYear() {
  date = date.split("-");
}

splitIntoDayMonthYear();

// Another function could be expecting date as a string
console.log(date); // ['21', '8', '2021'];

// Do ✅
function splitIntoDayMonthYear(date) {
  return date.split("-");
}

const date = "21-8-2021";
const newDate = splitIntoDayMonthYear(date);

// Original vlaue is intact
console.log(date); // '21-8-2021';
console.log(newDate); // ['21', '8', '2021'];

另外,如果你将一个可变值传递给函数,你应该直接克隆一个新值返回,而不是直接改变该它。

// Don't ❌
function enrollStudentInCourse(course, student) {
  course.push({ student, enrollmentDate: Date.now() });
}

// Do ✅
function enrollStudentInCourse(course, student) {
  return [...course, { student, enrollmentDate: Date.now() }];
}

3. 条件语句

使用非负条件

// Don't ❌
function isUserNotVerified(user) {
  // ...
}

if (!isUserNotVerified(user)) {
  // ...
}

// Do ✅
function isUserVerified(user) {
  // ...
}

if (isUserVerified(user)) {
  // ...
}

尽可能使用简写

// Don't ❌
if (isActive === true) {
  // ...
}

if (firstName !== "" && firstName !== null && firstName !== undefined) {
  // ...
}

const isUserEligible = user.isVerified() && user.didSubscribe() ? true : false;

// Do ✅
if (isActive) {
  // ...
}

if (!!firstName) {
  // ...
}

const isUserEligible = user.isVerified() && user.didSubscribe();

避免过多分支

尽早 return 会使你的代码线性化、更具可读性且不那么复杂。

// Don't ❌
function addUserService(db, user) {
  if (!db) {
    if (!db.isConnected()) {
      if (!user) {
        return db.insert("users", user);
      } else {
        throw new Error("No user");
      }
    } else {
      throw new Error("No database connection");
    }
  } else {
    throw new Error("No database");
  }
}

// Do ✅
function addUserService(db, user) {
  if (!db) throw new Error("No database");
  if (!db.isConnected()) throw new Error("No database connection");
  if (!user) throw new Error("No user");

  return db.insert("users", user);
}

优先使用 map 而不是 switch 语句

既能减少复杂度又能提升性能。

// Don't ❌
const getColorByStatus = (status) => {
  switch (status) {
    case "success":
      return "green";
    case "failure":
      return "red";
    case "warning":
      return "yellow";
    case "loading":
    default:
      return "blue";
  }
};

// Do ✅
const statusColors = {
  success: "green",
  failure: "red",
  warning: "yellow",
  loading: "blue",
};

const getColorByStatus = (status) => statusColors[status] || "blue";

使用可选链接

const user = {
  email: "JDoe@example.com",
  billing: {
    iban: "...",
    swift: "...",
    address: {
      street: "Some Street Name",
      state: "CA",
    },
  },
};

// Don't ❌
const email = (user && user.email) || "N/A";
const street =
  (user &&
    user.billing &&
    user.billing.address &&
    user.billing.address.street) ||
  "N/A";
const state =
  (user &&
    user.billing &&
    user.billing.address &&
    user.billing.address.state) ||
  "N/A";

// Do ✅
const email = user?.email ?? "N/A";
const street = user?.billing?.address?.street ?? "N/A";
const street = user?.billing?.address?.state ?? "N/A";

4.并发

避免回调

回调很混乱,会导致代码嵌套过深,使用 Promise 替代回调。

// Don't ❌
getUser(function (err, user) {
  getProfile(user, function (err, profile) {
    getAccount(profile, function (err, account) {
      getReports(account, function (err, reports) {
        sendStatistics(reports, function (err) {
          console.error(err);
        });
      });
    });
  });
});

// Do ✅
getUser()
  .then(getProfile)
  .then(getAccount)
  .then(getReports)
  .then(sendStatistics)
  .catch((err) => console.error(err));

// or using Async/Await ✅✅

async function sendUserStatistics() {
  try {
    const user = await getUser();
    const profile = await getProfile(user);
    const account = await getAccount(profile);
    const reports = await getReports(account);
    return sendStatistics(reports);
  } catch (e) {
    console.error(err);
  }
}

5. 错误处理

处理抛出的错误和 reject 的 promise

/ Don't ❌
try {
  // Possible erronous code
} catch (e) {
  console.log(e);
}

// Do ✅
try {
  // Possible erronous code
} catch (e) {
  // Follow the most applicable (or all):
  // 1- More suitable than console.log
  console.error(e);

  // 2- Notify user if applicable
  alertUserOfError(e);

  // 3- Report to server
  reportErrorToServer(e);

  // 4- Use a custom error handler
  throw new CustomError(e);
}

6.注释

只注释业务逻辑

可读的代码使你免于过度注释,因此,你应该只注释复杂的逻辑。

// Don't ❌
function generateHash(str) {
  // Hash variable
  let hash = 0;

  // Get the length of the string
  let length = str.length;

  // If the string is empty return
  if (!length) {
    return hash;
  }

  // Loop through every character in the string
  for (let i = 0; i < length; i++) {
    // Get character code.
    const char = str.charCodeAt(i);

    // Make the hash
    hash = (hash << 5) - hash + char;

    // Convert to 32-bit integer
    hash &= hash;
  }
}

// Do ✅
function generateHash(str) {
  let hash = 0;
  let length = str.length;
  if (!length) {
    return hash;
  }

  for (let i = 0; i < length; i++) {
    const char = str.charCodeAt(i);
    hash = (hash << 5) - hash + char;
    hash = hash & hash; // Convert to 32bit integer
  }
  return hash;
}

使用版本控制

在代码里不需要保留历史版本的注释,想查的话你直接用 git log 就可以搜到。。

// Don't ❌
/**
 * 2021-7-21: Fixed corner case
 * 2021-7-15: Improved performance
 * 2021-7-10: Handled mutliple user types
 */
function generateCanonicalLink(user) {
  // const session = getUserSession(user)
  const session = user.getSession();
  // ...
}

// Do ✅
function generateCanonicalLink(user) {
  const session = user.getSession();
  // ...
}

好了,去写出你漂亮的代码吧!🌈

总结

到此这篇关于如何写出干净的JavaScript代码的文章就介绍到这了,更多相关写干净的JavaScript代码内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 非常不错的一个JS分页效果代码,值得研究

    本来想用网上找来的分页程序,不过都得做修改,感觉麻烦了,还是自己写一个好了,以后自己用的时候修改就方便了~~大家都多动手,自己写的才是最好的,日后想干什么的,做修改也是很容易的~~顺便也扩充一下自己的代码库~~ 补充一句,cpage是页面计数,应为全局变量,这样可以随处调用它,totalpage是总页数 JS静态分页程序 a:link,a:visited,a:hover,.current,#info{ border:1px solid #DDD; background:#F2F2F2; disp

  • js代码实现点击按钮出现60秒倒计时

    比如,一些网站上的手机短信认证的功能,有类似实现点击按钮后,倒计时60秒才能再次点击发送的效果. 此例子用Javascript实现点击按钮后,倒计时60秒才能再次点击发送验证码的功能. 例子1:Javascript 实现 点击按钮 倒计时60秒方可再次点击发送的效果 <input type="button" id="btn" value="免费获取验证码" /> <script type="text/javascrip

  • 详解javascript中的变量提升和函数提升

    1在js中只有两种作用域 a:全局作用域 b:函数作用域 在ES6之前,js是没有块级作用域. 首先来解释一下什么是没有块级作用域? 所以此时 是可以打印输出变量a的值. 2:什么是变量提升? 在我们的js中,代码的执行时分两步走的,1.解析 2.一步一步执行 那么变量提升就是变量声明会被提升到作用域的最顶上去,也就是该变量不管是在作用域的哪个地方声明的,都会提升到作作用域的最顶上去. 那么上面这种写法其实等价于下面这种写法: 看几个例子: 把上面的例子稍作改动: 结果就会大不一样, 再看一个例

  • JS弹出窗口代码大全(详细整理)

    如何利用网页弹出各种形式的窗口,我想大家大多都是知道些的,但那种多种多样的弹出式窗口是怎么搞出来的,我们今天就来学习一下: 1.弹启一个全屏窗口 复制代码 代码如下: <html> <body http://www.jb51.net','我们','fullscreen');">; <b>www.jb51.net</b> </body> </html> 2.弹启一个被F11化后的窗口 复制代码 代码如下: <html&g

  • JavaScript中判断函数、变量是否存在

    一.是否存在指定函数 function isExitsFunction(funcName) { try { if (typeof(eval(funcName)) == "function") { return true; } } catch(e) {} return false; } 二.类似PHP常用的判断函数是否存在,不存在则创建 if (typeof String.prototype.endsWith != 'function') { String.prototype.endsW

  • 比较正宗的验证邮箱的正则表达式js代码详解

    fuchangxi的正则: 复制代码 代码如下: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/ 开始必须是一个或者多个单词字符或者是-,加上@,然后又是一个或者多个单词字符或者是-.然后是点"."和单词字符和-的组合,可以有一个或者多个组合. 复制代码 代码如下: <script type="text/javascript"> function isEmail(str){ var reg =

  • JavaScript 获取当前时间戳的代码

    JavaScript 获取当前时间戳: 第一种方法: 复制代码 代码如下: var timestamp = Date.parse(new Date()); 结果:1280977330000 第二种方法: 复制代码 代码如下: var timestamp = (new Date()).valueOf(); 结果:1280977330748 以上代码将获取从 1970年1月1日午夜开始的毫秒数.二者的区别是,第一种方法的毫秒位上为全零,即只是精确到秒的毫秒数 如题所示,返回unix时间戳所对应的具体

  • JS类的封装及实现代码

    1. 定义js类 js并不是一种面向对向的语言, 没有提供对类的支持, 因此我们不能像在传统的语言里那样 用class来定义类, 但我们可以利用js的闭包封装机制来实现js类, 我们来封装一个简的Shape类. 复制代码 代码如下: function ShapeBase() { this.show = function() { alert("ShapeBase show"); }; this.init = function(){ alert("ShapeBase init&q

  • 一篇文章教你写出干净的JavaScript代码

    目录 1. 变量 使用有意义的名称 避免添加不必要的上下文 避免硬编码值 2. 函数 使用有意义的名称 使用默认参数 限制参数的数量 避免在一个函数中做太多事情 避免使用布尔标志作为参数 避免写重复的代码 避免副作用 3. 条件语句 使用非负条件 尽可能使用简写 避免过多分支 优先使用 map 而不是 switch 语句 4.并发 避免回调 5. 错误处理 6.注释 只注释业务逻辑 使用版本控制 总结 一段干净的代码,你在阅读.重用和重构的时候都能非常轻松.编写干净的代码非常重要,因为在我们日常

  • 一篇文章教你学会js实现弹幕效果

    目录 新建一个html文件: 建好html文件,搞出初始模版 HTML添加 CSS填充 js逻辑代码 动画效果 下面是弹幕效果 : 相信小伙伴们都看过了,那么它实现的原理是什么呢,那么我们前端怎么用我们web技术去实现呢?? 新建一个html文件: 哈哈哈,大家别像我一样用中文命名. 中文命名是不合规范的,行走江湖,大佬们看见你的中文命名会笑话你的. 上图中,我们引入了jquery插件,没错我们用jq写,回归原始(找不到cdn链接的小伙伴可以百度bootcdn,在里面搜索jquery).并且取了

  • 一篇文章教你学会使用Python绘制甘特图

    目录 优点 局限 一日一书 用来制作甘特图的专业工具也不少,常见的有:Microsoft Office Project.GanttProject.WARCHART XGantt.jQuery.Gantt.Excel等,网络上也有一些优质工具支持在线绘制甘特图. 可是这种现成的工具,往往也存在一些弊端,让编程人员不知所措.比如说,花里胡哨的UI,让人目不暇接,不知点哪个才好: 比如说,有些基于浏览器的图表需要掌握HTML.JS等编程语言,只会点Python的我直接被劝退: 再比如,进来就是注册.登

  • 一篇文章教你使用SpringBoot如何实现定时任务

    前言 在 Spring + SpringMVC 环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用 Spring 自带的定时任务处理器 @Scheduled 注解,另一种就是使用第三方框架 Quartz ,Spring Boot 源自 Spring+SpringMVC ,因此天然具备这两个 Spring 中的定时任务实现策略,当然也支持 Quartz,本文我们就来看下 Spring Boot 中两种定时任务的实现方式. 一.第一种方式:@Scheduled 使用 @Scheduled

  • 通过数据库和ajax方法写出地图的实例代码

    ajax教程 AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). AJAX 不是新的编程语言,而是一种使用现有标准的新方法. AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下. 客户端部分:html.js.css代码部分: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www

  • 如何写出优雅的JS 代码

    变量 使用有意义和可发音的变量名 // 不好的写法 const yyyymmdstr = moment().format("YYYY/MM/DD"); // 好的写法 const currentDate = moment().format("YYYY/MM/DD"); 对同一类型的变量使用相同的词汇 // 不好的写法 getUserInfo(); getClientData(); getCustomerRecord(); // 好的写法 getUser(); 使用可

  • Java杂谈之如何优化写出漂亮高效的代码

    目录 命名中的不一致 方案中的不一致 代码中的不一致 总结 大部分程序员对于一致性本身的重要性是有认知的.但通常来说,大家理解的一致性都表现在比较大的方面,比如,数据库访问是叫 DAO还是叫 Mapper,Repository?在一个团队内,这是有统一标准的,但编码的层面上,要求往往就不是那么细致了.所以,我们才会看到在代码细节上呈现出了各种不一致.我们还是从一段具体的代码来分析问题. 命名中的不一致 有一次,我在代码评审中看到了这样一段代码: enum DistributionChannel

  • LyScript实现计算片段Hash并写出Excel的示例代码

    本案例将学习运用LyScript计算特定程序中特定某些片段的Hash特征值,并通过xlsxwriter这个第三方模块将计算到的hash值存储成一个excel表格,本例中的知识点可以说已经具备了简单的表格输出能力,如果时间充裕完全可以实现自动化报告生成. 第一步实现计算特定片段的特征值,此类代码实现原理用户传入一个rva相对地址以及读入指令长度,并通过内置的hashlib库实现计算内存段内指令的特征,如下代码先来实现计算两段指令特征. import hashlib import zlib,bina

  • 12条写出高质量JS代码的方法

    书写出高质量的JS代码不仅让程序员看着舒服,更加能够提高程序的运行速度,以下就是我们的小编整理方法: 一.如何书写可维护性的代码 当出现bug的时候如果你能立马修复它是最好的,此时解决问题的四路在你脑中还是很清晰的.否则,你转移到其他任务或者bug是经过一定的时间才出现的,你忘了那个特定的代码,一段时间后再去查看这些代码就 需要: 1.花时间学习和理解这个问题 2.化时间是了解应该解决的问题代码 还有个问题,特别对于大的项目或是公司,修复bug的这位伙计不是写代码的那个人(且发现bug和修复bu

  • 一篇文章教你用python画动态爱心表白

    初级画心 学Python,感觉你们的都好复杂,那我来个简单的,我是直接把心形看作是一个正方形+两个半圆: 于是这就很简单了,十行代码解决: import turtle as t t.pensize(2) # 笔大小2像素 t.pencolor("red") # 颜色为红色 t.left(45) # 45度 t.fd(200) # 向前200直线 t.circle(100, 180) # 画一圆半径100 弧度180 t.right(90) # 向右90度 t.circle(100, 1

随机推荐