JavaScript 编码标准

JavaScript 已成为开发基于 WordPress 的应用程序(主题和插件)以及 WordPress 核心的关键组件。JavaScript 代码的格式和样式需要标准,以保持与 WordPress 标准为核心 PHP、HTML 和 CSS 代码提供的相同的代码一致性。

任何代码库中的所有代码都应该看起来像一个人输入的,不管有多少人贡献。–编写一致、惯用的 JavaScript 的原则

WordPress JavaScript 编码标准改编自jQuery JavaScript 风格指南。我们的标准在以下方面与 jQuery 指南不同:

  • WordPress 使用单引号来声明字符串。
  • Case 语句在 switch 块中缩进。
  • 函数内容一致缩进,包括完整文件闭包包装器。
  • 为了与 WordPress PHP 编码标准保持一致,一些空白规则有所不同。
  • 鼓励使用 jQuery 的 100 个字符的硬行限制,但并不严格执行。

下面的许多示例都直接改编自 jQuery 样式指南;这些差异都已集成到本页的示例中。以下任何标准和示例都应被视为 WordPress 代码的最佳实践,除非明确指出为反模式。

代码重构

“不应该仅仅因为我们可以就进行代码重构。” – 首席开发人员 Andrew Nacin

JavaScript 的 WordPress 代码结构的许多部分在风格上是不一致的。WordPress 正在努力逐步改进这一点,因此代码将干净利落,一目了然。

虽然编码标准很重要,但仅仅为了符合标准而重构旧的 .js 文件并不是一个紧迫的问题。强烈建议不要为旧文件打“纯空白”补丁。

所有新的或更新的 JavaScript 代码都将被审查以确保其符合标准并通过 JSHint。

间距

在整个代码中大量使用空格。“如有疑问,请将其隔开。”

这些规则鼓励自由间距以提高开发人员的可读性。缩小过程会创建一个文件,该文件针对浏览器进行了优化以供读取和处理。

  • 带制表符的缩进。
  • 行尾或空行上没有空格。
  • 行通常不应超过 80 个字符,并且不应超过 100 个(将制表符算作 4 个空格)。这是一个“软”规则,但长行通常表示代码不可读或混乱。
  • if// else/ for/块应该总是使用大括号,并且总是whiletry多行上。
  • 一元特殊字符运算符(例如++, --)的操作数旁边不能有空格。
  • Any ,and;前面不能有空格。
  • 任何;用作语句终止符的都必须在行尾。
  • 对象定义中属性名称之后的任何内容都:不能有前面的空格。
  • ?三元条件中的 and两边:必须有空格。
  • 空结构中没有填充空间(例如{},,,,)。[]``fn()
  • 每个文件的末尾应该有一个新行。
  • 任何!否定运算符都应有以下空格。*
  • 所有函数体都缩进一个制表符,即使整个文件都包含在一个闭包中。*
  • 空格可以对齐文档块内或一行内的代码,但只能在行首使用制表符。*

* : WordPress JavaScript 标准比 jQuery 风格指南更喜欢更广泛的空白规则。这些偏差是为了 WordPress 代码库中 PHP 和 JavaScript 文件之间的一致性。

空格很容易堆积在一行的末尾——避免这种情况,因为尾随空格在 JSHint 中会被视为错误。捕捉空格堆积的一种方法是在文本编辑器中启用可见的空格字符。

对象声明

如果对象声明很短,则可以在一行中进行(记住行长度准则)。当对象声明太长无法放在一行时,每行必须有一个属性。如果属性名称是保留字或包含特殊字符,则只需要引用它们:

如果对象和数组很短,则可以在一行中声明它们(记住行长度准则)。当一个对象或数组太长而无法放在一行中时,每个成员都必须放在自己的行中,并且每行以逗号结尾。

// Preferred
var obj = {
    ready: 9,
    when: 4,
    'you are': 15,
};
var arr = [
    9,
    4,
    15,
];

