程序员的10个编程小技巧,教你写出高质量代码

编码规范是成为一个优质程序员的重要一课,它是编程的样式的模板。这篇文章将介绍12中编程规范及技巧,相信学习之后你的代码一定会提升一个档次。

首先我们要明确,为什么要遵循编码规范?遵循这样的约定有什么好处?

1. 遵循规范可以写出干净简洁的代码

2. 可以代码的质量

3. 提升代码的可读性

4. 使代码维护更加容易

代码整洁之道一书的作者罗伯特曾经说过:

“干净的代码既简单又直接。干净的代码读起来像写得很好的散文。简洁的代码永远不会掩盖设计者的意图,而是充满清晰的抽象和直接的控制线。” -罗伯特·马丁(Robert C. Martin)

1.不要出现莫名其妙的数字

很多程序员在实现功能的时候会分配一个没有明确意义的数字,用于特定的目的,写完这个数字后没有即使去做注释,然后过两天当程序出现问题时,翻看代码碰到这个数字,连自己都忘了它的意义。当程序需要固定的数值参与时,给予特定的名称。

案例

//错误的示范:

for(let i = 0; i < 50; i++){

//do something

}

//正确的示范:

let NUMBER_OF_STUDENTS= 50

for(let i = 0; i < NUMBER_OF_STUDENTS; i++){

//do something

}

2.深度嵌套

有些程序需要使用到无数次的嵌套循环,看着看着就晕了,这时可以将所有循环提取到单独的函数中。

假设有一个包含两层嵌套的数组,想要拿到最后一个数组的值?一般情况下开发者都会使用嵌套循环,但不是最佳的办法。可以尝试使用函数的反复调用来完成操作执行相同操作的,这样一来代码重复性更小,更易于阅读、重用性高。

// 错误示范

const array = [ [ [\’Shoaib Mehedi\’] ] ]

array.forEach((firstArr) =>{

firstArr.forEach((secondArr) => {

secondArr.forEach((element) => {

console.log(element);

})

})

})

// 正确示范

const array = [ [ [\’Shoaib Mehedi\’] ] ]

const getValuesOfNestedArray = (element) => {

if(Array.isArray(element)){

return getValuesOfNestedArray(element[0])

}

return element

}

getValuesOfNestedArray(array)

3.注释

注释是一个老生常谈的话题,很多人不重视,为了快速完成项目忽略注释,导致后期修改和复用出现很大问题,得不偿失。

4.避免创建大函数

当一个函数或一个类需要实现的功能太多时,建议将其分成多个小的函数。

假设我们需要加减两个数字。我们可以用一个功能做到这一点。但是好的做法是将它们分为两部分。如果有单独的功能,则可以在整个应用程序中重复使用。

// 错误示范

const addSub = (a,b) => {

// add

const addition = a+b

// sub

const sub = a-b

// returning as a string

return `${addition}${sub}`

}

//正确示范

// add

const add = (a,b) => {

return a+b

}

// sub

const sub = (a,b) => {

return a-b

}

5.重复代码

重复代码也是常见的问题,如遇到此情况,将重复代码提取到函数中。

继续用上面的第2点“深层嵌套”中的例子来举例。

// 错误示范

const array = [ [ [\’Shoaib Mehedi\’] ] ]

array.forEach((firstArr) =>{

firstArr.forEach((secondArr) => {

secondArr.forEach((element) => {

console.log(element);

})

})

})

// 正确示范

const array = [ [ [\’Shoaib Mehedi\’] ] ]

const getValuesOfNestedArray = (element) => {

if(Array.isArray(element)){

return getValuesOfNestedArray(element[0])

}

return element

}

getValuesOfNestedArray(array)

6.变量命名

变量命名也是有讲究的,好的变量命名可以让代码更加通俗易懂,一般来说命名遵循以下标准,名称以小写字母开头,之后的每一个单词首字母都用大写,比如骆驼的大小写为camelCase

函数和变量都必须遵循此规则。

示例代码:

