contributor_docs/zh-Hans/documentation_style_guide.md
你好!欢迎来到 p5.js 文档编写指南。本文档是以下资源的混合:
我们的社区庞大而多样。许多人使用 p5.js 学习编程,其中很大一部分是 K-12 年级的学生。阅读本指南后,你将了解:
我们使用 YUIDoc 来生成 p5.js API 文档。要生成文档,请切换到 p5.js 根目录,运行 npm install,然后执行:
$ npm run grunt yui:dev
输出将出现在 docs/reference 目录中。更多信息请参考内联文档指南。
请使用美式英语(color、center、modularize 等)。参见美式和英式英语拼写差异列表。
请使用牛津逗号("red, white, and blue",而不是"red, white and blue")。
写简单、陈述性的句子。简洁是加分项:直奔主题。
使用现在时态:"Returns an object that...",而不是"Returned an object that..."或"Will return an object that..."。
注释以大写字母开头。遵循常规标点规则:
// Draws a fractal from a Julia set.
function drawFractal(c, radius, maxIter) {
// ...
}
明确和隐式地传达当前的做事方式。使用本指南中推荐的惯用语。如果需要,重新排序部分以强调首选方法。文档应该是最佳实践的典范,并且对初学者友好。
文档必须简洁但全面。探索并记录边缘情况。每种参数组合会发生什么?初学者的代码中最可能出现哪些错误?
正确拼写名称:p5.js、CSS、HTML、JavaScript、WebGL。如有疑问,请参考官方文档等权威来源。
编写文档时不要对任何类型的人有偏见。在记录特别要求高/敏感的主题时,花时间自己学习一下。确保你的写作不会无意中伤害或冒犯他人。
在编写无偏见的文档时:
优先使用避免"you"和"your"的措辞。例如,不要:
If you need to declare a variable, it is recommended that you use `let`.
而是使用这种风格:
Always use `let` to declare variables.
代词
| 推荐 | 不推荐 |
|---|---|
| they | he or she |
| them | him or her |
| their | his or her |
| theirs | his or hers |
| themselves | himself or herself |
可访问性术语
以下术语改编自 WordPress 文档指南中的编写包容性文档。有关以人为本语言的更多背景,请参见 CDC 的与残障人士沟通指南。
| 推荐 | 不推荐 |
|---|---|
| 残障人士 | 残疾人、残障、能力不同、有挑战、不正常 |
| 非残障人士 | 正常人、健康人、健全人 |
| 有[残障] | 受害者、遭受、受...影响、被...折磨 |
| 无法说话,使用合成语音 | 哑巴、失语 |
| 聋人,听力低下 | 听力障碍 |
| 盲人,视力低下 | 视力障碍,视觉挑战 |
| 认知或发育障碍 | 智力挑战,学习缓慢 |
| 行动不便的人,身体残障的人 | 瘸子,残障 |
选择有意义的代码示例,涵盖基础知识以及容易出错的地方。只有在解释功能工作原理时才使用高级语法。当一个圆就能传达想法时,不要画五个圆来解释。代码示例本身应遵循以下指南。
// 进行单行注释。将单行注释放在注释主题上方的新行上。除非是块的第一行,否则在注释前放置一个空行。// 不好。
let magicWord = 'Please'; // 记住这个。
// 好。
// 记住这个。
let magicWord = 'Please';
// 不好。
if (keyIsPressed === true) {
thing1();
// 这是一个重要的注释。
thing2();
}
// 好。
if (keyIsPressed === true) {
thing1();
// 这是一个重要的注释。
thing2();
}
// 不好。
//记住这个。
let magicWord = 'Please';
// 好。
// 记住这个。
let magicWord = 'Please';
// 进行多行注释。
// 不好。
/**
* 我将使用 // 进行多行注释。
* 我将使用 // 进行多行注释。
* 我将使用 // 进行多行注释。
* 我将使用 // 进行多行注释。
* 我将使用 // 进行多行注释。
*/
// 不好。
/*
我将使用 // 进行多行注释。
我将使用 // 进行多行注释。
我将使用 // 进行多行注释。
我将使用 // 进行多行注释。
我将使用 // 进行多行注释。
*/
// 好。
// 我将使用 // 进行多行注释。
// 我将使用 // 进行多行注释。
// 我将使用 // 进行多行注释。
// 我将使用 // 进行多行注释。
// 我将使用 // 进行多行注释。
// 不好。
function setup() {
∙∙∙∙createCanvas(400, 400);
}
// 不好。
function setup() {
∙createCanvas(400, 400);
}
// 好。
function setup() {
∙∙createCanvas(400, 400);
}
// 不好。
function setup(){
createCanvas(400, 400);
}
// 好。
function setup() {
createCanvas(400, 400);
}
if 和 for)中的左括号前放置 1 个空格。在参数列表和函数名之间不要放置空格。// 不好。
if(keyIsPressed === true) {
doStuff ();
}
// 好。
if (keyIsPressed === true) {
doStuff();
}
// 不好。
function setup () {
createCanvas (400, 400);
}
// 好。
function setup() {
createCanvas(400, 400);
}
// 不好。
let y=x+5;
// 好。
let y = x + 5;
为什么?JavaScript 的自动分号插入可能导致细微的错误。
// 不好。
let x = 0
// 好。
let x = 0;
// 不好。
function f(x, y) {
// ...
}
// 好。
function vectorField(x, y) {
// ...
}
// 不好。
let OBJEcttsssss = {};
// 不好。
let this_is_my_object = {};
// 好。
let thisIsMyObject = {};
// 不好。
class player {
constructor(name) {
this.name = name;
}
}
// 好。
class Player {
constructor(name) {
this.name = name;
}
}
为什么?JavaScript 没有私有属性或方法。
// 不好。
class Spy {
constructor(secret) {
this._secret = secret;
}
}
// 好。
class Spy {
constructor(secret) {
this.secret = secret;
}
}
var 声明变量。为什么?使用
var声明的变量具有令人困惑的作用域规则。这些会导致细微的错误。
// 不好,因为它看起来合理。
circle(x, y, 50);
var x = 200;
var y = 200;
// 好,因为它会抛出 ReferenceError。
circle(x, y, 50);
let x = 200;
let y = 200;
let 声明变量。避免使用 const。为什么?使用
let声明的变量比使用var声明的变量更容易理解。变量在草图中经常被重新赋值,所以默认使用let很有帮助。
// 不好。
flower = '🌸';
var flower = '🌸';
const flower = '🌸';
// 好。
let flower = '🌸';
let 声明。为什么?这样更容易阅读和添加新的变量声明。
// 不好。
let positions = getPositions(),
startSearch = true,
dragonball = 'z';
// 好。
let positions = getPositions();
let startSearch = true;
let dragonball = 'z';
为什么?
let是块作用域而不是函数作用域。
// 不好 - 不必要的搜索。
function getCharacter(name = 'default') {
let character = characters.find((c) => c.name === name);
if (name === 'default') {
return false;
}
if (character) {
return character;
}
return false;
}
// 好。
function getCharacter(name = 'default') {
if (name === 'default') {
return false;
}
let character = characters.find((c) => c.name === name);
if (character) {
return character;
}
return false;
}
++,--)。为什么?一元递增和递减语句受自动分号插入的影响。这可能导致递增或递减值的静默错误。使用像
num += 1这样的语句更新变量也比num++更具表现力。
// 不好。
let num = 1;
num++;
--num;
// 好。
let num = 1;
num += 1;
num -= 1;
'' 表示字符串。// 不好。
let name = "Hilma af Klint";
// 不好 - 模板字面量应包含插值或换行。
let name = `Hilma af Klint`;
// 好。
let name = 'Hilma af Klint';
为什么?断开的字符串难以阅读,使代码不易搜索。
// 不好。
let essay = 'You see us as you want to see us: \
in the simplest terms, in the most convenient definitions.';
// 不好。
let essay = 'You see us as you want to see us: ' +
'in the simplest terms, in the most convenient definitions.';
// 好。
let essay = 'You see us as you want to see us: in the simplest terms, in the most convenient definitions.';
为什么?模板字符串具有简洁的语法。它们还提供适当的换行和字符串插值功能。
let name = 'Dave';
// 不好。
text(name + ', this conversation can serve no purpose anymore. Goodbye.' + name, 0, 0);
// 好。
text(`${name}, this conversation can serve no purpose anymore. Goodbye.`, 0, 0);
为什么?反斜杠会损害可读性。
// 不好。
let bad = '\'this\' \i\s \"quoted\"';
// 好。
let good = 'Air quotes make you look "cool".';
使用 === 和 !== 而不是 == 和 !=。
不要使用布尔值的快捷方式。
为什么?对初学者来说更容易理解。
// 不好。
if (mouseIsPressed) {
// ...
}
// 好。
if (mouseIsPressed === true) {
// ...
}
// 不好。
if (name) {
// ...
}
// 好。
if (name !== '') {
// ...
}
// 不好。
if (collection.length) {
// ...
}
// 好。
if (collection.length > 0) {
// ...
}
除非必要,否则不要使用 switch 语句。
混合运算符时使用括号。唯一的例外是算术运算符 +、- 和 **。
为什么?这样更容易阅读并避免细微的错误。
// 不好。
let huh = a && b < 0 || c > 0 || d + 1 === 0;
// 好。
let huh = (a && b < 0) || c > 0 || (d + 1 === 0);
// 不好。
if (a || b && c) {
return d;
}
// 好。
if (a || (b && c)) {
return d;
}
// 不好。
let what = a + b / c * d;
// 好。
let what = a + (b / c) * d;
// 不好。
if (mouseIsPressed === true)
circle(mouseX, mouseY, 50);
// 更好。
if (mouseIsPressed === true) circle(mouseX, mouseY, 50);
// 最好。
if (mouseIsPressed === true) {
circle(mouseX, mouseY, 50);
}
else 放在前一个 if 块的右大括号的同一行。// 不好。
if (mouseIsPressed === true) {
thing1();
thing2();
}
else {
thing3();
}
// 好。
if (mouseIsPressed === true) {
thing1();
thing2();
} else {
thing3();
}
return 语句的 if 块后不要使用 else 块。// 不好。
function mouseIsOnLeft() {
if (mouseX < width * 0.5) {
return true;
} else {
return false;
}
}
// 好。
function mouseIsOnLeft() {
if (mouseX < width * 0.5) {
return true;
}
return false;
}
为什么?这样更容易阅读。
// 不好。
if ((number === 123 || letters === 'abc') && mouseIsPressed === true && keyIsPressed === true) {
doStuff();
}
// 好。
if (
(number === 123 || letters === 'abc')
&& mouseIsPressed === true
&& keyIsPressed === true
) {
doStuff();
}
// 不好。
refrigeratorIsRunning && goCatchIt();
// 好。
if (refrigeratorIsRunning === true) {
goCatchIt();
}
while 或 do-while 循环。使用 for 循环来迭代固定次数。let numPetals = 7;
// 不好。
let i = 0;
while (i < numPetals) {
ellipse(0, 0, 20, 80);
rotate(PI / numPetals);
i += 1;
}
// 好。
for (let i = 0; i < numPetals; i += 1) {
ellipse(0, 0, 20, 80);
rotate(PI / numPetals);
}
for 循环来迭代数组。为什么?纯函数比副作用更容易推理。
使用
forEach()/map()/every()/filter()/find()/findIndex()/reduce()/some()/...来迭代数组。使用Object.keys()/Object.values()/Object.entries()来生成用于迭代对象的数组。
let diameters = [50, 40, 30, 20, 10];
// 不好。
for (let i = 0; i < diameters.length; i += 1) {
circle(0, 0, diameters[i]);
}
// 不好。
for (let d of diameters) {
circle(0, 0, d);
}
// 好。
diameters.forEach((d) => circle(0, 0, d));
// 不好。
let ball = new Object();
// 好。
let ball = {};
为什么?这样更容易阅读并提高语法高亮。JavaScript 引擎也更容易优化性能。
// 不好。
let secretObject = {
'x': 100,
'y': 200,
'top-secret': 'classified',
};
// 好。
let secretObject = {
x: 3,
y: 4,
'top-secret': 'classified',
};
let turtle = {
name: 'Leonardo',
color: 'dodgerblue',
weapon: '🗡️',
food: '🍕',
};
// 不好。
let turtleName = turtle['name'];
// 好。
let turtleName = turtle.name;
[] 访问带有变量的属性。let turtle = {
name: 'Leonardo',
color: 'dodgerblue',
weapon: '🗡️',
food: '🍕',
};
function getProp(prop) {
return turtle[prop];
}
let turtleName = getProp('name');
// 不好。
let mathematician = {
firstName: 'Ada'
, lastName: 'Lovelace'
};
// 好。
let mathematician = {
firstName: 'Ada',
lastName: 'Lovelace',
};
// 不好。
let artist = {
firstName: 'Lauren',
lastName: 'McCarthy'
};
// 好。
let artist = {
firstName: 'Lauren',
lastName: 'McCarthy',
};
// 不好。
let images = new Array();
// 好。
let images = [];
let lyrics = [];
// 不好。
lyrics[lyrics.length] = 'Little rough around the edges, but I keep it smooth';
// 好。
lyrics.push('Little rough around the edges, but I keep it smooth');
slice() 方法复制数组。// 不好。
let numbersCopy = [];
for (let i = 0; i < numbers.length; i += 1) {
numbersCopy[i] = numbers[i];
}
// 好。
let numbersCopy = numbers.slice();
// 不好。
let matrix = [[1, 0, 0],
[0, 1, 0],
[0, 0, 1]];
// 好。
let matrix = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
];
// 也好。
let matrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
为什么?函数声明有一些陷阱,但对初学者来说更容易理解。
// 不好。
let foo = function () {
// ...
};
// 不好。
let foo = () => {
// ...
};
// 好。
function foo() {
// ...
}
// 不好。
function createBall(diameter) {
diameter = diameter || 50;
// ...
}
// 好。
function createBall(diameter = 50) {
// ...
}
// 不好。
function drawSpiral(angle = 90, length) {
// ...
}
// 好。
function drawSpiral(length, angle = 90) {
// ...
}
为什么?语法更简洁。它还创建了一个在
this上下文中执行的函数版本,这通常很有帮助。
为什么不?如果匿名函数很复杂,将其重写为声明的函数。
// 不好。
function setup() {
loadImage('assets/moonwalk.jpg', function (img) {
image(img, 0, 0);
});
}
// 好。
function setup() {
loadImage('assets/moonwalk.jpg', (img) => {
image(img, 0, 0);
});
}
// 不好。
function preload() {
loadImage('assets/moonwalk.jpg', (img) => {
// 复杂的预处理...
});
}
// 好。
function preload() {
loadImage('assets/moonwalk.jpg', processImage);
}
function processImage(img) {
// 复杂的预处理...
}
return 语句。为什么?这样更容易阅读。
// 不好。
[1, 2, 3].map((number) => {
let squared = number ** 2;
`${number} squared is ${squared}.`;
});
// 不好。
[1, 2, 3].map((number) => {
let squared = number ** 2;
return `${number} squared is ${squared}.`;
});
// 好。
[1, 2, 3].map((number) => `${number} squared is ${number ** 2}.`);
为什么?这样做可以减少更改参数时的错误。
// 不好。
[1, 2, 3].map(number => number * number);
// 好。
[1, 2, 3].map((number) => number * number);
为什么?适应可能不熟悉函数链式调用概念的用户。
// 不好。
fill(0)
.strokeWeight(6)
.textSize(20);
// 不好。
fill(0).strokeWeight(6).textSize(20);
// 好。
fill(0);
strokeWeight(6);
textSize(20);
class。避免直接操作 prototype。唯一的例外是解释如何创建库。为什么?
class语法更简洁,更容易理解。
// 不好。
function Mover(x, y, radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
Mover.prototype.update = function () {
this.x += 1;
this.y += 1;
};
Mover.prototype.render = function () {
circle(this.x, this.y, 2 * this.radius);
};
// 好。
class Mover {
constructor(x, y, radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
update() {
this.x += 1;
this.y += 1;
}
render() {
circle(this.x, this.y, 2 * this.radius);
}
}
extends 进行继承。class RandomMover extends Mover {
update() {
this.x += random(-1, 1);
this.y += random(-1, 1);
}
}
toString() 方法不会引起副作用。// 不好。
class Mover {
// ...
toString() {
this.x += 1;
return `Mover at (${this.x}, ${this.y})`;
}
}
// 好。
class Mover {
// ...
toString() {
return `Mover at (${this.x}, ${this.y})`;
}
}
为什么?如果未指定,类有默认构造函数。
// 不好。
class Dot {
constructor() {}
render() {
circle(mouseX, mouseY, 50);
}
}
// 好。
class Dot {
render() {
circle(mouseX, mouseY, 50);
}
}
// 不好。
class DragonBall extends Ball {
constructor(x, y, d) {
super(x, y, d);
}
}
// 好。
class DragonBall extends Ball {
constructor(x, y, d, numStars) {
super(x, y, d);
this.numStars = numStars;
}
}
为什么?重复的类成员声明优先选择最后一个。有重复通常意味着有错误。
// 不好。
class Mover {
// ...
update() {
this.x += this.xspeed;
this.y += this.yspeed;
}
update() {
this.x = 0;
this.y = 0;
}
}
// 好。
class Mover {
// ...
update() {
this.x += this.xspeed;
this.y += this.yspeed;
}
reset() {
this.x = 0;
this.y = 0;
}
}
为什么?它模拟了良好的项目组织。这也是在 p5.js 网站上加载资源所必需的。将资源放在以下文件夹中以将其包含在我们的在线文档中:
let img;
// 不好。
function preload() {
img = loadImage('moonwalk.jpg');
}
// 好。
function preload() {
img = loadImage('assets/moonwalk.jpg');
}