// Acceptable for small objects and arrays
var obj = { ready: 9, when: 4, 'you are': 15 };
var arr = [ 9, 4, 15 ];

// Bad
var obj = { ready: 9,
    when: 4, 'you are': 15 };
var arr = [ 9,
    4, 15 ];

数组和函数调用

始终在元素和参数周围包含额外的空格:

array = [ a, b ];

foo( arg );

foo( 'string', object );

foo( options, object[ property ] );

foo( node, 'property', 2 );

prop = object[ 'default' ];

firstArrayElement = arr[ 0 ];

良好间距的例子

var i;

if ( condition ) {
    doSomething( 'with a string' );
} else if ( otherCondition ) {
    otherThing( {
        key: value,
        otherKey: otherValue
    } );
} else {
    somethingElse( true );
}

// Unlike jQuery, WordPress prefers a space after the ! negation operator.
// This is also done to conform to our PHP standards.
while ( ! condition ) {
    iterating++;
}

for ( i = 0; i < 100; i++ ) {
    object[ array[ i ] ] = someFn( i );
    $( '.container' ).val( array[ i ] );
}

try {
    // Expressions
} catch ( e ) {
    // Expressions
}

分号

使用它们。永远不要依赖自动分号插入 (ASI)。

缩进和换行

缩进和换行符增加了复杂语句的可读性。

制表符应该用于缩进。即使整个文件包含在一个闭包中(即一个立即调用的函数),该函数的内容也应该缩进一个制表符:

( function ( $ ) {
    // Expressions indented

    function doSomething() {
        // Expressions indented
    }
} )( jQuery );

块和大括号

if, else, for, while, 和try块应该总是使用大括号,并且总是在多行上。左大括号应与函数定义、条件语句或循环位于同一行。右大括号应该紧跟在块的最后一条语句之后。

var a, b, c;

if ( myFunction() ) {
    // Expressions
} else if ( ( a && b ) || c ) {
    // Expressions
} else {
    // Expressions
}

多行语句

当语句太长无法放在一行中时,换行符必须出现在运算符之后。

// Bad
var html = '<p>The sum of ' + a + ' and ' + b + ' plus ' + c
    + ' is ' + ( a + b + c ) + '</p>';

// Good
var html = '<p>The sum of ' + a + ' and ' + b + ' plus ' + c +
    ' is ' + ( a + b + c ) + '</p>';

如果可以提高可读性,就应该将行分成逻辑组,例如将三元运算符的每个表达式拆分到自己的行中,即使两者都适合一行。

// Acceptable
var baz = ( true === conditionalStatement() ) ? 'thing 1' : 'thing 2';

// Better
var baz = firstCondition( foo ) && secondCondition( bar ) ?
    qux( foo, bar ) :
    foo;

当条件太长而无法放在一行中时,布尔表达式中逻辑运算符的每个操作数都必须出现在自己的行中,从左括号和右括号缩进一层。

if (
    firstCondition() &&
    secondCondition() &&
    thirdCondition()
) {
    doStuff();
}

链式方法调用

当一连串的方法调用太长而不能放在一行中时,每行必须有一个调用,第一个调用与调用方法的对象分开一行。如果该方法更改了上下文,则必须使用额外的缩进级别。

elements
    .addClass( 'foo' )
    .children()
        .html( 'hello' )
    .end()
    .appendTo( 'body' );

变量的声明

const用and声明变量let

对于使用 ES2015 或更新版本编写的代码,constlet始终代替var. 声明应该使用const,除非它的值将被重新分配,在这种情况下let是合适的。

与 不同var,不必在函数顶部声明所有变量。相反,它们将在首次使用时声明。

声明变量var

每个函数都应以单个逗号分隔的var语句开头,该语句声明任何必要的局部变量。如果函数未使用 声明变量var,则该变量可能会泄漏到外部作用域(通常是全局作用域,这是最坏的情况),并且可能会无意中引用和修改该数据。

