JavaScript 编程风格(书写习惯)

简介: JavaScript 编程风格(书写习惯)

前言


一门编程语言的“语法规则”(grammar)应该是每一位开发者都必须遵循的;而“编程风格”则可自由选择。


假设团队中有 100 位成员,然后每位成员的 coding 风格都不一样,而且团队中没有明确的编写规范,那 Code Review 的时候,不得打起来,或者内心口吐芬芳......所以,社区中出现了很多 Lint 工具来帮助团队去规范书写习惯,如 ESLintPrettier 等等...


“编程风格”的选择不应该基于个人爱好、熟悉程度、打字工作量等因素,而要考虑如何尽量使代码清晰易读、减少出错。你选择的,不是你喜欢的风格,而是一种能够清晰表达你的意图的风格。


推荐 JavaScript 权威 Douglas Crockford 的一篇演讲(Youtube)。


正文


一、大括号位置


规则 1:表示区块起首的大括号,不要另起一行。


绝大多数的编程语言,都用大括号 {} 表示区块(block),JavaScript 也一样。

常见的写法有以下两种:

// bad
block
{
  // ...
}

// good
block {
  // ...
}


由于 JavaScript 的 自动插入分号(Automatic Semicolon Insertion,简称 ASI)机制,导致一些难以察觉的错误。


因此,原则上更推荐后者的写法:起首的大括号跟在关键字的后面


例如:

return
{
  key: 'value'
}


上面的代码原意是要返回一个对象,但实际上返回值为 undefined。因为 ASI 的原因,JavaScript 解析器会在return 后面插入分号 ;,由于分号是终止符,解析器就认为这个语句结束了。


类似 return 的特定语句,在 ASI 中被称为 restricted production。它包括以下几个语法,均不能换行:


  • 后缀表达式 ++--
  • return
  • continue
  • break
  • throw
  • ES6 的箭头函数(参数和箭头之间不能换行)
  • yield


这些无需死记,因为按照一般的书写习惯,几乎没有人会这样换行的。如果有的话,打 si 它。


二、圆括号的位置


圆括号(parentheses)在 JavaScript 中有两种作用,一种是表示调用函数,另一种是表示不同的值的组合(grouping)。我们可以用空格区分两种不同的圆括号。


规则 2:调用函数的时候,函数名与左括号之间没有空格。

// bad
foo (bar)
// good
foo(bar)


规则 3:函数名与参数序列之间,没有空格。

// bad
function fn (foo) {
  // ...
}
// good
function fn(foo) {
  // ...
}


规则 4:所有其他语法元素与左括号之间,都有一个空格。

// bad
return(foo + bar)
// good
return (foo + bar)


上面这个示例,其实最好去掉圆括号,其实在这句语句里面它是不需要圆括号的。这里只是为了举例而已。


相信很多人对以上三条建议,不屑一顾。2021 年了,那就交给 Prettier 处理吧。


三、不要省略分号


规则 5:不要省略句末的分号。


其实我是偏向 semicolon-less 风格,我认为通篇少了 99% 的分号,看起来会简洁很多。


但是这时候,有人就会举出类似示例,来反对“无分号党”了:

a = b
(function () {
  // ...
})


由于 ASI 机制,JavaScript 解析器看到的会是这这样子:

a = b(function () {
  // ...
});