let camelCase = \’\’const thisIsCamelCase = () => { //so something}

7.函数命名

函数的命名基本与上述提到的变量命名规则基本一样,但需要注意的是,命名尽量注意详细,比如我们需要一个能够获取用户银行信息的功能,那么要尽量将命名具体化,如下

错误的示范:getUserInfo。

正确的示范:getUserBankInfo

8.命名时注意动词的使用

比如我们需要从数据库中获取用户信息,函数的名称可以是userInfo,user或者fetchUser,但我推荐使用含有动词的命名 getUser。

//正确示范

function getUser(){//do something}

9. 常量值所有都大写

常量命名都使用全大写的名称,并用下划线分割所有单词

//正确示范

const DAYS_IN_A_YEAR = 365;

10. 避免变量使用字母

在功能性的命名中尽量避免使用单个字母,不过如果在循环中,可以忽略这一点

//错误示范

const q = () => {

//….

}

//正确示范

const query = () => {

//….

}//this is also okay

for(let i = 0;i < 10; i++){

//…

}

结论

从长远来看,遵循代码编写规范,对开发者的自身发展来说是百利而无一害的。每个项目的生命周期都很长,在很长的周期中谁也无法确定会用到之前的哪段代码,哪个功能。所以对现在的每一段代码负责,就是对以后的自己负责。加油,程序猿!!!

7 行代码 3 分钟:从零开始实现一门编程语言

本文最初发布于 Matt Might 的个人博客。

本文介绍了多种解释器实现。通过修改最后一个解释器,你应该可以快速测试关于编程语言的新想法。如果你希望有一种语法不一样的语言,就可以构建一个解析器,把 s-表达式转储。这样,你就可以干净利落地将语法设计与语义设计分开。

实现一门编程语言是任何程序员都不应该错过的经验;这个过程可以培养你对计算的深刻理解,而且很有趣。

本文直击本质,把整个过程归结为:一个面向函数式(但图灵等价)编程语言的 7 行解释器,而其实现只需要大约 3 分钟。

这个 7 行的解释器展示了许多解释器中都存在的可扩展架构——《计算机程序的结构与解释》中的 eval/apply 设计模式:

本文中总共有三种语言的实现:

  • 一个使用 Scheme 耗时 3 分钟实现的 7 行解释器;
  • 使用Racket重新实现;
  • 一个耗时“一下午”实现的 100 行解释器,实现了顶层绑定形式、显式递归、副作用、高阶函数等功能。如果想要实现一门功能更丰富的语言,那么最后一个解释器是一个不错的起点。

最容易实现的编程语言是一种极简的高阶函数式编程语言,名为λ演算(lambda calculus)。

实际上,λ演算是所有主要的函数式语言的核心——Haskell、Scheme 和 ML——但它也存在于 JavaScript、Python 和 Ruby 中。它甚至隐藏在 Java 中,不知道你是否知道在哪里可以找到它。

阿隆佐·丘奇在 1929 年开发了λ演算。

那时,它还不叫编程语言,因为当时没有计算机;没有什么东西可以“编程”。

它实际上只是一个用于函数推理的数学符号。幸运的是,阿隆佐·丘奇有一个博士生叫艾伦·图灵。

艾伦·图灵定义了图灵机,这成为通用计算机第一个公认的定义。

人们很快发现,λ演算和图灵机是等价的:任何能用λ演算描述的函数都能在图灵机上实现,而任何能在图灵机上实现的函数都能用λ演算描述。

值得注意的是,λ演算中只有三种表达式:变量引用、匿名函数和函数调用。

匿名函数的编写采用“lambda-dot”标记法,如下所示:

复制代码

该函数接受参数v ,返回值e 。如果用 JavaScript 编写,上述代码等价于:

复制代码

函数调用的写法是使两个表达式相邻:

复制代码

JavaScript(或其他任何语言)的写法如下:

复制代码

将参数原样返回的恒等函数写法如下:

复制代码

我们可以将恒等函数应用于恒等函数:

复制代码

(返回当然也是恒等函数。)下面这个程序更有意思一些:

复制代码

你能搞懂它做了什么吗?

乍一看,这门简单的语言似乎缺少递归和迭代,更不用说数值、布尔、条件、数据结构等其他东西。这种语言怎么可能是通用的呢?

λ演算达到图灵等价是通过两个最酷的编程黑科技实现的:Church 编码和 Y 组合子。

关于 Y 组合子,我已经写过一篇文章,关于Church编码,也写过一篇。不过,你不想读这些文章也没事,我只需一个程序就可以说服你,λ演算的功能远超你的预期:

复制代码

这个看上去无害的程序名为 Omega,如果你试图执行它,就发现它不会终止!(看看你能不能找出原因)。

下面是用 R5RS Scheme 耗时 3 分钟实现的一个 7 行λ演算解释器。从技术上讲(下文有解释),它是一个基于环境的指示型解释器。

复制代码

这段代码将从 stdin 读取一个程序,解析它,求值并打印结果。(去掉注释和空行,它只有 7 行)。Scheme 的read函数简化了词法分析和解析——只要你愿意生活在“平衡圆括号”(即s-表达式)的语法世界中。(如果不愿意,你就必须仔细研究解析中的词法分析;可以从我的一篇关于词法分析的文章入手)。在 Scheme 中,read从 stdin 中获取括号括起来的输入,并将其解析为一棵树。

evalapply 两个函数构成了解释器的核心。尽管是在 Scheme 中,但我们可以给予这些函数概念上的“签名”:

复制代码

eval函数接收一个表达式和一个环境然后转换为一个值。表达式可以是一个变量,一个 lambda 项或一个应用程序。环境是一个从变量到值的映射,用来定义一个开项的自由变量。(开项是一个变量的非绑定出现。)例如,考虑一下表达式(λ x . z)。这个项是开放的,因为我们不知道z是什么。

由于用的是 R5RS Scheme,我们可以使用关联列表来定义环境。

闭包是一个函数的编码,它将一个(可能是开放的)lambda 表达式与一个环境配对,以定义其自由变量。换句话说,一个闭包封闭了一个开项。

Racket是 Scheme 的一种方言,它功能齐备,可以把事情做好。Racket 提供了一个可以清理解释器的匹配结构,如下所示:

复制代码

这个代码多点,但更简洁,更容易理解。

λ演算是一门很小的语言。即便如此,其解释器的 eval/apply 设计也可以扩展到更大的语言。例如,用大约 100 行代码,我们可以为一个相当大的 Scheme 子集实现一个解释器。

考虑一种具有各种表达形式的语言:

  1. 变量引用,如:xfoosave-file
  2. 数值和布尔常量,如:3003.14#f
  3. 基本操作,如:+<=
  4. 条件:(if condition if-true if-false)
  5. 变量绑定:(let ((var value) …) body-expr)
  6. 递归绑定:(letrec ((var value) …) body-expr)
  7. 变量可变:(set! var value)
  8. 定序:(begin do-this then-this)。现在,为这门语言添加 3 个顶层形式:
  9. 函数定义:(define (proc-name var …) expr)
  10. 全局定义:(define var expr)
  11. 顶层表达式:expr。下面是完整的解释器,其中包括测试工具和测试用例:

复制代码

下载源代码,请点击https://matt.might.net/articles/implementing-a-programming-language/minilang.rkt?accessToken=eyJhbGciOiJIUzI1NiIsImtpZCI6ImRlZmF1bHQiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJhY2Nlc3NfcmVzb3VyY2UiLCJleHAiOjE2NTU0NTMzMzAsImZpbGVHVUlEIjoibG9xZVcyRXl2d0hkSkxBbiIsImlhdCI6MTY1NTQ1MzAzMCwidXNlcklkIjoyMDQxOTA5MH0.Nv5UyUdCUJNT7c0kIaPSE0g0f4k9Ed26rLl2Bu5RpG4

通过修改最后一个解释器,你应该可以快速测试关于编程语言的新想法。

如果你希望有一种语法不一样的语言,就可以构建一个解析器,把 s-表达式转储。这样,你就可以干净利落地将语法设计与语义设计分开。

查看英文原文:

https://matt.might.net/articles/implementing-a-programming-language?accessToken=eyJhbGciOiJIUzI1NiIsImtpZCI6ImRlZmF1bHQiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJhY2Nlc3NfcmVzb3VyY2UiLCJleHAiOjE2NTU0NTMzMzAsImZpbGVHVUlEIjoibG9xZVcyRXl2d0hkSkxBbiIsImlhdCI6MTY1NTQ1MzAzMCwidXNlcklkIjoyMDQxOTA5MH0.Nv5UyUdCUJNT7c0kIaPSE0g0f4k9Ed26rLl2Bu5RpG4

本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com

点赞 0
收藏 0

文章为作者独立观点不代本网立场,未经允许不得转载。