语句中的赋值var应该在单独的行中列出,而声明可以分组在一行中。任何额外的行都应该用额外的制表符缩进。占用多于几行的对象和函数应该在var语句之外分配,以避免过度缩进。

// Good
var k, m, length,
    // Indent subsequent lines by one tab
    value = 'WordPress';

// Bad
var foo = true;
var bar = false;
var a;
var b;
var c;

全局变量

过去,WordPress 核心更多地使用全局变量。由于核心 JavaScript 文件有时会在插件中使用,因此不应删除现有的全局变量。

文件中使用的所有全局变量都应记录在该文件的顶部。多个全局变量可以用逗号分隔。

此示例将passwordStrength在该文件中创建一个允许的全局变量:

/* global passwordStrength:true */

后面的“真”passwordStrength意味着这个全局是在这个文件中定义的。如果您正在访问在别处定义的全局,请忽略:true将全局指定为只读。

公共图书馆

Backbone、jQuery、Underscore 和全局wp对象都在根.jshintrc文件中注册为允许的全局对象。

可以随时直接访问 Backbone 和 Underscore。应该通过$jQuery对象传递给匿名函数来访问 jQuery:

( function ( $ ) {
    // Expressions
} )( jQuery );

这将不需要调用.noConflict(),或使用另一个变量进行设置$

添加或修改wp对象的文件必须安全地访问全局以避免覆盖以前设置的属性:

// At the top of the file, set "wp" to its existing value (if present)
window.wp = window.wp || {};

命名约定

变量和函数名称应该是完整的单词,使用首字母小写的驼峰式大小写。这是该标准与WordPress PHP 编码标准不同的地方。

名称应该是描述性的,但不要过分。迭代器允许有例外,例如使用 来i表示循环中的索引。

缩写与首字母缩略词

首字母缩略词的每个组成字母必须大写。这是为了反映首字母缩略词的每个字母都是其扩展形式的正确单词。

所有其他缩写必须采用驼峰式大小写,首字母大写,后跟小写字母。

如果缩写词或首字母缩略词出现在变量名的开头,则必须遵循驼峰命名规则,包括变量或类定义的第一个字母。对于变量赋值,这意味着将缩写完全写成小写。对于类定义,其首字母应大写。

// "Id" is an abbreviation of "Identifier":
const userId = 1;

// "DOM" is an acronym of "Document Object Model":
const currentDOMDocument = window.document;

// Acronyms and abbreviations at the start of a variable name are consistent
// with camelcase rules covering the first letter of a variable or class.
const domDocument = window.document;
class DOMDocument {}
class IdCollection {}

类定义

用于 with 的构造函数new首字母应大写 (UpperCamelCase)。

定义必须使用 UpperCamelCase 约定,无论它是否打算与构造class一起使用new

class Earth {
    static addHuman( human ) {
        Earth.humans.push( human );
    }

    static getHumans() {
        return Earth.humans;
    }
}

Earth.humans = [];

所有@wordpress/element组件,包括无状态功能组件,都应使用类定义命名规则进行命名,以保持一致性并反映组件可能需要从功能转换为类而不破坏兼容性的事实。

常量

驼峰式大小写的例外是常量值,它们永远不会被重新分配或改变。此类变量必须使用SCREAMING_SNAKE_CASE 约定。

在几乎所有情况下,常量都应定义在文件的最顶层范围内。重要的是要注意JavaScript 的const赋值在概念上比这里暗示的更受限制,JavaScript 中赋值的值const实际上可以被改变,并且只能防止重新赋值。这些编码指南中定义的常量仅适用于预期永远不会改变的值,并且是开发人员传达意图的策略,而不是技术限制。

评论

注释出现在它们引用的代码之前,并且应该始终以空行开头。将评论的第一个字母大写,并在写完整句子时在末尾加上句号。//评论标记 ( ) 和评论文本之间必须有一个空格。

