Title here
' + 'This is a paragraph
' + '' + 'Title here
', @@ -522,14 +524,14 @@ foo( ); // 也可以按逻辑对参数进行组合。 -// 最经典的是baidu.format函数,调用时将参数分为“模板”和“数据”两块 +// 最经典的是 baidu.format 函数,调用时将参数分为“模板”和“数据”两块 baidu.format( dateFormatTemplate, year, month, date, hour, minute, second ); // 当函数调用时,如果有一个或以上参数跨越多行,应当每一个参数独立一行。 -// 这通常出现在匿名函数或者对象初始化等作为参数时,如setTimeout函数等。 +// 这通常出现在匿名函数或者对象初始化等作为参数时,如 `setTimeout` 函数等。 setTimeout( function () { alert('hello'); @@ -538,11 +540,11 @@ setTimeout( ); order.data.read( - 'id=' + me.model.id, + 'id=' + me.model.id, function (data) { me.attchToModel(data.result); callback(); - }, + }, 300 ); @@ -560,7 +562,7 @@ var result = condition ? thisIsAVeryVeryLongResult : resultB; -// 数组和对象初始化的混用,严格按照每个对象的 { 和结束 } 在独立一行的风格书写。 +// 数组和对象初始化的混用,严格按照每个对象的 `{` 和结束 `}` 在独立一行的风格书写。 var array = [ { // ... @@ -715,7 +717,7 @@ function TextNode(options) { } ``` -##### [强制] 类的 `方法 / 属性` 使用 `Camel命名法`。 +##### [强制] 类的 `方法` / `属性` 使用 `Camel命名法`。 示例: @@ -846,7 +848,7 @@ loadingData.then(callback); #### 2.4.4 类型定义 -##### [强制] 类型定义都是以`{`开始, 以`}`结束。 +##### [强制] 类型定义都是以 `{` 开始, 以 `}` 结束。 解释: @@ -873,6 +875,7 @@ loadingData.then(callback); |不允许为null|{!Object}|Object 类型, 但不是 null| |Function类型|{function(number, boolean)}|函数, 形参类型| |Function带返回值|{function(number, boolean):string}|函数, 形参, 返回值类型| +|Promise|Promise.<resolveType, rejectType>|Promise,成功返回的数据类型,失败返回的错误类型| |参数可选|@param {string=} name|可选参数, =为类型后缀| |可变参数|@param {...number} args|变长参数, ...为类型前缀| |任意类型|{*}|任意类型| @@ -997,14 +1000,14 @@ function Fronteer() { util.extend( Fronteer.prototype, /** @lends Fronteer.prototype */{ - _getLevel: function () { + getLevel: function () { // TODO } } ); ``` -##### [强制] 类的属性或方法等成员信息使用 `@public` / `@protected` / `@private` 中的任意一个,指明可访问性。 +##### [强制] 类的属性或方法等成员信息不是 `public` 的,应使用 `@protected` 或 `@private` 标识可访问性。 解释: @@ -1028,7 +1031,7 @@ var Fronteer = function () { * @type {string} * @private */ - this._level = 'T12'; + this.level = 'T12'; // constructor body }; @@ -1040,7 +1043,7 @@ util.inherits(Fronteer, Developer); * @private * @return {string} 返回值描述 */ -Fronteer.prototype._getLevel = function () { +Fronteer.prototype.getLevel = function () { }; ``` @@ -1050,7 +1053,12 @@ Fronteer.prototype._getLevel = function () { ##### [强制] 函数/方法注释必须包含函数说明,有参数和返回值时必须使用注释标识。 -##### [强制] 参数和返回值注释必须包含类型信息和说明。 +解释: + +当 `return` 关键字仅作退出函数/方法使用时,无须对返回值作注释标识。 + + +##### [强制] 参数和返回值注释必须包含类型信息,且不允许省略参数的说明。 ##### [建议] 当函数是内部函数,外部不可访问时,可以使用 `@inner` 标识。 @@ -1110,13 +1118,18 @@ function foo(option) { /** * 值变更时触发 * - * @event + * @event Select#change * @param {Object} e e描述 * @param {string} e.before before描述 * @param {string} e.after after描述 */ -onchange: function (e) { -} +this.fire( + 'change', + { + before: 'foo', + after: 'bar' + } +); ``` ##### [强制] 在会广播事件的函数前使用 `@fires` 标识广播的事件,在广播事件代码前使用 `@event` 标识事件。 @@ -1133,6 +1146,7 @@ onchange: function (e) { * @private */ Select.prototype.clickHandler = function () { + /** * 值变更时触发 * @@ -1462,7 +1476,7 @@ function foo(p1, p2, opt_p3) { ### 3.1 变量 -##### [强制] 变量在使用前必须通过 `var` 定义。 +##### [强制] 变量、函数在使用前必须先定义。 解释: @@ -1479,11 +1493,20 @@ var name = 'MyName'; name = 'MyName'; ``` +原则上不建议使用全局变量,对于已有的全局变量或第三方框架引入的全局变量,需要根据检查工具的语法标识。 + +示例: + +```javascript +/* globals jQuery */ +var element = jQuery('#element-id'); +``` + ##### [强制] 每个 `var` 只能声明一个变量。 解释: -一个 var 声明多个变量,容易导致较长的行长度,并且在修改时容易造成逗号和分号的混淆。 +一个 `var` 声明多个变量,容易导致较长的行长度,并且在修改时容易造成逗号和分号的混淆。 示例: @@ -1503,14 +1526,14 @@ var hangModules = [], ##### [强制] 变量必须 `即用即声明`,不得在函数或其它形式的代码块起始位置统一声明所有变量。 -解释: +解释: 变量声明与使用的距离越远,出现的跨度越大,代码的阅读与维护成本越高。虽然JavaScript的变量是函数作用域,还是应该根据编程中的意图,缩小变量出现的距离空间。 示例: -```javascript +```javascript // good function kv2List(source) { var list = []; @@ -1521,6 +1544,7 @@ function kv2List(source) { k: key, v: source[key] }; + list.push(item); } } @@ -1540,6 +1564,7 @@ function kv2List(source) { k: key, v: source[key] }; + list.push(item); } } @@ -1556,11 +1581,11 @@ function kv2List(source) { ### 3.2 条件 -##### [强制] 在 Equality Expression 中使用类型严格的 `===`。仅当判断 null 或 undefined 时,允许使用 `== null`。 +##### [强制] 在 Equality Expression 中使用类型严格的 `===`。仅当判断 `null` 或 `undefined` 时,允许使用 `== null`。 解释: -使用 === 可以避免等于判断中隐式的类型转换。 +使用 `===` 可以避免等于判断中隐式的类型转换。 示例: @@ -1684,7 +1709,7 @@ switch (typeof variable) { var type = typeof variable; if (type === 'object') { // ...... -} +} else if (type === 'number' || type === 'boolean' || type === 'string') { // ...... } @@ -1777,7 +1802,7 @@ for (var i = 0, len = elements.length; i < len; i++) { 解释: -虽然现代浏览器都对数组长度进行了缓存,但对于一些宿主对象和老旧浏览器的数组对象,在每次 length 访问时会动态计算元素个数,此时缓存 length 能有效提高程序性能。 +虽然现代浏览器都对数组长度进行了缓存,但对于一些宿主对象和老旧浏览器的数组对象,在每次 `length` 访问时会动态计算元素个数,此时缓存 `length` 能有效提高程序性能。 示例: @@ -1911,7 +1936,7 @@ var num = 3.14; !!num; ``` -##### [建议] `number` 去除小数点,使用 `Math.floor / Math.round / Math.ceil`,不使用 `parseInt`。 +##### [建议] `number` 去除小数点,使用 `Math.floor` / `Math.round` / `Math.ceil`,不使用 `parseInt`。 示例: @@ -1935,7 +1960,7 @@ parseInt(num, 10); 解释: -1. 输入单引号不需要按住 shift,方便输入。 +1. 输入单引号不需要按住 `shift`,方便输入。 2. 实际使用中,字符串经常用来拼接 HTML。为方便 HTML 中包含双引号而不需要转义写法。 示例: @@ -1949,8 +1974,8 @@ var html = '- ',
+ '
- 第一项 ', @@ -1973,6 +1998,30 @@ var str2 = '' // 建议第一个为空字符串, 第二个换行开始并缩进 + '
' + htmlEncode(content) + '
'; + +// HTML 转义 +var str = ''; + +// URL 转义 +var str = 'link'; + +// JavaScript字符串 转义 + HTML 转义 +var str = ''; +``` + + ##### [建议] 复杂的数据到视图字符串的转换过程,选用一种模板引擎。 解释: @@ -1981,6 +2030,7 @@ var str2 = '' // 建议第一个为空字符串, 第二个换行开始并缩进 1. 在开发过程中专注于数据,将视图生成的过程由另外一个层级维护,使程序逻辑结构更清晰。 2. 优秀的模板引擎,通过模板编译技术和高质量的编译产物,能获得比手工拼接字符串更高的性能。 +3. 模板引擎能方便的对动态数据进行相应的转义,部分模板引擎默认进行HTML转义,安全性更好。 - artTemplate: 体积较小,在所有环境下性能高,语法灵活。 - dot.js: 体积小,在现代浏览器下性能高,语法灵活。 @@ -1997,7 +2047,7 @@ var str2 = '' // 建议第一个为空字符串, 第二个换行开始并缩进 ##### [强制] 使用对象字面量 `{}` 创建新 `Object`。 -示例: +示例: ```javascript // good @@ -2007,9 +2057,9 @@ var obj = {}; var obj = new Object(); ``` -##### [强制] 对象创建时,如果一个对象的所有 `属性` 均可以不添加引号,则所有 `属性` 不得添加引号。 +##### [建议] 对象创建时,如果一个对象的所有 `属性` 均可以不添加引号,建议所有 `属性` 不添加引号。 -示例: +示例: ```javascript var info = { @@ -2018,14 +2068,14 @@ var info = { }; ``` -##### [强制] 对象创建时,如果任何一个 `属性` 需要添加引号,则所有 `属性` 必须添加 `'`。 +##### [建议] 对象创建时,如果任何一个 `属性` 需要添加引号,则所有 `属性` 建议添加 `'`。 解释: 如果属性不符合 Identifier 和 NumberLiteral 的形式,就需要以 StringLiteral 的形式提供。 -示例: +示例: ```javascript // good @@ -2045,7 +2095,7 @@ var info = { ##### [强制] 不允许修改和扩展任何原生对象和宿主对象的原型。 -示例: +示例: ```javascript // 以下行为绝对禁止 @@ -2059,10 +2109,10 @@ String.prototype.trim = function () { 属性名符合 Identifier 的要求,就可以通过 `.` 来访问,否则就只能通过 `[expr]` 方式访问。 -通常在 JavaScript 中声明的对象,属性命名是使用 Camel 命名法,用 `.` 来访问更清晰简洁。部分特殊的属性(比如来自后端的JSON),可能采用不寻常的命名方式,可以通过 `[expr]` 方式访问。 +通常在 JavaScript 中声明的对象,属性命名是使用 Camel 命名法,用 `.` 来访问更清晰简洁。部分特殊的属性(比如来自后端的 JSON ),可能采用不寻常的命名方式,可以通过 `[expr]` 方式访问。 -示例: +示例: ```javascript info.age; @@ -2104,13 +2154,15 @@ var arr = new Array(); 解释: -数组对象可能存在数字以外的属性, 这种情况下 for in 不会得到正确结果. +数组对象可能存在数字以外的属性, 这种情况下 `for in` 不会得到正确结果。 示例: ```javascript var arr = ['a', 'b', 'c']; -arr.other = 'other things'; // 这里仅作演示, 实际中应使用Object类型 + +// 这里仅作演示, 实际中应使用 Object 类型 +arr.other = 'other things'; // 正确的遍历方式 for (var i = 0, len = arr.length; i < len; i++) { @@ -2118,7 +2170,7 @@ for (var i = 0, len = arr.length; i < len; i++) { } // 错误的遍历方式 -for (i in arr) { +for (var i in arr) { console.log(i); } ``` @@ -2127,7 +2179,7 @@ for (i in arr) { 解释: -自己实现的常规排序算法,在性能上并不优于数组默认的 sort 方法。以下两种场景可以自己实现排序: +自己实现的常规排序算法,在性能上并不优于数组默认的 `sort` 方法。以下两种场景可以自己实现排序: 1. 需要稳定的排序算法,达到严格一致的排序结果。 2. 数据特点鲜明,适合使用桶排。 @@ -2165,14 +2217,14 @@ function syncViewStateOnUserAction() { y.checked = false; } - if (!a.value) { - warning.innerText = 'Please enter it'; - submitButton.disabled = true; - } - else { + if (a.value) { warning.innerText = ''; submitButton.disabled = false; } + else { + warning.innerText = 'Please enter it'; + submitButton.disabled = true; + } } // 直接阅读该函数会难以明确其主线逻辑,因此下方是一种更合理的表达方式: @@ -2183,21 +2235,19 @@ function syncViewStateOnUserAction() { } function syncXStateToView() { + y.checked = x.checked; + if (x.checked) { - y.checked = true; z.value = ''; } - else { - y.checked = false; - } } function checkAAvailability() { - if (!a.value) { - displayWarningForAMissing(); + if (a.value) { + clearWarnignForA(); } else { - clearWarnignForA(); + displayWarningForAMissing(); } } ``` @@ -2210,16 +2260,16 @@ function checkAAvailability() { 解释: -除去不定长参数以外,函数具备不同逻辑意义的参数建议控制在 6 个以内,过多参数会导致维护难度增大。 +除去不定长参数以外,函数具备不同逻辑意义的参数建议控制在 `6` 个以内,过多参数会导致维护难度增大。 -某些情况下,如使用 AMD Loader 的 require 加载多个模块时,其 callback 可能会存在较多参数,因此对函数参数的个数不做强制限制。 +某些情况下,如使用 AMD Loader 的 `require` 加载多个模块时,其 `callback` 可能会存在较多参数,因此对函数参数的个数不做强制限制。 ##### [建议] 通过 `options` 参数传递非数据输入型参数。 解释: -有些函数的参数并不是作为算法的输入,而是对算法的某些分支条件判断之用,此类参数建议通过一个 options 参数传递。 +有些函数的参数并不是作为算法的输入,而是对算法的某些分支条件判断之用,此类参数建议通过一个 `options` 参数传递。 如下函数: @@ -2232,6 +2282,7 @@ function checkAAvailability() { */ function removeElement(element, removeEventListeners) { element.parent.removeChild(element); + if (removeEventListeners) { element.clearEventListeners(); } @@ -2250,6 +2301,7 @@ function removeElement(element, removeEventListeners) { */ function removeElement(element, options) { element.parent.removeChild(element); + if (options.removeEventListeners) { element.clearEventListeners(); } @@ -2258,8 +2310,8 @@ function removeElement(element, options) { 这种模式有几个显著的优势: -- boolean 型的配置项具备名称,从调用的代码上更易理解其表达的逻辑意义。 -- 当配置项有增长时,无需无休止地增加参数个数,不会出现 removeElement(element, true, false, false, 3) 这样难以理解的调用代码。 +- `boolean` 型的配置项具备名称,从调用的代码上更易理解其表达的逻辑意义。 +- 当配置项有增长时,无需无休止地增加参数个数,不会出现 `removeElement(element, true, false, false, 3)` 这样难以理解的调用代码。 - 当部分配置参数可选时,多个参数的形式非常难处理重载逻辑,而使用一个 options 对象只需判断属性是否存在,实现得以简化。 @@ -2273,7 +2325,7 @@ function removeElement(element, options) { 在 JavaScript 中,无需特别的关键词就可以使用闭包,一个函数可以任意访问在其定义的作用域外的变量。需要注意的是,函数的作用域是静态的,即在定义时决定,与调用的时机和方式没有任何关系。 -闭包会阻止一些变量的垃圾回收,对于较老旧的JavaScript引擎,可能导致外部所有变量均无法回收。 +闭包会阻止一些变量的垃圾回收,对于较老旧的 JavaScript 引擎,可能导致外部所有变量均无法回收。 首先一个较为明确的结论是,以下内容会影响到闭包内变量的回收: @@ -2281,23 +2333,23 @@ function removeElement(element, options) { - 嵌套的函数中是否有 **直接调用eval**。 - 是否使用了 with 表达式。 -Chakra、V8 和 SpiderMonkey 将受以上因素的影响,表现出不尽相同又较为相似的回收策略,而JScript.dll和Carakan则完全没有这方面的优化,会完整保留整个 LexicalEnvironment 中的所有变量绑定,造成一定的内存消耗。 +Chakra、V8 和 SpiderMonkey 将受以上因素的影响,表现出不尽相同又较为相似的回收策略,而 JScript.dll 和 Carakan 则完全没有这方面的优化,会完整保留整个 LexicalEnvironment 中的所有变量绑定,造成一定的内存消耗。 -由于对闭包内变量有回收优化策略的 Chakra、V8 和 SpiderMonkey 引擎的行为较为相似,因此可以总结如下,当返回一个函数 fn 时: +由于对闭包内变量有回收优化策略的 Chakra、V8 和 SpiderMonkey 引擎的行为较为相似,因此可以总结如下,当返回一个函数 **fn** 时: -1. 如果 fn 的 [[Scope]] 是ObjectEnvironment(with 表达式生成 ObjectEnvironment,函数和 catch 表达式生成 DeclarativeEnvironment),则: +1. 如果 **fn** 的 `[[Scope]]` 是 ObjectEnvironment(with 表达式生成 ObjectEnvironment,函数和 catch 表达式生成 DeclarativeEnvironment),则: 1. 如果是 V8 引擎,则退出全过程。 2. 如果是 SpiderMonkey,则处理该 ObjectEnvironment 的外层 LexicalEnvironment。 2. 获取当前 LexicalEnvironment 下的所有类型为 Function 的对象,对于每一个 Function 对象,分析其 FunctionBody: - 1. 如果 FunctionBody 中含有 **直接调用eval**,则退出全过程。 + 1. 如果 FunctionBody 中含有 **直接调用 eval**,则退出全过程。 2. 否则得到所有的 Identifier。 - 3. 对于每一个 Identifier,设其为 name,根据查找变量引用的规则,从 LexicalEnvironment 中找出名称为 name 的绑定 binding。 - 4. 对 binding 添加 notSwap 属性,其值为 true。 -3. 检查当前 LexicalEnvironment 中的每一个变量绑定,如果该绑定有 notSwap 属性且值为 true,则: - 1. 如果是V8引擎,删除该绑定。 - 2. 如果是SpiderMonkey,将该绑定的值设为 undefined,将删除 notSwap 属性。 + 3. 对于每一个 Identifier,设其为 **name**,根据查找变量引用的规则,从 LexicalEnvironment 中找出名称为 **name** 的绑定 binding。 + 4. 对 binding 添加 **notSwap** 属性,其值为 `true`。 +3. 检查当前 LexicalEnvironment 中的每一个变量绑定,如果该绑定有 **notSwap** 属性且值为 `true`,则: + 1. 如果是 V8 引擎,删除该绑定。 + 2. 如果是 SpiderMonkey,将该绑定的值设为 `undefined`,将删除 **notSwap** 属性。 -对于Chakra引擎,暂无法得知是按 V8 的模式还是按 SpiderMonkey 的模式进行。 +对于 Chakra 引擎,暂无法得知是按 V8 的模式还是按 SpiderMonkey 的模式进行。 如果有 **非常庞大** 的对象,且预计会在 **老旧的引擎** 中执行,则使用闭包时,注意将闭包不需要的对象置为空引用。 @@ -2381,7 +2433,7 @@ MyClass.prototype.hooks.after = EMPTY_FUNCTION; 解释: -通常使用其他 library 的类继承方案都会进行 constructor 修正。如果是自己实现的类继承方案,需要进行 constructor 修正。 +通常使用其他 library 的类继承方案都会进行 `constructor` 修正。如果是自己实现的类继承方案,需要进行 `constructor` 修正。 示例: @@ -2389,7 +2441,7 @@ MyClass.prototype.hooks.after = EMPTY_FUNCTION; ```javascript /** * 构建类之间的继承关系 - * + * * @param {Function} subClass 子类函数 * @param {Function} superClass 父类函数 */ @@ -2428,7 +2480,7 @@ Animal.prototype.jump = function () { ##### [建议] 属性在构造函数中声明,方法在原型中声明。 -解释: +解释: 原型对象的成员被所有实例共享,能节约内存占用。所以编码时我们应该遵守这样的原则:原型对象包含程序不会修改的成员,如方法函数或配置项。 @@ -2466,8 +2518,8 @@ TextNode.prototype.clone = function () { 常见禁止默认行为的方式有两种: -1. 事件监听函数中 return false。 -2. 事件对象中包含禁止默认行为的方法,如 preventDefault。 +1. 事件监听函数中 `return false`。 +2. 事件对象中包含禁止默认行为的方法,如 `preventDefault`。 @@ -2482,9 +2534,9 @@ TextNode.prototype.clone = function () { 解释: -直接 eval,指的是以函数方式调用 eval 的调用方法。直接 eval 调用执行代码的作用域为本地作用域,应当避免。 +直接 `eval`,指的是以函数方式调用 `eval` 的调用方法。直接 `eval` 调用执行代码的作用域为本地作用域,应当避免。 -如果有特殊情况需要使用直接 eval,需在代码中用详细的注释说明为何必须使用直接 eval,不能使用其它动态执行代码的方式,同时需要其他资深工程师进行 Code Review。 +如果有特殊情况需要使用直接 `eval`,需在代码中用详细的注释说明为何必须使用直接 `eval`,不能使用其它动态执行代码的方式,同时需要其他资深工程师进行 Code Review。 ##### [建议] 尽量避免使用 `eval` 函数。 @@ -2496,7 +2548,7 @@ TextNode.prototype.clone = function () { 解释: -通过 new Function 生成的函数作用域是全局使用域,不会影响当当前的本地作用域。如果有动态代码执行的需求,建议使用 new Function。 +通过 `new Function` 生成的函数作用域是全局使用域,不会影响当当前的本地作用域。如果有动态代码执行的需求,建议使用 `new Function`。 示例: @@ -2515,7 +2567,7 @@ var result = handler($('#x').val(), $('#y').val()); 解释: -使用 with 可能会增加代码的复杂度,不利于阅读和管理;也会对性能有影响。大多数使用 with 的场景都能使用其他方式较好的替代。所以,尽量不要使用 with。 +使用 `with` 可能会增加代码的复杂度,不利于阅读和管理;也会对性能有影响。大多数使用 `with` 的场景都能使用其他方式较好的替代。所以,尽量不要使用 `with`。 @@ -2527,16 +2579,16 @@ var result = handler($('#x').val(), $('#y').val()); 解释: -如果没有特别的需求,减少或避免使用`delete`。`delete`的使用会破坏部分 JavaScript 引擎的性能优化。 +如果没有特别的需求,减少或避免使用 `delete`。`delete` 的使用会破坏部分 JavaScript 引擎的性能优化。 ##### [建议] 处理 `delete` 可能产生的异常。 解释: -对于有被遍历需求,且值 null 被认为具有业务逻辑意义的值的对象,移除某个属性必须使用 delete 操作。 +对于有被遍历需求,且值 `null` 被认为具有业务逻辑意义的值的对象,移除某个属性必须使用 `delete` 操作。 -在严格模式或IE下使用 delete 时,不能被删除的属性会抛出异常,因此在不确定属性是否可以删除的情况下,建议添加 try-catch 块。 +在严格模式或 IE 下使用 `delete` 时,不能被删除的属性会抛出异常,因此在不确定属性是否可以删除的情况下,建议添加 `try-catch` 块。 示例: @@ -2563,7 +2615,7 @@ JavaScript 因其脚本语言的动态特性,当一个对象未被 seal 或 fr 但是随意地对 非自身控制的对象 进行修改,很容易造成代码在不可预知的情况下出现问题。因此,设计良好的组件、函数应该避免对外部传入的对象的修改。 -下面代码的 selectNode 方法修改了由外部传入的 datasource 对象。如果 datasource 用在其它场合(如另一个 Tree 实例)下,会造成状态的混乱。 +下面代码的 **selectNode** 方法修改了由外部传入的 **datasource** 对象。如果 **datasource** 用在其它场合(如另一个 Tree 实例)下,会造成状态的混乱。 ```javascript function Tree(datasource) { @@ -2580,7 +2632,7 @@ Tree.prototype.selectNode = function (id) { }; ``` -对于此类场景,需要使用额外的对象来维护,使用由自身控制,不与外部产生任何交互的 selectedNodeIndex 对象来维护节点的选中状态,不对 datasource 作任何修改。 +对于此类场景,需要使用额外的对象来维护,使用由自身控制,不与外部产生任何交互的 **selectedNodeIndex** 对象来维护节点的选中状态,不对 **datasource** 作任何修改。 ```javascript function Tree(datasource) { @@ -2589,12 +2641,15 @@ function Tree(datasource) { } Tree.prototype.selectNode = function (id) { + // 从datasource中找出节点对象 var node = this.findNode(id); + if (node) { this.selectedNodeIndex[id] = true; this.flushView(); } + }; ``` @@ -2605,8 +2660,8 @@ Tree.prototype.selectNode = function (id) { 解释: -- 如果一个属性被设计为 boolean 类型,则不要使用 1 / 0 作为其值。对于标识性的属性,如对代码体积有严格要求,可以从一开始就设计为 number 类型且将 0 作为否定值。 -- 从 DOM 中取出的值通常为 string 类型,如果有对象或函数的接收类型为 number 类型,提前作好转换,而不是期望对象、函数可以处理多类型的值。 +- 如果一个属性被设计为 `boolean` 类型,则不要使用 `1` 或 `0` 作为其值。对于标识性的属性,如对代码体积有严格要求,可以从一开始就设计为 `number` 类型且将 `0` 作为否定值。 +- 从 DOM 中取出的值通常为 `string` 类型,如果有对象或函数的接收类型为 `number` 类型,提前作好转换,而不是期望对象、函数可以处理多类型的值。 @@ -2659,9 +2714,9 @@ AMD 作为由社区认可的模块定义形式,提供多种重载提供灵活 解释: -在 AMD 的设计思想里,模块名称是和所在路径相关的,匿名的模块更利于封包和迁移。模块依赖应在模块定义内部通过 local require 引用。 +在 AMD 的设计思想里,模块名称是和所在路径相关的,匿名的模块更利于封包和迁移。模块依赖应在模块定义内部通过 `local require` 引用。 -所以,推荐使用 define(factory) 的形式进行模块定义。 +所以,推荐使用 `define(factory)` 的形式进行模块定义。 示例: @@ -2721,15 +2776,15 @@ var foo = require('foo'); 解释: -1. 在模块定义中使用 global require,对封装性是一种破坏。 -2. 在 AMD 里,global require 是可以被重命名的。并且 Loader 甚至没有全局的 require 变量,而是用 Loader 名称做为 global require。模块定义不应该依赖使用的 Loader。 +1. 在模块定义中使用 `global require`,对封装性是一种破坏。 +2. 在 AMD 里,`global require` 是可以被重命名的。并且 Loader 甚至没有全局的 `require` 变量,而是用 Loader 名称做为 `global require`。模块定义不应该依赖使用的 Loader。 -##### [强制] Package在实现时,内部模块的 `require` 必须使用 `relative id`。 +##### [强制] Package 在实现时,内部模块的 `require` 必须使用 `relative id`。 解释: -对于任何可能通过 发布-引入 的形式复用的第三方库、框架、包,开发者所定义的名称不代表使用者使用的名称。因此不要基于任何名称的假设。在实现源码中,require 自身的其它模块时使用 relative id。 +对于任何可能通过 发布-引入 的形式复用的第三方库、框架、包,开发者所定义的名称不代表使用者使用的名称。因此不要基于任何名称的假设。在实现源码中,`require` 自身的其它模块时使用 `relative id`。 示例: @@ -2746,7 +2801,7 @@ define( 解释: -有些模块是依赖的模块,但不会在模块实现中被直接调用,最为典型的是 css / js / tpl 等 Plugin 所引入的外部内容。此类内容建议放在模块定义最开始处统一引用。 +有些模块是依赖的模块,但不会在模块实现中被直接调用,最为典型的是 `css` / `js` / `tpl` 等 Plugin 所引入的外部内容。此类内容建议放在模块定义最开始处统一引用。 示例: diff --git a/less-code-style.md b/less-code-style.md index 14186b8..861481a 100644 --- a/less-code-style.md +++ b/less-code-style.md @@ -1,10 +1,10 @@ -# Less 编码规范 (1.0) +# Less 编码规范 (1.1) ## 简介 该文档主要的设计目标是提高 Less 文档的团队一致性与可维护性。 -Less 代码的基本规范和原则与 [HTML 与 CSS 编码规范](https://github.com/ecomfe/spec/blob/master/html-and-css-code-style.md)中的 CSS 部分保持一致。 +Less 代码的基本规范和原则与 [CSS 编码规范](https://github.com/ecomfe/spec/blob/master/css-style-guide.md) 保持一致。 ### 编撰 @@ -20,7 +20,7 @@ erik、顾轶灵、黄后锦、李玉北、赵雷。 ## 编码 -使用UTF-8编码。HTML、CSS、模板等文件*不得*(MUST NOT)包含BOM信息。 +使用UTF-8编码。*不得*(MUST NOT)包含BOM信息。 *** @@ -183,7 +183,7 @@ margin-top: 0; ### 颜色 -颜色定义*必须*(MUST)使用 `#RRGGBB` 格式定义,并在可能时*尽量*(SHOULD)缩写为 `#RGB` 形式,且避免直接使用颜色名称与 `rgb()` 表达式。 +颜色定义*必须*(MUST)使用 `#rrggbb` 格式定义,并在可能时*尽量*(SHOULD)缩写为 `#rgb` 形式,且避免直接使用颜色名称与 `rgb()` 表达式。 ```less // ✗ @@ -191,8 +191,8 @@ border-color: red; color: rgb(254, 254, 254); // ✓ -border-color: #F00; -color: #FEFEFE; +border-color: #f00; +color: #fefefe; ``` ### 私有属性前缀 @@ -365,7 +365,7 @@ Mixin 的参数分隔符使用 `,` 和 `;` 均可,但在同一项目中*必须 在进行字符串转义时,使用 `~""` 表达式与 `e()` 函数均可,但在同一项目中*必须*(MUST)保持一致。 -字符串两侧的引号*可以*(MAY)使用 `'` 或 `"`,但在同一项目中*必须*(MUST)保持一致。 +字符串两侧的引号*必须*(MUST)使用 `"`。 ## JS 表达式 diff --git a/package.md b/package.md index 22e2fd0..d64bef8 100644 --- a/package.md +++ b/package.md @@ -96,7 +96,7 @@ require.config({ ### 示例 - ```javascript + ```JavaScript { "name": "zrender", "version": "0.0.1", @@ -112,7 +112,8 @@ require.config({ "uglify-js": "*" } } - ``` +``` + ## 包目录结构 diff --git a/react-style-guide.md b/react-style-guide.md new file mode 100644 index 0000000..13e34a5 --- /dev/null +++ b/react-style-guide.md @@ -0,0 +1,459 @@ +# React规范 + +## 文件组织 + +- [强制]同一目录下不得拥有同名的`.js`和`.jsx`文件。 + + 在使用模块导入时,倾向于不添加后缀,如果存在同名但不同后缀的文件,构建工具将无法决定哪一个是需要引入的模块。 + +- [强制]组件文件使用一致的`.js`或 `.jsx`后缀。 + + 所有组件文件的后缀名从`.js`或`.jsx`中任选其一。 + + 不应在项目中出现部分组件为`.js`文件,部分为`.jsx`的情况。 + +- [强制]每一个文件以`export default`的形式暴露一个组件。 + + 允许一个文件中存在多个不同的组件,但仅允许通过`export default`暴露一个组件,其它组件均定义为内部组件。 + +- [强制]每个存放组件的目录使用一个`index.js`以命名导出的形式暴露所有组件。 + + 同目录内的组件相互引用使用`import Foo from './Foo';`进行。 + + 引用其它目录的组件使用`import {Foo} from '../component';`进行。 + + 建议使用[VSCode的export-index插件](https://marketplace.visualstudio.com/items?itemName=BrunoLM.export-index)等插件自动生成`index.js`的内容。 + +## 命名规则 + +- [强制]组件名为PascalCase。 + + 包括函数组件,名称均为PascalCase。 + +- [强制]组件名称与文件名称保持相同。 + + 同时组件名称应当能体现出组件的功能,以便通过观察文件名即确定使用哪一个组件。 + +- [强制]高阶组件使用camelCase命名。 + + 高阶组件事实上并非一个组件,而是一个“生成组件类型”的函数,因此遵守JavaScript函数命名的规范,使用camelCase命名。 + +- [强制]使用`onXxx`形式作为`props`中用于回调的属性名称。 + + 使用统一的命名规则用以区分`props`中回调和非回调部分的属性,在JSX上可以清晰地看到一个组件向上和向下的逻辑交互。 + + 对于不用于回调的函数类型的属性,使用动词作为属性名称。 + + ```javascript + // onClick作为回调以on开头,renderText非回调函数则使用动词 + let Label = ({onClick, renderText}) => {renderText()}; + ``` + +- [建议]使用`withXxx`或`xxxable`形式的词作为高阶组件的名称。 + + 高阶组件是为组件添加行为和功能的函数,因此使用如上形式的词有助于对其功能进行理解。 + +- [建议]作为组件方法的事件处理函数以具备业务含义的词作为名称,不使用`onXxx`形式命名。 + + ```javascript + // Good + class Form { + @autobind + collectAndSubmitData() { + let data = { + name: this.state.name, + age: this.state.age + }; + this.props.onSubmit(data); + } + + @autobind + syncName() { + // ... + } + + @autobind + syncAge() { + // ... + } + + render() { + return ( +-
+ {
+ items.map(item => (
+
-
+
+ +{item.title}
+ {item.subtitle} +{item.content} + +
+ ))
+ }
+
{title}
+ {subtitle} +-
+ {items.map(Item)}
+