浩明老哥说编程风格指南非常重要,那就咱也整一个!
在官方的风格指南里面,所有的做法都附上了原因,不论是好的还是坏的。编程风格,更像是一种程序员之间约定俗成的规定,统一的约定可以极大程度的减小阅读他人代码时候所带来的困难。
1.单一功能原则
在面向对象编程领域中,单一功能原则(Single responsibility principle)规定每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来。所有它的(这个类的)服务都应该严密的和该功能平行(功能平行,意味着没有依赖)。
单一规则
- 每个文件只定义一样东西(服务或组件)
- 文件大小限制在400行代码之内
原因?
-
单组件文件容易阅读和维护,而且可以防止在版本控制之中和团队冲突。
-
单组件文件可以防止一些隐蔽的程序缺陷,多个组件放在一个文件之中时可能会造成共享变量,创建意外的闭包或者与依赖之间意外耦合。
-
单独的组件通常是文件默认的导出,可以用路由器实现按需加载。
可以让代码更加复用,更易阅读,减少出错的可能性
小函数
坚持定义简单函数,考虑限制在75行之内
原因?
简单函数更易于测试,特别是只为一件事或者一个目的服务的时候。
简单函数促进代码重用
简单函数易于阅读,且易于维护。
可避免易在大函数之中产生的隐蔽错误,和上面单一规则的第2点一样。
2.命名
命名约定对于可维护性和可读性很重要。
总体命名规则
坚持遵循同一个规则来描述符号和特性,推荐模式是 feature.type.ts
原因:
命名约定提供了一致的方式来查找内容。项目的一致性至关重要
目录名和文件名应该清楚的传递他们的意图,例如,app/heroes/hero-list.component.ts
包含了一个用来管理英雄列表的组件。
使用点和横杠来分割文件名
用横杠来连接单词,用点来分隔描述性名字和类型:different-words.service.ts
坚持使用惯用的后缀来描述类型,包括 *.service
、*.component
、*.pipe
、.module
、.directive
风格2-5
把引导程序和平台相关的逻辑放到名 main.ts
的文件里
在引导逻辑之中放入错误处理代码
风格5-2:组件选择器
坚持使用中线命名法(带 - 的名字)来命名 元素的 selectors
原因是让元素名和自定义元素保持一致
//wrong
@Component({
selector: 'tohHeroButton',
templateUrl: './hero-button.component.html'
})
//right
@Component({
selector: 'toh-hero-button',
templateUrl: './hero-button.component.html'
})
3.为指令添加自定义前缀
风格02-08
坚持为指令的选择器添加自定义前缀。(例如前缀 toh
来自 Tour of Heroes)
坚持用小驼峰形式拼写元素选择器,除非其用于匹配原生HTML属性
原因?
防止名字冲突,同时让指令更容易被识别
4.管道名
风格02-09
坚持为所有管道使用一致的命名约定,用其特性来命名。
原因?
一致的方式快速识别和使用管道。
5.Angular NgModule 命名
坚持为符号名添加 Module
后缀
坚持为文件名添加 .module.ts
扩展名。
坚持用特性名和所在目录命名模块。
为何?提供一致的方式来快速标识和引用模块。
为何?大驼峰命名法是一种命名约定,用来标识可用构造函数实例化的对象。
为何?很容易就能看出这个模块是同名特性的根模块。
坚持为 RoutingModule 类名添加 RoutingModule
后缀。
坚持为 RoutingModule 的文件名添加 -routing.module.ts
后缀。
为何?RoutingModule
是一种专门用来配置 Angular 路由器的模块。 “类名和文件名保持一致”的约定使这些模块易于发现和验证。
6.编程约定
类
风格03-01
使用大驼峰命名法来命名类。
原因是:类可以被实例化和构造实例,根据约定,用大驼峰表示可以构造的东西。
常量
风格03-02
坚持用 const 声明常量,除非其值在应用的生命周期之内可能变化。
注意,const 所声明的常量只是:对于对象,不可以改变指针的位置,但是里面的值随便换
接口
风格03-03
坚持使用大写驼峰命名法来命名接口。
考虑不要在接口名字前面加 I
前缀。
考虑在服务和可声明对象(组件、指令和管道)中用类代替接口。
考虑用接口作为数据模型。
为何?TypeScript 指导原则不建议使用 “I” 前缀。
为何?单独一个类的代码量小于类+接口。
为何?类可以作为接口使用(只是用 implements
代替 extends
而已)。
为何?在 Angular 依赖注入系统中,接口类(译注:指写成类的形式,但是只当做接口使用)可以作为服务提供商的查找令牌。
属性和方法
样式03-04
避免为私有属性和方法添加下划线
为何? JavaScript 不支持真正的私有属性和方法。
为何? TypeScript 工具让识别私有或公有属性和方法变得很简单。
导入语句之中的空行
风格03-06
坚持在第三方导入和应用导入之间留一个空行。
考虑按模块名字的字母顺排列导入行。
考虑在解构表达式中按字母顺序排列导入的东西。
为何?空行可以让阅读和定位本地导入更加容易。
为何?按字母顺序排列可以让阅读和定位本地导入更加容易。
//avoid
import { ExceptionService, SpinnerService, ToastService } from '../../core';
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Hero } from './hero.model';
//try to
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ExceptionService, SpinnerService, ToastService } from '../../core';
import { Hero } from './hero.model';
定位
风格04-03
坚持文件名要看到名字立刻知道其包含什么,代表什么。
扁平
风格04-04
扁平,更多的子目录,而非深的要死的文件树。
按特性组织的目录结构
以这种方式,开发人员可以快速定位代码,一眼就知道每个文件代表什么。目录尽可能保持扁平。
7.Components
把组件当成元素
考虑给组件一个元素选择器,而不是属性或者类选择器
//avoid
<div tohHeroButton></div>
//use
<toh-hero-button></toh-hero-button>
把模板和样式提取到其自己的文件
坚持当超过三行的时候,把模板和样式提取到一个单独的文件。
指定相对于模块的 URL,给其加上 ./ 前缀
原因?
内联的模板会遮盖组件的意图和实现方式,削弱可读性和维护性。
编写内联模板时候大多数的编辑器都无法使用语法提示和代码片段功能。
内联输入和输出属性装饰器
坚持 使用 @Input()
和 @Output()
,而非 @Directive
和 @Component
装饰器的 inputs
和 outputs
属性:
坚持把 @Input()
或者 @Output()
放到所装饰的属性的同一行。
原因?
易于在类里面识别哪些属性是输入属性或输出属性。
需要修改或者重命名输入/输出关联的属性或者事件名称,可以在一个地方完成修改。