someStatement();

// Explanation of something complex on the next line
$( 'p' ).doSomething();

// This is a comment that is long enough to warrant being stretched
// over the span of multiple lines.

JSDoc 注释应该使用/**多行注释开头。有关详细信息,请参阅JavaScript 文档标准。

当用于注释形式参数列表中的特殊参数时,允许内联注释作为例外:

function foo( types, selector, data, fn, /* INTERNAL */ one ) {
    // Do stuff
}

判断相等

必须使用严格相等检查 ( ===) 来支持抽象相等检查 ( ==)。

类型检查

这些是检查对象类型的首选方法:

  • 细绳:typeof object === 'string'
  • 数字:typeof object === 'number'
  • 布尔值:typeof object === 'boolean'
  • 对象:typeof object === 'object'_.isObject( object )
  • 普通对象:jQuery.isPlainObject( object )
  • 功能:_.isFunction( object )jQuery.isFunction( object )
  • 数组:_.isArray( object )jQuery.isArray( object )
  • 元素:object.nodeType_.isElement( object )
  • 无效的:object === null
  • 空或未定义:object == null
  • 不明确的:
    • 全局变量:typeof variable === 'undefined'
    • 局部变量:variable === undefined
    • 特性:object.prop === undefined
    • 以上任何一项:_.isUndefined( object )

在已经使用 Backbone 或 Underscore 的任何地方,我们鼓励您使用Underscore.js的类型检查方法而不是 jQuery 的。

字符串

对字符串文字使用单引号:

var myStr = 'strings should be contained in single quotes';

当字符串中包含单引号时,需要使用反斜杠 ( \) 进行转义:

// Escape single quotes within strings:
'Note the backslash before the \'single quotes\'';

Switch条件语句

通常不鼓励使用switch语句,但在存在大量案例时很有用——尤其是当多个案例可以由同一个块处理,或者可以利用 fall-through 逻辑(案例)时default

使用switch语句时:

  • break对除 以外的每种情况使用 a default。当允许语句“失败”时,请明确注意。
  • 在 . 中将语句缩进case一个选项卡switch
switch ( event.keyCode ) {
    // ENTER and SPACE both trigger x()
    case $.ui.keyCode.ENTER:
    case $.ui.keyCode.SPACE:
        x();
        break;
    case $.ui.keyCode.ESCAPE:
        y();
        break;
    default:
        z();
}

不建议从 switch 语句中返回值:使用case块设置值,然后return在最后设置这些值。

function getKeyCode( keyCode ) {
    var result;

    switch ( event.keyCode ) {
        case $.ui.keyCode.ENTER:
        case $.ui.keyCode.SPACE:
            result = 'commit';
            break;
        case $.ui.keyCode.ESCAPE:
            result = 'exit';
            break;
        default:
            result = 'default';
    }

    return result;
}

最佳实践

数组

在 JavaScript 中创建数组应该使用速记[]构造函数而不是new Array()符号来完成。

var myArray = [];

您可以在构造期间初始化数组:

var myArray = [ 1, 'WordPress', 2, 'Blog' ];

在 JavaScript 中,关联数组被定义为对象。

对象

在 JavaScript 中创建对象的方法有很多种。对象字面量表示法{}是性能最高的,也是最容易阅读的。

var myObj = {};

除非对象需要特定的原型,否则应使用对象文字表示法,在这种情况下,应通过调用构造函数来创建对象new

var myObj = new ConstructorMethod();

对象属性应该通过点表示法访问,除非键是变量或不是有效标识符的字符串:

prop = object.propertyName;
prop = object[ variableKey ];
prop = object['key-with-hyphens'];

迭代

当使用循环遍历大型集合时for,建议将循环的最大值存储为变量,而不是每次都重新计算最大值:

// Good & Efficient
var i, max;

