博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript代码重构之:写好函数
阅读量:3959 次
发布时间:2019-05-24

本文共 6461 字,大约阅读时间需要 21 分钟。

1、函数要短小,一个函数只做一件事

如果函数做了较多的事情,它就难以组合、测试和推测。同时让函数只做一件事情的时候,它们就很容易重构。

// Badfunction showStudent(ssn){
const student = db.get(ssn);if(student !== null){
document.querySelector(`#${
elementId}`).innerHTML =`${
student.ssn}, ${
student.firstName}, ${
student.lastName}`} else{
thrownewError('student not found')}}showStudent('444-44-4444')// Goodfunction findStudent(db,id){
const student = db.get(id);if(student === null){
thrownewError('student not found');}};function getStudentInfo(student){
return`${
student.ssn},${
student.firstName},${
student.lastName}`};function showStudentInfo(elementId,info){
document.querySelector(elementId).innerHTML = info;}function showStudent(ssn){
const student = findStudent(ssn);let studentInfo = getStudentInfo(student); showStudentInfo(elementId,studentInfo);}

只是做了些许的改进,但已开始展现出很多的优势:undefined

2、每个函数一个抽象层级

函数中混杂不同的抽象层级,往往让人迷惑。读者可能无法判断某个表达式是基础概念还是细节。更恶劣的是,就像破损的窗户,一旦细节和基础概念混杂,更多的细节就会在函数中纠结起来。理解抽象层次请参考:抽象层次

// Badfunction parseBetterJSAlternative(code) {
let REGEXES = [// ...];let statements = code.split(' ');let tokens; REGEXES.forEach((REGEX) => {
statements.forEach((statement) => {
// ...})});let ast; tokens.forEach((token) => {
// lex...}); ast.forEach((node) => {
// parse...})}// Goodfunction tokenize(code) {
let REGEXES = [// ...];let statements = code.split(' ');let tokens; REGEXES.forEach((REGEX) => {
statements.forEach((statement) => {
// ...})});return tokens;}function lexer(tokens) {
let ast; tokens.forEach((token) => {
// lex...});return ast;}function parseBetterJSAlternative(code) {
let tokens = tokenize(code);let ast = lexer(tokens); ast.forEach((node) => {
// parse...})}

3、使用描述性的名称

函数越短小,功能越集中,就越便于取个好名字。长而具有描述性的名称,要比短而令人费解的名称好。长而具有描述性的名称,要比描述性的长注释好。使用某种命名约定,让函数名称中的多个单词容易阅读,然后使用这些单词给函数取个能说明其功能的名称。

// Badfunction dateAdd(date, month) {
// ...}let date = newDate();// 很难从函数名了解到加了什么dateAdd(date, 1);function write(name){
// ...}function assertEqual(a,b){
// ...}// Goodfunction dateAddMonth(date, month) {
// ...}let date = newDate();dateAddMonth(date, 1);// 告诉我们 name 是一个 fieldfunction writeField(name){
// ...}// 能更好的解释参数的顺序和意图function assertExpectedEqualActual(expected,actual){
// ...}

4、函数参数

最理想的参数数量是零,其次是一(单参数函数),再次是二(双参数函数),应尽量避免三(三参数函数)。有足够的理由才能使用三个以上参数。如果函数需要三个以上参数,就说明其中一些参数应该放在一个对象中了。参数越多,函数越不容易理解,同时编写能确保参数的各种组合运行正常的测试用例越困难。

5、避免副作用

如果一个函数不是获取一个输入的值并返回其它值,它就有可能产生副作用。这些副作用可能是写入文件、修改一些全局变量、屏幕打印或者日志记录、查询HTML文档、浏览器的cookie或访问数据库。无论哪种情况,都具有破坏性,会导致古怪的时序性耦合及顺序依赖。现在你确实需要在程序中有副作用。像前面提到的那样,你可能需要写入文件。现在你需要做的事情是搞清楚在哪里集中完成这件事情。不要使用几个函数或类来完成写入某个特定文件的工作。采用一个,就一个服务来完成。

// Bad// 下面的函数使用了全局变量。// 如果有另一个函数在使用 name,现在可能会因为 name 变成了数组而不能正常运行。var name = 'Ryan McDermott';function splitIntoFirstAndLastName() {
name = name.split(' ');}splitIntoFirstAndLastName();console.log(name); // ['Ryan', 'McDermott'];// Goodfunction splitIntoFirstAndLastName(name) {
return name.split(' ');}var name = 'Ryan McDermott'var newName = splitIntoFirstAndLastName(name);console.log(name); // 'Ryan McDermott';console.log(newName); // ['Ryan', 'McDermott'];

6、删除重复代码

重复代码意味着你要修改某些逻辑的时候要修改不止一个地方的代码。

// Badfunction showDeveloperList(developers) {
developers.forEach(developers => {
var expectedSalary = developer.calculateExpectedSalary();var experience = developer.getExperience();var githubLink = developer.getGithubLink();var data = {
expectedSalary: expectedSalary, experience: experience, githubLink: githubLink}; render(data);});}function showManagerList(managers) {
managers.forEach(manager => {
var expectedSalary = manager.calculateExpectedSalary();var experience = manager.getExperience();var portfolio = manager.getMBAProjects();var data = {
expectedSalary: expectedSalary, experience: experience, portfolio: portfolio}; render(data);});}// Goodfunction showList(employees) {
employees.forEach(employee => {
var expectedSalary = employee.calculateExpectedSalary();var experience = employee.getExperience();var portfolio;if(employee.type === 'manager') {
portfolio = employee.getMBAProjects();} else{
portfolio = employee.getGithubLink();}var data = {
expectedSalary: expectedSalary, experience: experience, portfolio: portfolio}; render(data);});}

7、使用更优雅写法

1、使用默认参数代替短路表达式

// Badfunction writeForumComment(subject, body) {
subject = subject || 'No Subject'; body = body || 'No text';}// Goodfunction writeForumComment(subject = 'No subject', body = 'No text') {
...}

2、用 Object.assign 设置默认对象

// Badconst 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);// Goodconst 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 等于: {title: "Foo", body: "Bar", buttonText: "Baz", cancellable: true}// ...}createMenu(menuConfig);

3、喜欢上命令式编程之上的函数式编程

// Badconst programmerOutput = [{
name: 'Uncle Bobby', linesOfCode: 500}, {
name: 'Suzie Q', linesOfCode: 1500}, {
name: 'Jimmy Gosling', linesOfCode: 150}, {
name: 'Gracie Hopper', linesOfCode: 1000}];var totalOutput = 0;for(var i = 0; i < programmerOutput.length; i++) {
totalOutput += programmerOutput[i].linesOfCode;}// Goodconst programmerOutput = [{
name: 'Uncle Bobby', linesOfCode: 500}, {
name: 'Suzie Q', linesOfCode: 1500}, {
name: 'Jimmy Gosling', linesOfCode: 150}, {
name: 'Gracie Hopper', linesOfCode: 1000}];var totalOutput = programmerOutput.map((programmer) => programmer.linesOfCode).reduce((acc, linesOfCode) => acc + linesOfCode, 0);

