返回顶部
首页 > 资讯 > 前端开发 > JavaScript >如何写出优雅的JS 代码
  • 593
分享到

如何写出优雅的JS 代码

2024-04-02 19:04:59 593人浏览 安东尼
摘要

目录变量使用有意义和可发音的变量名对同一类型的变量使用相同的词汇使用可搜索的名字使用解释性变量避免费脑的猜测无需添加不必要的上下文使用默认参数代替逻辑或(与)运算函数函数参数(理想情

变量

使用有意义和可发音的变量名


// 不好的写法
const yyyymmdstr = moment().fORMat("YYYY/MM/DD");

// 好的写法
const currentDate = moment().format("YYYY/MM/DD");

对同一类型的变量使用相同的词汇


// 不好的写法
getUserInfo();
getClientData();
getCustomerRecord();

// 好的写法
getUser();

使用可搜索的名字

我们读的会比我们写的多得多,所以如果命名太过随意不仅会给后续的维护带来困难,也会伤害了读我们代码的开发者。让你的变量名可被读取,像buddy.js和ESLint这样的工具可以帮助识别未命名的常量。


// 不好的写法
// 86400000 的用途是什么?
setTimeout(blastOff, 86400000);

// 好的写法
const MILLISECONDS_IN_A_DAY = 86_400_000;
setTimeout(blastOff, MILLISECONDS_IN_A_DAY);

使用解释性变量


// 不好的写法
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})?$/;
const [_, city, zipCode] = address.match(cityZipCodeRegex) || [];
saveCityZipCode(city, zipCode);

避免费脑的猜测

显式用于隐式