是的,这样就得不到预期的结果。但是作为合格的 semicolon-less 风格的码农(俗称 coder),如果一条语句是以 ([/+- 开头,我们会在该语句的行首主动键入分号来避免分号 ; 来避免 ASI 机制产生的非逾期结果或报错。


在实际项目中,以 /+- 作为行首的代码其实是很少的,([ 也是较少的。


如果你说这很容易忘记键入分号,那说明你不是合格的“无分号党”,那还是乖乖敲分号吧!或许多数人更容易忘记,所以才有了“不要省略句末分号”的推荐写法吧。(算是少数服从多数的妥协吧)


对于不加思考而一味否定 semicolon-less 的人,我还是给出尤大那句话:所有直觉性的 “当然应该加分号” 都是保守的、未经深入思考的草率结论。


四、with 语句


规则 6:不要使用 with 语句。

with (obj) {
  foo = bar
}


上面的代码,可能会产生四种运行结果:

obj.foo = bar
obj.foo = obj.bar
foo = bar
foo = obj.bar


以上四种结果都可能发生,取决于不同的变量是否有定义。因此,建议不要使用 with 语句。


五、相等与严格相等


规则 7:尽可能不要使用相等运算符(==),而使用全等运算符(===)。


Always use 3 equals unless you have a good reason to use 2.


主要原因是,使用相等运算符对两个不同类型的操作数进行比较时,JavaScript 内部会“偷偷”进行了类型转换。

0 == '' // true
2 == true // false
0 == '0' // true
false == '0' // true
' \t\r\n ' == 0 // true


六、语句的合并


有些开发者追求“过分”简洁,喜欢合并不同目的的语句。

例如,原语句是:

a = b
if (a) { ... }


他喜欢写成下面这样:

if (a = b) { ... }


虽然语句少了一行,但是可读性大打折扣,而且会造成误读,让别人误以为这行代码的意思是:

if (a === b) { ... }


另外一种情况是,有些开发者喜欢在同一行中赋值多个变量:

// 非严格模式
var a = b = 0


它可能认为,上面的代码相当于:

var a = 0, b = 0


但实际上不是,它的真正效果是下面这样:

// 这里指非严格模式(严格模式下会报错,不允许这种默认全局变量的写法)
b = 0
var a = b


因此,不建议将不同目的的语句合并成一行。


七、变量声明


在 JavaScript 中,有一个非常著名的变量提升Hoisting)概念,相信都知道。

不管我们实际项目中怎样,作为一个合格或不合格的 Jser,都应该去了解清楚提升是什么鬼,好吧。


就一句话:


先声明,后调用。


还有都 2021 年了,尽可能别用 var 了,用 letconst 吧。至于兼容就放心交给 Babel 吧!

// bad
if (!obj) {
  var obj = {}
}
// good
var obj
if (!obj) {
   obj = {}
}


为了避免可能出现的问题,不如把变量声明都放在代码块的头部。

// bad
for (var i ...) { ... }
// good
var i
for (i ...) { ... }


因此,


规则 9:所有变量声明都放在函数的头部。

规则 10:所有函数都在使用之前定义。


八、全局变量


Javascript 最大的语法缺点,可能就是全局变量对于任何一个代码块,都是可读可写。这对代码的模块化和重复使用,非常不利。


规则 11:避免使用全局变量;如果不得不使用,用大写字母表示变量名,比如 UPPER_CASE


九、new 关键字


JavaScript 使用 new 关键字,从构造函数生成一个新对象。

var obj = new myObject()


这种做法的问题是,一段你忘了加上 new 关键字,myObject() 内部的 this 关键字就会指向全局对象(严格模式下 thisundefined),导致所有绑定在 this 上的变量,都变成了全局变量。


规则 12:不要使用 new 关键字,改用 Object.create() 来创建新对象。

规则 13:构造函数的函数名,采用首字母大写(InitialCap)的书写方式;其他的函数名,一律首字母小写。


当然,构造函数名称首字母大写,只是约定俗成的一种书写方式而已,不影响实际运行。像 ESLint 就有一个 new-cap 规则去检查这种写法的。


十、自增和自减运算符


自增 ++ 和自减 -- 运算符,放在操作数的前面或后面,返回值是不一样的,很容易发生错误。


说实话,我到现在还经常记不太清这俩玩意。有时候遇到,还特地去查阅一番以确认是否预期运行。


所以我也是使用 += 1-= 1 去替代它的。ESLint 也有一个规则 no-plusplus 去限制这种写法。

//  bad
++i
// good
i += 1

听说某 JS 库源码出现了以下代码片段:

++i;
++i;
// 怎么看,更合理的写法应该是:
i += 2


因此,

规则 14:不要使用自增(++)和自减(--),使用 +=-= 代替。


其实我的习惯是,仅允许 forfinal-expression 使用自增或自减,其他的不允许,所以 ESLint 规则可以这样写。

/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
for (let i = 0; i < 10; i++) {
  // 上面 final-expression 允许自增、自减,但循环体本身不允许
}


详见:no-plusplus


总结

综上所述,总结成一句话:爱咋咋地


都 2021 年了,项目都继承 ESLint、Prettier 了吧,那上面的很多毛病,它们基本上都给你处理了。但我们应该要了解下背后的原因,对吧。


对于有强迫症的我,还要继承 CSScomb,去对 CSS 进行排序。


参考



作者:越前君

链接:https://www.jianshu.com/p/72ca1a46da0d

来源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

目录
相关文章
|
2月前
|
存储 JavaScript 前端开发
JavaScript编程实现tab选项卡切换的效果+1
JavaScript编程实现tab选项卡切换的效果+1
|
3月前
|
JavaScript 前端开发 编译器
解锁JavaScript模块化编程新纪元:从CommonJS的基石到ES Modules的飞跃,探索代码组织的艺术与科学
【8月更文挑战第27天】随着Web应用复杂度的提升,JavaScript模块化编程变得至关重要,它能有效降低代码耦合度并提高项目可维护性及扩展性。从CommonJS到ES Modules,模块化标准经历了显著的发展。CommonJS最初专为服务器端设计,通过`require()`同步加载模块。而ES Modules作为官方标准,支持异步加载,更适合浏览器环境,并且能够进行静态分析以优化性能。这两种标准各有特色,但ES Modules凭借其更广泛的跨平台兼容性和现代语法逐渐成为主流。这一演进不仅标志着JavaScript模块化的成熟,也反映了整个JavaScript生态系统的不断完善。
53 3
|
22天前
|
自然语言处理 JavaScript 前端开发
JavaScript闭包:解锁编程潜能,释放你的创造力
【10月更文挑战第25天】本文深入探讨了JavaScript中的闭包,包括其基本概念、创建方法和实践应用。闭包允许函数访问其定义时的作用域链,常用于数据封装、函数柯里化和模块化编程。文章还提供了闭包的最佳实践,帮助读者更好地理解和使用这一强大特性。
14 2
|
2月前
|
JavaScript 前端开发
JavaScript编程实现tab选项卡切换的效果
JavaScript编程实现tab选项卡切换的效果
|
2月前
|
JavaScript 前端开发
用JavaScript编程控制网页上checkbox选择状态:全选、全部取消、反选
用JavaScript编程控制网页上checkbox选择状态:全选、全部取消、反选
|
2月前
|
JavaScript 前端开发 安全
JavaScript编程实现字符和字符串翻转
JavaScript编程实现字符和字符串翻转
|
2月前
|
JavaScript 前端开发
用JavaScript编程定义二维数组并初始化,然后输出元素值
用JavaScript编程定义二维数组并初始化,然后输出元素值
|
3月前
|
JavaScript 前端开发 安全
揭秘TypeScript的魔力:它是如何华丽变身为JavaScript的超能英雄,让您的代码飞入全新的编程维度!
【8月更文挑战第22天】在Web开发领域,JavaScript是最主流的编程语言之一。但随着应用规模的增长,其类型安全和模块化的不足逐渐显现。为解决这些问题,微软推出了TypeScript,这是JavaScript的一个超集,通过添加静态类型检查来提升开发效率。TypeScript兼容所有JavaScript代码,并引入类型注解功能。
38 2
|
3月前
|
JavaScript 前端开发 Oracle
|
3月前
|
JavaScript 前端开发 开发者
震撼揭秘!JS模块化进化史:从混沌到秩序,一场代码世界的华丽蜕变,你怎能错过这场编程盛宴?
【8月更文挑战第23天】在 Web 前端开发领域,JavaScript 模块化已成为处理日益复杂的 Web 应用程序的关键技术。通过将代码分解成独立且可重用的模块,开发者能够更有效地组织和管理代码,避免命名冲突和依赖混乱。从最早的全局函数模式到 IIFE,再到 CommonJS 和 AMD,最终进化到了 ES6 的原生模块支持以及 UMD 的跨环境兼容性。本文通过具体示例介绍了这些模块化规范的发展历程及其在实际开发中的应用。
52 0
下一篇
无影云桌面