8、不要把标记用作函数参数

标记告诉你的用户这个函数做的事情不止一件。但是函数应该只做一件事。如果你的函数中会根据某个布尔参数产生不同的分支,那就拆分这个函数。

// Badfunction createFile(name, temp) {
if(temp) {
fs.create('./temp/'+ name);} else{
fs.create(name);}}// Goodfunction createTempFile(name) {
fs.create('./temp/'+ name);}function createFile(name) {
fs.create(name);}

转载地址:http://isozi.baihongyu.com/

你可能感兴趣的文章
位运算(含应用)
查看>>
野指针与空指针
查看>>
图文混排效果
查看>>
urllib2.urlopen超时问题
查看>>
Choosing a Machine Learning Classifier
查看>>
魏兴国:深入浅出DDoS攻击防御
查看>>
使连续的参考文献能够中间用破折号连起来
查看>>
Discover Feature Engineering, How to Engineer Features and How to Get Good at It
查看>>
36辆车,6条跑道,无计时器,最少几次比赛可以选出前三
查看>>
matlab2012b与matlab7.1执行set(gca,'Yscale','log')之后画到的直方图结果居然不同
查看>>
python读大文件
查看>>
python 3里没有cmp这个函数了
查看>>
回文题
查看>>
二叉树的最短根到叶路径中点的个数
查看>>
给定二叉树求最小深度
查看>>
平衡树
查看>>
栈的应用题(1)
查看>>
判断链表是否有环
查看>>
从有序链表中去掉重复的
查看>>
后台程序结果重定向到文件,结果看不到文件?缓冲区的问题
查看>>