// 不好的写法
const locations = ["Austin", "New York", "San Francisco"];
locations.forEach(l => {
  doStuff();
  doSomeOtherStuff();
  // ...
  // ...
  // ...
  // 等等,“l”又是什么?
  dispatch(l);

// 好的写法
const locations = ["Austin", "New York", "San Francisco"];
locations.forEach(location => {
  doStuff();
  doSomeOtherStuff();
  // ...
  // ...
  // ...
  dispatch(location);
});

无需添加不必要的上下文

如果类名/对象名已经说明了,就无需在变量名中重复。


// 不好的写法
const Car = {
  carMake: "Honda",
  carModel: "Accord",
  carColor: "Blue"
};

function paintCar(car) {
  car.carColor = "Red";
}
// 好的写法
const Car = {
  make: "Honda",
  model: "Accord",
  color: "Blue"
};

function paintCar(car) {
  car.color = "Red";
}

使用默认参数代替逻辑或(与)运算


// 不好的写法
function createMicrobrewery(name) {
  const breweryName = name || "Hipster Brew Co.";
  // ...
}
// 好的写法
function createMicrobrewery(name = "Hipster Brew Co.") {
  // ...
}

函数

函数参数(理想情况下为2个或更少)

限制函数参数的数量是非常重要的,因为它使测试函数变得更容易。如果有三个以上的参数,就会导致组合爆炸,必须用每个单独的参数测试大量不同的情况。

一个或两个参数是理想的情况,如果可能,应避免三个参数。 除此之外,还应该合并。大多数情况下,大于三个参数可以用对象来代替。


// 不好的写法
function createMenu(title, body, buttonText, cancellable) {
  // ...
}

createMenu("Foo", "Bar", "Baz", true);

// 好的写法
function createMenu({ title, body, buttonText, cancellable }) {
  // ...
}

createMenu({
  title: "Foo",
  body: "Bar",
  buttonText: "Baz",
  cancellable: true
});

函数应该只做一件事

这是目前为止软件工程中最重要的规则。当函数做不止一件事时,它们就更难组合、测试和推理。可以将一个函数隔离为一个操作时,就可以很容易地重构它,代码也会读起来更清晰。


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

// 好的写法

function emailActiveClients(clients) {
  clients.filter(isActiveClient).forEach(email);
}

function isActiveClient(client) {
  const clientRecord = database.lookup(client);
  return clientRecord.isActive();
}

函数名称应说明其作用


// 不好的写法
function addToDate(date, month) {
  // ...
}

const date = new Date();

// 从函数名称很难知道添加什么
addToDate(date, 1);

// 好的写法
function addMonthToDate(month, date) {
  // ...
}

const date = new Date();
addMonthToDate(1, date);

函数应该只有一个抽象层次

当有一个以上的抽象层次函数,意味该函数做得太多了,需要将函数拆分可以实现可重用性和更简单的测试。


// 不好的写法
function parseBetterjsAlternative(code) {
  const REGEXES = [
    // ...
  ];

  const statements = code.split(" ");
  const tokens = [];
  REGEXES.forEach(REGEX => {
    statements.forEach(statement => {
      // ...
    });
  });

  const ast = [];
  tokens.forEach(token => {
    // lex...
  });

  ast.forEach(node => {
    // parse...
  });
}

// 好的写法
function parseBetterJSAlternative(code) {
  const tokens = tokenize(code);
  const syntaxTree = parse(tokens);
  syntaxTree.forEach(node => {
    // parse...
  });
}

function tokenize(code) {
  const REGEXES = [
    // ...
  ];

  const statements = code.split(" ");
  const tokens = [];
  REGEXES.forEach(REGEX => {
    statements.forEach(statement => {
      tokens.push();
    });
  });

  return tokens;
}

function parse(tokens) {
  const syntaxTree = [];
  tokens.forEach(token => {
    syntaxTree.push();
  });

  return syntaxTree;
}

删除重复的代码

尽量避免重复的代码,重复的代码是不好的,它意味着如果我们需要更改某些逻辑,要改很多地方。

通常,有重复的代码,是因为有两个或多个稍有不同的事物,它们有很多共同点,但是它们之间的差异迫使我们编写两个或多个独立的函数来完成许多相同的事情。 删除重复的代码意味着创建一个仅用一个函数/模块/类就可以处理这组不同事物的抽象。

获得正确的抽象是至关重要的,这就是为什么我们应该遵循类部分中列出的SOLID原则。糟糕的抽象可能比重复的代码更糟糕,所以要小心!说了这么多,如果你能做一个好的抽象,那就去做吧!不要重复你自己,否则你会发现自己在任何时候想要改变一件事的时候都要更新多个地方。

设计模式的六大原则有:

  • Single Responsibility Principle:单一职责原则
  • Open Closed Principle:开闭原则
  • Liskov Substitution Principle:里氏替换原则
  • Law of Demeter:迪米特法则
  • Interface Segregation Principle:接口隔离原则
  • Dependence Inversion Principle:依赖倒置原则

把这六个原则的首字母联合起来(两个 L 算做一个)就是 SOLID (solid,稳定的),其代表的含义就是这六个原则结合使用的好处:建立稳定、灵活、健壮的设计。下面我们来分别看一下这六大设计原则。

不好的写法


function showDeveloperList(developers) {
  developers.forEach(developer => {
    const expectedSalary = developer.calculateExpectedSalary();
    const experience = developer.getExperience();
    const GitHubLink = developer.getgithubLink();
    const data = {
      expectedSalary,
      experience,
      githubLink
    };

    render(data);
  });
}

function showManagerList(managers) {
  managers.forEach(manager => {
    const expectedSalary = manager.calculateExpectedSalary();
    const experience = manager.getExperience();
    const portfolio = manager.getMBAProjects();
    const data = {
      expectedSalary,
      experience,
      portfolio
    };

    render(data);
  });
}

好的写法


function showEmployeeList(employees) {
  employees.forEach(employee => {
    const expectedSalary = employee.calculateExpectedSalary();
    const experience = employee.getExperience();

    const data = {
      expectedSalary,
      experience
    };

    switch (employee.type) {
      case "manager":
        data.portfolio = employee.getMBAProjects();
        break;
      case "developer":
        data.githubLink = employee.getGithubLink();
        break;
    }

    render(data);
  });
}

使用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",
  // User did not include 'body' key
  buttonText: "Send",
  cancellable: true
};

function createMenu(config) {
  config = Object.assign(
    {
      title: "Foo",
      body: "Bar",
      buttonText: "Baz",
      cancellable: true
    },
    config
  );

  // config now equals: {title: "Order", body: "Bar", buttonText: "Send", cancellable: true}
  // ...
}

createMenu(menuConfig);

不要使用标志作为函数参数

标志告诉使用者,此函数可以完成多项任务,函数应该做一件事。 如果函数遵循基于布尔的不同代码路径,请拆分它们。


// 不好的写法
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}`);
}

避免副作用(第一部分)

如果函数除了接受一个值并返回另一个值或多个值以外,不执行任何其他操作,都会产生副作用。 副作用可能是写入文件,修改某些全局变量,或者不小心将你的所有资金都汇给了陌生人。

不好的写法


let name = "Ryan McDermott";

function splitIntoFirstAndLastName() {
  name = name.split(" ");
}

splitIntoFirstAndLastName();

console.log(name); // ['Ryan', 'McDermott'];

好的写法


function splitIntoFirstAndLastName(name) {
  return name.split(" ");
}

const name = "Ryan McDermott";
const newName = splitIntoFirstAndLastName(name);

console.log(name); // 'Ryan McDermott';
console.log(newName); // ['Ryan', 'McDermott'];

避免副作用(第二部分)

javascript中,原始类型值是按值传递,而对象/数组按引用传递。 对于对象和数组,如果有函数在购物车数组中进行了更改(例如,通过添加要购买的商品),则使用该购物车数组的任何其他函数都将受到此添加的影响。 那可能很棒,但是也可能不好。 来想象一个糟糕的情况:

用户单击“购买”按钮,该按钮调用一个purchase函数,接着,该函数发出一个网络请求并将cart数组发送到服务器。由于网络连接不好,purchase函数必须不断重试请求。现在,如果在网络请求开始之前,用户不小心点击了他们实际上不需要的项目上的“添加到购物车”按钮,该怎么办?如果发生这种情况,并且网络请求开始,那么购买函数将发送意外添加的商品,因为它有一个对购物车数组的引用,addItemToCart函数通过添加修改了这个购物车数组。

一个很好的解决方案是addItemToCart总是克隆cart数组,编辑它,然后返回克隆。这可以确保购物车引用的其他函数不会受到任何更改的影响。

关于这种方法有两点需要注意:

1.可能在某些情况下,我们确实需要修改输入对象,但是当我们采用这种编程实践时,会发现这种情况非常少见,大多数东西都可以被改造成没有副作用。

2.就性能而言,克隆大对象可能会非常昂贵。 幸运的是,在实践中这并不是一个大问题,因为有很多很棒的库使这种编程方法能够快速进行,并且不像手动克隆对象和数组那样占用大量内存。


// 不好的写法
const addItemToCart = (cart, item) => {
  cart.push({ item, date: Date.now() });
};

// 好的写法
const addItemToCart = (cart, item) => {
  return [...cart, { item, date: Date.now() }];
};

不要写全局函数

污染全局变量在 JS 中是一种不好的做法,因为可能会与另一个库发生冲突,并且在他们的生产中遇到异常之前,api 的用户将毫无用处。 让我们考虑一个示例:如果想扩展 JS 的原生Array方法以具有可以显示两个数组之间差异的diff方法,该怎么办? 可以将新函数写入Array.prototype,但它可能与另一个尝试执行相同操作的库发生冲突。 如果其他库仅使用diff来查找数组的第一个元素和最后一个元素之间的区别怎么办? 这就是为什么只使用 es6 类并简单地扩展Array全局会更好的原因。


// 不好的写法
Array.prototype.diff = function diff(comparisonArray) {
  const hash = new Set(comparisonArray);
  return this.filter(elem => !hash.has(elem));
};

// 好的写法
class SuperArray extends Array {
  diff(comparisonArray) {
    const hash = new Set(comparisonArray);
    return this.filter(elem => !hash.has(elem));
  }
}

尽量使用函数式编程而非命令式

JavaScript不像Haskell那样是一种函数式语言,但它具有函数式的风格。函数式语言可以更简洁、更容易测试。如果可以的话,尽量喜欢这种编程风格。

不好的写法


const programmerOutput = [
  {
    name: "Uncle Bobby",
    linesOfCode: 500
  },
  {
    name: "Suzie Q",
    linesOfCode: 1500
  },
  {
    name: "Jimmy Gosling",
    linesOfCode: 150
  },
  {
    name: "Gracie Hopper",
    linesOfCode: 1000
  }
];

let totalOutput = 0;

for (let i = 0; i < programmerOutput.length; i++) {
  totalOutput += programmerOutput[i].linesOfCode;
}

好的写法


const programmerOutput = [
  {
    name: "Uncle Bobby",
    linesOfCode: 500
  },
  {
    name: "Suzie Q",
    linesOfCode: 1500
  },
  {
    name: "Jimmy Gosling",
    linesOfCode: 150
  },
  {
    name: "Gracie Hopper",
    linesOfCode: 1000
  }
];

const totalOutput = programmerOutput.reduce(
  (totalLines, output) => totalLines + output.linesOfCode,
  0
);

封装条件


// 不好的写法
if (fsm.state === "fetching" && isEmpty(listNode)) {
  // ...
}

// 好的写法
function shouldShowSpinner(fsm, listNode) {
  return fsm.state === "fetching" && isEmpty(listNode);
}

if (shouldShowSpinner(fsmInstance, listNodeInstance)) {
  // ...
}

避免使用非条件


// 不好的写法
function isDOMNodeNotPresent(node) {
  // ...
}

if (!isDOMNodeNotPresent(node)) {
  // ...
}

// 好的写法
function isDOMNodePresent(node) {
  // ...
}

if (isDOMNodePresent(node)) {
  // ...
}

避免使用过多条件

这似乎是一个不可能完成的任务。一听到这个,大多数人会说,“没有if语句,我怎么能做任何事情呢?”答案是,你可以在许多情况下使用多态性来实现相同的任务。

第二个问题通常是,“那很好,但是我为什么要那样做呢?”答案是上面讲过一个概念:一个函数应该只做一件事。当具有if语句的类和函数时,这是在告诉你的使用者该函数执行不止一件事情。

不好的写法


class Airplane {
  // ...
  getCruisingAltitude() {
    switch (this.type) {
      case "777":
        return this.getMaxAltitude() - this.getPassengerCount();
      case "Air Force One":
        return this.getMaxAltitude();
      case "Cessna":
        return this.getMaxAltitude() - this.getFuelExpenditure();
    }
  }
}

好的写法


class Airplane {
  // ...
}

class Boeing777 extends Airplane {
  // ...
  getCruisingAltitude() {
    return this.getMaxAltitude() - this.getPassengerCount();
  }
}

class AirForceOne extends Airplane {
  // ...
  getCruisingAltitude() {
    return this.getMaxAltitude();
  }
}

class Cessna extends Airplane {
  // ...
  getCruisingAltitude() {
    return this.getMaxAltitude() - this.getFuelExpenditure();
  }
}

避免类型检查

JavaScript 是无类型的,这意味着函数可以接受任何类型的参数。 有时q我们会被这种自由所困扰,并且很想在函数中进行类型检查。 有很多方法可以避免这样做。 首先要考虑的是一致的API。


// 不好的写法
function travelToTexas(vehicle) {
  if (vehicle instanceof Bicycle) {
    vehicle.pedal(this.currentLocation, new Location("texas"));
  } else if (vehicle instanceof Car) {
    vehicle.drive(this.currentLocation, new Location("texas"));
  }
}

// 好的写法
function travelToTexas(vehicle) {
  vehicle.move(this.currentLocation, new Location("texas"));
}

不要过度优化

现代浏览器在运行时做了大量的优化工作。很多时候,如果你在优化,那么你只是在浪费时间。有很好的资源可以查看哪里缺乏优化,我们只需要针对需要优化的地方就行了。


// 不好的写法

// 在旧的浏览器上,每一次使用无缓存“list.length”的迭代都是很昂贵的
// 会为“list.length”重新计算。在现代浏览器中,这是经过优化的
for (let i = 0, len = list.length; i < len; i++) {
  // ...
}

// 好的写法
for (let i = 0; i < list.length; i++) {
  // ...
}

以上就是如何写出优雅的JS 代码的详细内容,更多关于优雅的JS 代码的资料请关注编程网其它相关文章!

--结束END--

本文标题: 如何写出优雅的JS 代码

本文链接: https://lsjlt.com/news/125297.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何写出优雅的JS 代码
    目录变量使用有意义和可发音的变量名对同一类型的变量使用相同的词汇使用可搜索的名字使用解释性变量避免费脑的猜测无需添加不必要的上下文使用默认参数代替逻辑或(与)运算函数函数参数(理想情...
    99+
    2024-04-02
  • 怎么写出优雅的Java代码
    这篇文章主要讲解了“怎么写出优雅的Java代码”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么写出优雅的Java代码”吧!1.使用 IntelliJ IDEA 作为您的集成开发环境 (ID...
    99+
    2023-06-16
  • 怎么写出优雅的C++代码
    本篇内容主要讲解“怎么写出优雅的C++代码”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么写出优雅的C++代码”吧!工欲善其事必先利其器,优雅的代码离不开静态代码检查工具,大家可能平时使用较多...
    99+
    2023-06-15
  • 如何借助AngularJS写优雅的代码
    本篇文章为大家展示了如何借助AngularJS写优雅的代码,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。接触AngularJS还真有点碰巧,在用JQuery写数据绑...
    99+
    2024-04-02
  • 如何写出优雅的vue.js
    这篇文章主要为大家展示了“如何写出优雅的vue.js”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何写出优雅的vue.js”这篇文章吧。1. watch 与 ...
    99+
    2024-04-02
  • 怎么写出优雅耐看的css代码
    这篇“怎么写出优雅耐看的css代码”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面...
    99+
    2024-04-02
  • 怎么写出优雅耐看的JavaScript代码
    这篇文章主要介绍“怎么写出优雅耐看的JavaScript代码”,在日常操作中,相信很多人在怎么写出优雅耐看的JavaScript代码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解...
    99+
    2024-04-02
  • 怎么写出清晰又优雅的Python代码
    本篇文章为大家展示了怎么写出清晰又优雅的Python代码,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。个人认为,下面这几条规则是绝对应该遵循的。01 与空白有关的建议在Python中,空白(whit...
    99+
    2023-06-15
  • ASP Web部署的艺术:如何写出优雅高效的代码
    编写可重用组件 可重用组件可以极大地提高开发效率和代码的可维护性。ASP提供了许多内置组件,如ASP.NET Web Forms和ASP.NET MVC,这些组件可以用于构建各种Web应用程序。此外,还可以创建自己的自定义组件,以满...
    99+
    2024-02-21
    ASP Web部署 代码优化 组件 缓存 数据库查询
  • 助您写出优雅的Java代码七点建议
    有的Java程序代码一眼看上去就让人觉得混乱且费解,而有的代码却能给人如沐春风之感。本文将通过七点建议,帮助您写出更好、更优雅的程序代码。...
    99+
    2023-06-02
  • 如何写出高质量JS代码
    这篇文章主要介绍如何写出高质量JS代码,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、如何书写可维护性的代码当出现bug的时候如果你能立马修复它是最好的,此时解决问题的四路在你脑中...
    99+
    2024-04-02
  • 如何用Java Stream写出既高雅又装*的代码
    目录一. 冷静分析二. 直接开装2.1 初级炫2.2 普通炫2.3 高级炫2.4 再炫一波 拿到当前key与对应的数量2.5 Map Reduce炫 git仓库直达 List&l...
    99+
    2024-04-02
  • 详解Go语言如何利用高阶函数写出优雅的代码
    目录前言问题白银黄金王者总结前言 go项目中经常需要查询db,按照以前java开发经验,会根据查询条件写很多方法,如: GetUserByUserIDGetUsersByNameGe...
    99+
    2023-01-05
    Go语言高阶函数 Go语言 函数 Go 高阶函数
  • 教你如何写出可维护的JS代码
    目录什么是可维护代码代码约定1.可读性2.变量和函数的命名3.变量类型透明松散耦合1.解耦html/JavaScript2.解耦css/JavaScript3.解耦应用逻辑/事件处理...
    99+
    2024-04-02
  • 如何JS代码变得更加优雅且可维护
    本篇内容介绍了“如何JS代码变得更加优雅且可维护”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!语义化首先便...
    99+
    2024-04-02
  • 编写高效且优雅的 Python 代码(
    貌似只能创建一个专栏,所以这篇文章只好放到“JavaScript从前端到全终端”里了 原文链接:Effective Python Python 作为一门入门极易并容易上瘾的语音,相信已经成为了很多人 “写着玩” 的标配脚本语言。但很多...
    99+
    2023-01-31
    高效 优雅 代码
  • JS优雅的写法有哪些
    今天小编给大家分享一下JS优雅的写法有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。JS的一些优雅写法reduce可以使...
    99+
    2023-07-05
  • 如何编写优雅的Dockerfile
    导读Kubernetes要从容器化开始,而容器又需要从Dockerfile开始,本文将介绍如何写出一个优雅的Dockerfile文件。文章主要内容包括:Docker容器Dockerfile使用多阶构建感谢公司提供大量机器资源及时间让我们可以...
    99+
    2023-06-03
  • 怎么写出干净的JS代码
    本篇内容介绍了“怎么写出干净的JS代码”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. 将数字定义为常量...
    99+
    2024-04-02
  • JS如何优化代码
    这篇文章主要介绍了JS如何优化代码,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、松耦合当修改一个组件而不需要更改其他组件时,就做到了松耦...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作