// getItemCount() gets called once
for ( i = 0, max = getItemCount(); i < max; i++ ) {
    // Do stuff
}

// Bad & Potentially Inefficient:
// getItemCount() gets called every time
for ( i = 0; i < getItemCount(); i++ ) {
    // Do stuff
}

Underscore.js 集合函数

学习理解 Underscore 的集合和数组方法。这些函数(包括_.each_.map_.reduce)允许对大型数据集进行高效、可读的转换。

Underscore 还允许与常规 JavaScript 对象进行 jQuery 样式的链接:

var obj = {
    first: 'thing 1',
    second: 'thing 2',
    third: 'lox'
};

var arr = _.chain( obj )
    .keys()
    .map( function ( key ) {
        return key + ' comes ' + obj[ key ];
    } )
    // Exit the chain
    .value();

// arr === [ 'first comes thing 1', 'second comes thing 2', 'third comes lox' ]

遍历 jQuery 集合

唯一一次应该使用 jQuery 进行迭代是在迭代一组 jQuery 对象时:

$tabs.each( function ( index, element ) {
    var $element = $( element );

    // Do stuff to $element
} );

切勿使用 jQuery 迭代原始数据或原始 JavaScript 对象。

JSHint

JSHint是一种自动化的代码质量工具,旨在捕获 JavaScript 代码中的错误。JSHint 在 WordPress 开发中用于快速验证补丁是否没有向前端引入任何逻辑或语法错误。

安装和运行 JSHint

JSHint 使用名为Grunt的工具运行。JSHint 和 Grunt 都是用Node.js编写的程序。package.jsonWordPress 开发代码附带的配置文件允许您安装和配置这些工具。

要安装 Node.js,请单击Node.js网站上的安装链接。将下载适用于您的操作系统的正确安装文件。按照适用于您的操作系统的安装步骤来安装程序。

安装 Node.js 后,打开命令行窗口并导航到您检出 WordPress SVN 存储库副本的目录(使用cd ~/directoryname. 您应该位于包含该package.json文件的根目录中。

接下来,npm install在命令行窗口中键入。这将下载并安装 WordPress 开发中使用的所有 Node 包。

您现在应该能够键入npm run grunt jshint让 Grunt 检查所有 WordPress JavaScript 文件的语法和逻辑错误。要仅检查核心代码,请键入npm run grunt jshint:core;要仅检查单元测试 .js 文件,请键入npm run grunt jshint:tests.

JSHint 设置

用于 JSHint 的配置选项存储在 WordPress SVN 存储库中的.jshintrctitle=”WordPress JSHint file in svn trunk”中。该文件定义了 JSHint 在 WordPress 源代码中发现错误时应该标记的错误。

定位单个文件

要为 JSHint 指定要检查的单个文件,请将其添加--file=filename.js到命令的末尾。例如,这将只检查 WordPress 核心 JavaScript 文件中名为“admin-bar.js”的文件:

npm run grunt jshint:core --file=admin-bar.js

这只会检查单元测试目录中的“password-strength-meter.js”文件:

npm run grunt jshint:tests --file=password-strength-meter.js

如果您只处理一个或两个特定文件并且不想在每次运行时等待 JSHint 处理每个文件,那么将 JSHint 限制为单个文件会很有用。

JSHint 覆盖:忽略块

在某些情况下,文件的某些部分应该从 JSHint 中排除。例如,管理栏的脚本文件包含 jQuery HoverIntent 插件的精简代码——这是不应通过 JSHint 传递的第三方代码,即使它是 WordPress 核心 JavaScript 文件的一部分。

要排除 JSHint 处理的特定文件区域,请将其包含在 JSHint 指令注释中:

/* jshint ignore:start */
if ( typeof jQuery.fn.hoverIntent === 'undefined' ) {
    // hoverIntent r6 - Copy of wp-includes/js/hoverIntent.min.js
    (function(a){a.fn.hoverIntent=...............
}
/* jshint ignore:end */