前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何编写漂亮的 JavaScript 代码

如何编写漂亮的 JavaScript 代码

原创
作者头像
小鑫
发布2022-02-23 15:42:25
7810
发布2022-02-23 15:42:25
举报
文章被收录于专栏:小鑫の随笔

一、变量

传参使用默认值
代码语言:javascript
复制
// Bad:
function createMicrobrewery( name ) {
    const breweryName = name || 'Hipster Co.';
    // ...
}

// Good:
function createMicrobrewery( name = 'Hipster Co.' ) {
    // ...
}
避免无意义的命名

既然创建了一个car对象,就没有必要把它的颜色命名为 carColor

代码语言:javascript
复制
// Bad:
const car = {
    carMake: 'Honda',
    carModel: 'Accord',
    carColor: 'Blue'
};
function paintCar( car ) {
    car.carColor = 'Red';
}

// Good:
const car = {
    make: 'Honda',
    model: 'Accord',
    color: 'Blue'
};
function paintCar( car ) {
    car.color = 'Red';
}

二、函数

函数参数

如果参数超过两个,就使用ES6的解构语法,不用考虑参数的顺序

代码语言:javascript
复制
// Bad:
function createMenu( title, body, buttonText, cancellable ) {
    // ...
}

// Good:
function createMenu( { title, body, buttonText, cancellable } ) {
    // ...
}

createMenu({
    title: 'Foo',
    body: 'Bar',
    buttonText: 'Baz',
    cancellable: true
})
一个方法只做一件事

这是一条编程领域流传久远的规则。严格遵守这条规则会让你的代码可读性更好,也更容易重构。如果违反这个原则,那么代码会很难被测试或者重用。

代码语言:javascript
复制
// Bad:
function emailClients( clients ) {
    clients.forEach( client => {
        const clientRecord = database.lookup( client );
        if ( clientRecord.isActive() ) {
            email( client );
        }
    });
}

// Good:
function emailActiveClients( clients ) {
    clients
        .filter( isActiveClient )
        .forEach( email );
}
function isActiveClient( client ) {
    const clientRecord = database.lookup( client );    
    return clientRecord.isActive();
}
函数名上体现它的作用
代码语言:javascript
复制
// Bad:
function addToDate( date, month ) {
    // ...
}
const date = new Date();
// 很难知道是把什么加到日期中
addToDate( date, 1 );

// Good:
function addMonthToDate( month, date ) {
    // ...
}
const date = new Date();
addMonthToDate( 1, date );
删除重复代码,合并相似函数

很多时候虽然是同一个功能,但由于一两个不同点,让你不得不写两个几乎相同的函数。

代码语言:javascript
复制
// Bad:
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);
  });
}

// Good:
function showEmployeeList(employees) {
  employees.forEach(employee => {
    const expectedSalary = employee.calculateExpectedSalary();
    const experience = employee.getExperience();
    const data = {
      expectedSalary,
      experience,
    };
    switch(employee.type) {
      case 'develop':
        data.githubLink = employee.getGithubLink();
        break
      case 'manager':
        data.portfolio = employee.getMBAProjects();
        break
    }
    render(data);
  })
}
使用 Object.assign 设置默认属性
代码语言:javascript
复制
// Bad:
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);
// Good:
const menuConfig = {
  title: 'Order',
  // 不包含 body
  buttonText: 'Send',
  cancellable: true
};
function createMenu(config) {
  config = Object.assign({
    title: 'Foo',
    body: 'Bar',
    buttonText: 'Baz',
    cancellable: true
  }, config);
  // config : {title: "Order", body: "Bar", buttonText: "Send", cancellable: true}
  // ...
}
createMenu(menuConfig);
不要过度优化

现代浏览器已经在底层做了很多优化,过去的很多优化方案都是无效的,会浪费你的时间

代码语言:javascript
复制
// Bad:
// 现代浏览器已对此( 缓存 list.length )做了优化。
for (let i = 0, len = list.length; i < len; i++) {
  // ...
}

// Good:
for (let i = 0; i < list.length; i++) {
  // ...
}

三、类

使用 ES6 的class

在 ES6 之前,没有类的语法,只能用构造函数的方式模拟类,可读性非常差。

代码语言:javascript
复制
// Good:
// 动物
class Animal {
  constructor(age) {
    this.age = age
  };
  move() {};
}

// 哺乳动物
class Mammal extends Animal{
  constructor(age, furColor) {
    super(age);
    this.furColor = furColor;
  };
  liveBirth() {};
}

// 人类
class Human extends Mammal{
  constructor(age, furColor, languageSpoken) {
    super(age, furColor);
    this.languageSpoken = languageSpoken;
  };
  speak() {};
}
使用链式调用

这种模式相当有用,它能让代码更简洁优雅。

代码语言:javascript
复制
class Car {
  constructor(make, model, color) {
    this.make = make;
    this.model = model;
    this.color = color;
  }

  setMake(make) {
    this.make = make;
  }

  setModel(model) {
    this.model = model;
  }

  setColor(color) {
    this.color = color;
  }

  save() {
    console.log(this.make, this.model, this.color);
  }
}
// Bad:
const car = new Car('Ford','F-150','red');
car.setColor('pink');
car.save();

// Good: 
class Car {
  constructor(make, model, color) {
    this.make = make;
    this.model = model;
    this.color = color;
  }

  setMake(make) {
    this.make = make;
    // NOTE: Returning this for chaining
    return this;
  }

  setModel(model) {
    this.model = model;
    // NOTE: Returning this for chaining
    return this;
  }

  setColor(color) {
    this.color = color;
    // NOTE: Returning this for chaining
    return this;
  }

  save() {
    console.log(this.make, this.model, this.color);
    // NOTE: Returning this for chaining
    return this;
  }
}

const car = new Car("Ford", "F-150", "red").setColor("pink").save();

四、条件式和匹配条件的技巧

多个条件,使用 Array.includes

假设我们想要在函数中检查汽车模型是 renault 还是 peugeot。那么代码可能是这样的:

代码语言:javascript
复制
const checkCarModel = (model) => {
    if(model === 'renault' || model === 'peugeot') {
        console.log('model valid');
    }
}

checkCarModel('renault');   // 输出 'model valid'

考虑到只有两个模型,这样写勉强能接受,但如果我们还想要检查另一个或者是几个模型的话 还得增加更多的 or 语句,那么代码将变得难以维护,且不够整洁。为了让它更整洁,可以这样重写函数:

代码语言:javascript
复制
const checkCarModel = (model) => {
    if(['peugeot', 'renault'].includes(model)) {
        console.log('model valid');
    }
}

checkCarModel('renault');   // 输出 model valid

这时候 如果需要检查更多的模型,只需要添加数组的元素就可以了。

提前返回而不是使用 if...else 分支

假设我们想要显示所给的车辆的模型和生产年份:

代码语言:javascript
复制
const checkModel = (car) => {
    let result;     // 存储数据
    
    // 检查是否有车
    if(car) {
        
        // 检查是否有车的模型
        if(car.model) {
            
            // 检查是否有车的年份
            if(car.year) {
                result = `车的模型是:${car.model}; 车的年份是:${car.year}`;
            } else {
                result = '没有年份'
            }
            
        } else {
            result = '没有模型'
        }
        
    } else {
        result = '没有车'
    }
    
    return result;
}

console.log(checkModel());  // 输出 没有车
console.log(checkModel({ year: 1999 }));  // 输出 没有模型
console.log(checkModel({ model: 'ford' }));  // 输出 没有年份
console.log(checkModel({ model: 'ford',year: 1999 }));  // 输出车的模型是ford;车的年份是:1999

本身例子的问题很简单,但是上面的代码太长了。要是有更复杂的逻辑就会出现更多的 if..else 语句。

所以现在要重构函数,使用 ES6 的新特性和多个返回语句,展示一份简洁优雅的代码。

代码语言:javascript
复制
const checkModel =( {model, year} = {} ) => {
	// { model, year } 如果没有传值 默认为空对象
	if(!model && !year) return '没有车';
	if(!model) return '没有模型';
	if(!year) return '没有年份';

	return `车的模型是:${model}; 车的年份是:${year}`;
}
console.log(checkModel());  // 输出 没有车
console.log(checkModel({ year: 1999 }));  // 输出 没有模型
console.log(checkModel({ model: 'ford' }));  // 输出 没有年份
console.log(checkModel({ model: 'ford', year: 1999 }));  // 输出车的模型是 ford;车的年份是:1999

重构函数中,使用了解构和默认参数。参数如果传入 null ,函数将会抛出错误。

使用索引或者映射,而不是 switch 语句

假设完美想要基于给定的国家获取汽车模型

代码语言:javascript
复制
const getCarsByState = (state) => {
  switch (state) {
    case 'usa':
      return ['Ford', 'Dodge'];
    case 'france':
      return ['Renault', 'Peugeot'];
    case 'italy':
      return ['Fiat'];
    default:
      return [];
  }
}

console.log(getCarsByState()); // 输出 []
console.log(getCarsByState('usa')); // 输出 ['Ford', 'Dodge']
console.log(getCarsByState('italy')); // 输出 ['Fiat']

上述代码可以重构,完全去除 switch 语句

代码语言:javascript
复制
const cars = new Map()
  .set('usa', ['Ford', 'Dodge'])
  .set('france', ['Renault', 'Peugeot'])
  .set('italy', ['Fiat']);

const getCarsByState = (state) => {
  return cars.get(state) || [];
}

console.log(getCarsByState()); // 输出 []
console.log(getCarsByState('usa')); //输出 ['Ford', 'Dodge']
console.log(getCarsByState('italy')); // 输出 ['Fiat']

整合自:

https://juejin.im/post/5d11b494518825327a218454

https://juejin.im/post/5d0e11196fb9a07eee5ed6d2

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、变量
    • 传参使用默认值
      • 避免无意义的命名
      • 二、函数
        • 函数参数
          • 一个方法只做一件事
            • 函数名上体现它的作用
              • 删除重复代码,合并相似函数
                • 使用 Object.assign 设置默认属性
                  • 不要过度优化
                  • 三、类
                    • 使用 ES6 的class
                      • 使用链式调用
                      • 四、条件式和匹配条件的技巧
                        • 多个条件,使用 Array.includes
                          • 提前返回而不是使用 if...else 分支
                            • 使用索引或者映射,而不是 switch 语句
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档