前言
JavaScript在百度一直有着广泛的应用,特别是在浏览器端的行为管理。本文档的目标是使JavaScript代码风格保持一致,容易被理解和被维护。
虽然本文档是针对JavaScript设计的,但是在使用各种JavaScript的预编译语言时(如TypeScript等)时,适用的部分也应尽量遵循本文档的约定。
2 代码风格
2.1 文件
[建议] JavaScript 文件使用无 BOM 的 UTF-8 编码。
解释:UTF-8 编码具有更广泛的适应性。BOM 在使用程序或工具处理文件时可能造成不必要的干扰。
[建议] 在文件结尾处,保留一个空行。
2.2 结构
[强制] 使用 4 个空格做为一个缩进层级,不允许使用 2 个空格 或 tab 字符。
[强制] switch 下的 case 和 default 必须增加一个缩进层级。
// good switch (variable) { case '1': // do... break; case '2': // do... break; default: // do... } // bad switch (variable) { case '1': // do... break; case '2': // do... break; default: // do... }
[强制] 二元运算符两侧必须有一个空格,一元运算符与操作对象之间不允许有空格。
var a = !arr.length; a++; a = b + c;
[强制] 用作代码块起始的左花括号 { 前必须有一个空格。
示例:
// good if (condition) { } while (condition) { } function funcName() { } // bad if (condition){ } while (condition){ } function funcName(){ }
[强制] if / else / for / while / function / switch / do / try / catch / finally 关键字后,必须有一个空格。
// good if (condition) { } while (condition) { } (function () { })(); // bad if(condition) { } while(condition) { } (function() { })();
[强制] 在对象创建时,属性中的 : 之后必须有空格,: 之前不允许有空格。
// good var obj = { a: 1, b: 2, c: 3 }; // bad var obj = { a : 1, b:2, c :3 };
[强制] 函数声明、具名函数表达式、函数调用中,函数名和 ( 之间不允许有空格。
// good function funcName() { } var funcName = function funcName() { }; funcName(); // bad function funcName () { } var funcName = function funcName () { }; funcName ();
[强制] , 和 ; 前不允许有空格。
// good callFunc(a, b); // bad callFunc(a , b) ;
[强制] 在函数调用、函数声明、括号表达式、属性访问、if / for / while / switch / catch 等语句中,() 和 [] 内紧贴括号部分不允许有空格。
// good callFunc(param1, param2, param3); save(this.list[this.indexes[i]]); needIncream && (variable += increament); if (num > list.length) { } while (len--) { } // bad callFunc( param1, param2, param3 ); save( this.list[ this.indexes[ i ] ] ); needIncreament && ( variable += increament ); if ( num > list.length ) { } while ( len-- ) { }
[强制] 单行声明的数组与对象,如果包含元素,{} 和 [] 内紧贴括号部分不允许包含空格。
解释:声明包含元素的数组与对象,只有当内部元素的形式较为简单时,才允许写在一行。元素复杂的情况,还是应该换行书写。
// good var arr1 = []; var arr2 = [1, 2, 3]; var obj1 = {}; var obj2 = {name: 'obj'}; var obj3 = { name: 'obj', age: 20, sex: 1 }; // bad var arr1 = [ ]; var arr2 = [ 1, 2, 3 ]; var obj1 = { }; var obj2 = { name: 'obj' }; var obj3 = {name: 'obj', age: 20, sex: 1};
[强制] 行尾不得有多余的空格。
[强制] 每个独立语句结束后必须换行。
[强制] 每行不得超过 120 个字符。
解释:超长的不可分割的代码允许例外,比如复杂的正则表达式。长字符串不在例外之列。
[强制] 运算符处换行时,运算符必须在新行的行首。
// good if (user.isAuthenticated() && user.isInRole('admin') && user.hasAuthority('add-admin') || user.hasAuthority('delete-admin') ) { // Code } var result = number1 + number2 + number3 + number4 + number5; // bad if (user.isAuthenticated() && user.isInRole('admin') && user.hasAuthority('add-admin') || user.hasAuthority('delete-admin')) { // Code } var result = number1 + number2 + number3 + number4 + number5;
[强制] 在函数声明、函数表达式、函数调用、对象创建、数组创建、for语句等场景中,不允许在 , 或 ; 前换行。
// good var obj = { a: 1, b: 2, c: 3 }; foo( aVeryVeryLongArgument, anotherVeryLongArgument, callback ); // bad var obj = { a: 1 , b: 2 , c: 3 }; foo( aVeryVeryLongArgument , anotherVeryLongArgument , callback );
[建议] 不同行为或逻辑的语句集,使用空行隔开,更易阅读。
// 仅为按逻辑换行的示例,不代表setStyle的最优实现 function setStyle(element, property, value) { if (element == null) { return; } element.style[property] = value; }
[建议] 在语句的行长度超过 120 时,根据逻辑条件合理缩进。
// 较复杂的逻辑条件组合,将每个条件独立一行,逻辑运算符放置在行首进行分隔,或将部分逻辑按逻辑组合进行分隔。 // 建议最终将右括号 ) 与左大括号 { 放在独立一行,保证与 if 内语句块能容易视觉辨识。 if (user.isAuthenticated() && user.isInRole('admin') && user.hasAuthority('add-admin') || user.hasAuthority('delete-admin') ) { // Code } // 按一定长度截断字符串,并使用 + 运算符进行连接。 // 分隔字符串尽量按语义进行,如不要在一个完整的名词中间断开。 // 特别的,对于HTML片段的拼接,通过缩进,保持和HTML相同的结构。 var html = '' // 此处用一个空字符串,以便整个HTML片段都在新行严格对齐 + '<article>' + '<h1>Title here</h1>' + '<p>This is a paragraph</p>' + '<footer>Complete</footer>' + '</article>'; // 也可使用数组来进行拼接,相对 + 更容易调整缩进。 var html = [ '<article>', '<h1>Title here</h1>', '<p>This is a paragraph</p>', '<footer>Complete</footer>', '</article>' ]; html = html.join(''); // 当参数过多时,将每个参数独立写在一行上,并将结束的右括号 ) 独立一行。 // 所有参数必须增加一个缩进。 foo( aVeryVeryLongArgument, anotherVeryLongArgument, callback ); // 也可以按逻辑对参数进行组合。 // 最经典的是baidu.format函数,调用时将参数分为“模板”和“数据”两块 baidu.format( dateFormatTemplate, year, month, date, hour, minute, second ); // 当函数调用时,如果有一个或以上参数跨越多行,应当每一个参数独立一行。 // 这通常出现在匿名函数或者对象初始化等作为参数时,如setTimeout函数等。 setTimeout( function () { alert('hello'); }, 200 ); order.data.read( 'id=' + me.model.id, function (data) { me.attchToModel(data.result); callback(); }, 300 ); // 链式调用较长时采用缩进进行调整。 $('#items') .find('.selected') .highlight() .end(); // 三元运算符由3部分组成,因此其换行应当根据每个部分的长度不同,形成不同的情况。 var result = thisIsAVeryVeryLongCondition ? resultA : resultB; var result = condition ? thisIsAVeryVeryLongResult : resultB; // 数组和对象初始化的混用,严格按照每个对象的 { 和结束 } 在独立一行的风格书写。 var array = [ { // ... }, { // ... } ];
[建议] 对于 if...else...、try...catch...finally 等语句,推荐使用在 } 号后添加一个换行 的风格,使代码层次结构更清晰,阅读性更好。
if (condition) { // some statements; } else { // some statements; } try { // some statements; } catch (ex) { // some statements; }
[强制] 不得省略语句结束的分号。
[强制] 在 if / else / for / do / while 语句中,即使只有一行,也不得省略块 {...}。
// good if (condition) { callFunc(); } // bad if (condition) callFunc(); if (condition) callFunc();
[强制] 函数定义结束不允许添加分号。
// good function funcName() { } // bad function funcName() { }; // 如果是函数表达式,分号是不允许省略的。 var funcName = function () { };
[强制] IIFE 必须在函数表达式外添加 (,非 IIFE 不得在函数表达式外添加 (。
解释:IIFE = Immediately-Invoked Function Expression.
额外的 ( 能够让代码在阅读的一开始就能判断函数是否立即被调用,进而明白接下来代码的用途。而不是一直拖到底部才恍然大悟。
// good var task = (function () { // Code return result; })(); var func = function () { }; // bad var task = function () { // Code return result; }(); var func = (function () { });
2.3 命名
下面提到的 Camel命名法:驼峰命名法;Pascal命名法:帕斯卡命名法,又叫大驼峰命名法。
[强制] 变量 使用 Camel命名法。
var loadingModules = {};
[强制] 常量 使用 全部字母大写,单词间下划线分隔 的命名方式。
var HTML_ENTITY = {};
[强制] 函数 使用 Camel命名法。
function stringFormat(source) { }
[强制] 函数的 参数 使用 Camel命名法。
function hear(theBells) { }
[强制] 类 使用 Pascal命名法。
function TextNode(options) { }
[强制] 类的 方法 / 属性 使用 Camel命名法。
function TextNode(value, engine) { this.value = value; this.engine = engine; } TextNode.prototype.clone = function () { return this; };
[强制] 枚举变量 使用 Pascal命名法,枚举的属性 使用 全部字母大写,单词间下划线分隔 的命名方式。
var TargetState = { READING: 1, READED: 2, APPLIED: 3, READY: 4 };
[强制] 命名空间 使用 Camel命名法。
equipments.heavyWeapons = {};
[强制] 由多个单词组成的缩写词,在命名中,根据当前命名法和出现的位置,所有字母的大小写与首字母的大小写保持一致。
function XMLParser() { } function insertHTML(element, html) { } var httpRequest = new HTTPRequest();
[强制] 类名 使用 名词。
function Engine(options) { }
[建议] 函数名 使用 动宾短语。
function getStyle(element) { }
[建议] boolean 类型的变量使用 is 或 has 开头。
var isReady = false; var hasMoreCommands = false;
[建议] Promise对象 用 动宾短语的进行时 表达。
var loadingData = ajax.get('url'); loadingData.then(callback);
2.4 注释
2.4.1 单行注释
[强制] 必须独占一行。// 后跟一个空格,缩进与下一行被注释说明的代码一致。
2.4.2 多行注释
[建议] 避免使用 /*...*/ 这样的多行注释。有多行注释内容时,使用多个单行注释。
2.4.3 文档化注释
[强制] 为了便于代码阅读和自文档化,以下内容必须包含以 /**...*/ 形式的块注释中。
解释:
[强制] 文档注释前必须空一行。
[建议] 自文档化的文档说明 what,而不是 how。
2.4.4 类型定义
[强制] 类型定义都是以{开始, 以}结束。
解释:常用类型如:{string}, {number}, {boolean}, {Object}, {Function}, {RegExp}, {Array}, {Date}。
类型不仅局限于内置的类型,也可以是自定义的类型。比如定义了一个类 Developer,就可以使用它来定义一个参数和返回值的类型。
[强制] 对于基本类型 {string}, {number}, {boolean},首字母必须小写。
类型定义 语法示例 解释 String {string} -- Number {number} -- Boolean {boolean} -- Object {Object} -- Function {Function} -- RegExp {RegExp} -- Array {Array} -- Date {Date} -- 单一类型集合 {Array.<string>} string 类型的数组 多类型 {(number|boolean)} 可能是 number 类型, 也可能是 boolean 类型 允许为null {?number} 可能是 number, 也可能是 null 不允许为null {!Object} Object 类型, 但不是 null Function类型 {function(number, boolean)} 函数, 形参类型 Function带返回值 {function(number, boolean):string} 函数, 形参, 返回值类型 参数可选 @param {string=} name 可选参数, =为类型后缀 可变参数 @param {...number} args 变长参数, ...为类型前缀 任意类型 {*} 任意类型 可选任意类型 @param {*=} name 可选参数,类型不限 可变任意类型 @param {...*} args 变长参数,类型不限 2.4.5 文件注释
[强制] 文件顶部必须包含文件注释,用 @file 标识文件说明。
/** * @file Describe the file */
[建议] 文件注释中可以用 @author 标识开发者信息。
解释:
开发者信息能够体现开发人员对文件的贡献,并且能够让遇到问题或希望了解相关信息的人找到维护人。通常情况文件在被创建时标识的是创建者。随着项目的进展,越来越多的人加入,参与这个文件的开发,新的作者应该被加入 @author 标识。
@author 标识具有多人时,原则是按照 责任 进行排序。通常的说就是如果有问题,就是找第一个人应该比找第二个人有效。比如文件的创建者由于各种原因,模块移交给了其他人或其他团队,后来因为新增需求,其他人在新增代码时,添加 @author 标识应该把自己的名字添加在创建人的前面。
@author 中的名字不允许被删除。任何劳动成果都应该被尊重。
业务项目中,一个文件可能被多人频繁修改,并且每个人的维护时间都可能不会很长,不建议为文件增加 @author 标识。通过版本控制系统追踪变更,按业务逻辑单元确定模块的维护责任人,通过文档与wiki跟踪和查询,是更好的责任管理方式。
对于业务逻辑无关的技术型基础项目,特别是开源的公共项目,应使用 @author 标识。
/** * @file Describe the file * @author author-name(mail-name@domain.com) * author-name2(mail-name2@domain.com) */
2.4.6 命名空间注释
[建议] 命名空间使用 @namespace 标识。
/** * @namespace */ var util = {};
2.4.7 类注释
[建议] 使用 @class 标记类或构造函数。
解释:对于使用对象 constructor 属性来定义的构造函数,可以使用 @constructor 来标记。
/** * 描述 * * @class */ function Developer() { // constructor body }
[建议] 使用 @extends 标记类的继承信息。
/** * 描述 * * @class * @extends Developer */ function Fronteer() { Developer.call(this); // constructor body } util.inherits(Fronteer, Developer);
[强制] 使用包装方式扩展类成员时, 必须通过 @lends 进行重新指向。
解释:没有 @lends 标记将无法为该类生成包含扩展类成员的文档。
/** * 类描述 * * @class * @extends Developer */ function Fronteer() { Developer.call(this); // constructor body } util.extend( Fronteer.prototype, /** @lends Fronteer.prototype */{ _getLevel: function () { // TODO } } );
[强制] 类的属性或方法等成员信息使用 @public / @protected / @private 中的任意一个,指明可访问性。
解释:生成的文档中将有可访问性的标记,避免用户直接使用非 public 的属性或方法。
/** * 类描述 * * @class * @extends Developer */ var Fronteer = function () { Developer.call(this); /** * 属性描述 * * @type {string} * @private */ this._level = 'T12'; // constructor body }; util.inherits(Fronteer, Developer); /** * 方法描述 * * @private * @return {string} 返回值描述 */ Fronteer.prototype._getLevel = function () { };
2.4.8 函数/方法注释
[强制] 函数/方法注释必须包含函数说明,有参数和返回值时必须使用注释标识。
[强制] 参数和返回值注释必须包含类型信息和说明。
[建议] 当函数是内部函数,外部不可访问时,可以使用 @inner 标识。
/** * 函数描述 * * @param {string} p1 参数1的说明 * @param {string} p2 参数2的说明,比较长 * 那就换行了. * @param {number=} p3 参数3的说明(可选) * @return {Object} 返回值描述 */ function foo(p1, p2, p3) { var p3 = p3 || 10; return { p1: p1, p2: p2, p3: p3 }; }
[强制] 对 Object 中各项的描述, 必须使用 @param 标识。
/** * 函数描述 * * @param {Object} option 参数描述 * @param {string} option.url option项描述 * @param {string=} option.method option项描述,可选参数 */ function foo(option) { // TODO }
[建议] 重写父类方法时, 应当添加 @override 标识。如果重写的形参个数、类型、顺序和返回值类型均未发生变化,可省略 @param、@return,仅用 @override 标识,否则仍应作完整注释。
解释:简而言之,当子类重写的方法能直接套用父类的方法注释时可省略对参数与返回值的注释。
2.4.9 事件注释
[强制] 必须使用 @event 标识事件,事件参数的标识与方法描述的参数标识相同。
/** * 值变更时触发 * * @event * @param {Object} e e描述 * @param {string} e.before before描述 * @param {string} e.after after描述 */ onchange: function (e) { }
[强制] 在会广播事件的函数前使用 @fires 标识广播的事件,在广播事件代码前使用 @event 标识事件。
[建议] 对于事件对象的注释,使用 @param 标识,生成文档时可读性更好。
/** * 点击处理 * * @fires Select#change * @private */ Select.prototype.clickHandler = function () { /** * 值变更时触发 * * @event Select#change * @param {Object} e e描述 * @param {string} e.before before描述 * @param {string} e.after after描述 */ this.fire( 'change', { before: 'foo', after: 'bar' } ); };
2.4.10 常量注释
[强制] 常量必须使用 @const 标记,并包含说明和类型信息。
/** * 常量说明 * * @const * @type {string} */ var REQUEST_URL = 'myurl.do';
2.4.11 复杂类型注释
[建议] 对于类型未定义的复杂结构的注释,可以使用 @typedef 标识来定义。
// `namespaceA~` 可以换成其它 namepaths 前缀,目的是为了生成文档中能显示 `@typedef` 定义的类型和链接。 /** * 服务器 * * @typedef {Object} namespaceA~Server * @property {string} host 主机 * @property {number} port 端口 */ /** * 服务器列表 * * @type {Array.<namespaceA~Server>} */ var servers = [ { host: '1.2.3.4', port: 8080 }, { host: '1.2.3.5', port: 8081 } ];
2.4.12 AMD 模块注释
[强制] AMD 模块使用 @module 或 @exports 标识。
解释:@exports 与 @module 都可以用来标识模块,区别在于 @module 可以省略模块名称。而只使用 @exports 时在 namepaths 中可以省略 module: 前缀。
define( function (require) { /** * foo description * * @exports Foo */ var foo = { // TODO }; /** * baz description * * @return {boolean} return description */ foo.baz = function () { // TODO }; return foo; } );
也可以在 exports 变量前使用 @module 标识:
define( function (require) { /** * module description. * * @module foo */ var exports = {}; /** * bar description * */ exports.bar = function () { // TODO }; return exports; } );
如果直接使用 factory 的 exports 参数,还可以:
/** * module description. * * @module */ define( function (require, exports) { /** * bar description * */ exports.bar = function () { // TODO }; return exports; } );
[强制] 对于已使用 @module 标识为 AMD模块 的引用,在 namepaths 中必须增加 module: 作前缀。
解释:namepaths 没有 module: 前缀时,生成的文档中将无法正确生成链接。
/** * 点击处理 * * @fires module:Select#change * @private */ Select.prototype.clickHandler = function () { /** * 值变更时触发 * * @event module:Select#change * @param {Object} e e描述 * @param {string} e.before before描述 * @param {string} e.after after描述 */ this.fire( 'change', { before: 'foo', after: 'bar' } ); };
[建议] 对于类定义的模块,可以使用 @alias 标识构建函数。
/** * A module representing a jacket. * @module jacket */ define( function () { /** * @class * @alias module:jacket */ var Jacket = function () { }; return Jacket; } );
[建议] 多模块定义时,可以使用 @exports 标识各个模块。
// one module define('html/utils', /** * Utility functions to ease working with DOM elements. * @exports html/utils */ function () { var exports = { }; return exports; } ); // another module define('tag', /** @exports tag */ function () { var exports = { }; return exports; } );
[建议] 对于 exports 为 Object 的模块,可以使用@namespace标识。
解释:使用 @namespace 而不是 @module 或 @exports 时,对模块的引用可以省略 module: 前缀。
[建议] 对于 exports 为类名的模块,使用 @class 和 @exports 标识。
// 只使用 @class Bar 时,类方法和属性都必须增加 @name Bar#methodName 来标识,与 @exports 配合可以免除这一麻烦,并且在引用时可以省去 module: 前缀。 // 另外需要注意类名需要使用 var 定义的方式。 /** * Bar description * * @see foo * @exports Bar * @class */ var Bar = function () { // TODO }; /** * baz description * * @return {(string|Array)} return description */ Bar.prototype.baz = function () { // TODO };
2.4.13 细节注释
对于内部实现、不容易理解的逻辑说明、摘要信息等,我们可能需要编写细节注释。
[建议] 细节注释遵循单行注释的格式。说明必须换行时,每行是一个单行注释的起始。
function foo(p1, p2, opt_p3) { // 这里对具体内部逻辑进行说明 // 说明太长需要换行 for (...) { .... } }
[强制] 有时我们会使用一些特殊标记进行说明。特殊标记必须使用单行注释的形式。下面列举了一些常用标记:
解释:
3 语言特性
3.1 变量
[强制] 变量在使用前必须通过 var 定义。
解释:不通过 var 定义变量将导致变量污染全局环境。
// good var name = 'MyName'; // bad name = 'MyName';
[强制] 每个 var 只能声明一个变量。
解释:一个 var 声明多个变量,容易导致较长的行长度,并且在修改时容易造成逗号和分号的混淆。
// good var hangModules = []; var missModules = []; var visited = {}; // bad var hangModules = [], missModules = [], visited = {};
[强制] 变量必须 即用即声明,不得在函数或其它形式的代码块起始位置统一声明所有变量。
解释: 变量声明与使用的距离越远,出现的跨度越大,代码的阅读与维护成本越高。虽然JavaScript的变量是函数作用域,还是应该根据编程中的意图,缩小变量出现的距离空间。
// good function kv2List(source) { var list = []; for (var key in source) { if (source.hasOwnProperty(key)) { var item = { k: key, v: source[key] }; list.push(item); } } return list; } // bad function kv2List(source) { var list = []; var key; var item; for (key in source) { if (source.hasOwnProperty(key)) { item = { k: key, v: source[key] }; list.push(item); } } return list; }
3.2 条件
[强制] 在 Equality Expression 中使用类型严格的 ===。仅当判断 null 或 undefined 时,允许使用 == null。
解释:使用 === 可以避免等于判断中隐式的类型转换。
// good if (age === 30) { // ...... } // bad if (age == 30) { // ...... }
[建议] 尽可能使用简洁的表达式。
// 字符串为空 // good if (!name) { // ...... } // bad if (name === '') { // ...... } // 字符串非空 // good if (name) { // ...... } // bad if (name !== '') { // ...... } // 数组非空 // good if (collection.length) { // ...... } // bad if (collection.length > 0) { // ...... } // 布尔不成立 // good if (!notTrue) { // ...... } // bad if (notTrue === false) { // ...... } // null 或 undefined // good if (noValue == null) { // ...... } // bad if (noValue === null || typeof noValue === 'undefined') { // ...... }
[建议] 按执行频率排列分支的顺序。
解释:按执行频率排列分支的顺序好处是:
[建议] 对于相同变量或表达式的多值条件,用 switch 代替 if。
// good switch (typeof variable) { case 'object': // ...... break; case 'number': case 'boolean': case 'string': // ...... break; } // bad var type = typeof variable; if (type === 'object') { // ...... } else if (type === 'number' || type === 'boolean' || type === 'string') { // ...... }
[建议] 如果函数或全局中的 else 块后没有任何语句,可以删除 else。
示例:
// good function getName() { if (name) { return name; } return 'unnamed'; } // bad function getName() { if (name) { return name; } else { return 'unnamed'; } }
3.3 循环
[建议] 不要在循环体中包含函数表达式,事先将函数提取到循环体外。
解释:循环体中的函数表达式,运行过程中会生成循环次数个函数对象。
// good function clicker() { // ...... } for (var i = 0, len = elements.length; i < len; i++) { var element = elements[i]; addListener(element, 'click', clicker); } // bad for (var i = 0, len = elements.length; i < len; i++) { var element = elements[i]; addListener(element, 'click', function () {}); }
[建议] 对循环内多次使用的不变值,在循环外用变量缓存。
// good var width = wrap.offsetWidth + 'px'; for (var i = 0, len = elements.length; i < len; i++) { var element = elements[i]; element.style.width = width; // ...... } // bad for (var i = 0, len = elements.length; i < len; i++) { var element = elements[i]; element.style.width = wrap.offsetWidth + 'px'; // ...... }
[建议] 对有序集合进行遍历时,缓存 length。
解释:虽然现代浏览器都对数组长度进行了缓存,但对于一些宿主对象和老旧浏览器的数组对象,在每次 length 访问时会动态计算元素个数,此时缓存 length 能有效提高程序性能。
for (var i = 0, len = elements.length; i < len; i++) { var element = elements[i]; // ...... }
[建议] 对有序集合进行顺序无关的遍历时,使用逆序遍历。
解释:逆序遍历可以节省变量,代码比较优化。
var len = elements.length; while (len--) { var element = elements[len]; // ...... }
3.4 类型
3.4.1 类型检测
[建议] 类型检测优先使用 typeof。对象类型检测使用 instanceof。null 或 undefined 的检测使用 == null。
// string typeof variable === 'string' // number typeof variable === 'number' // boolean typeof variable === 'boolean' // Function typeof variable === 'function' // Object typeof variable === 'object' // RegExp variable instanceof RegExp // Array variable instanceof Array // null variable === null // null or undefined variable == null // undefined typeof variable === 'undefined'
3.4.2 类型转换
[建议] 转换成 string 时,使用 + ''。
// good num + ''; // bad new String(num); num.toString(); String(num);
[建议] 转换成 number 时,通常使用 +。
// good +str; // bad Number(str);
[建议] string 转换成 number,要转换的字符串结尾包含非数字并期望忽略时,使用 parseInt。
var width = '200px'; parseInt(width, 10);
[强制] 使用 parseInt 时,必须指定进制。
// good parseInt(str, 10); // bad parseInt(str);
[建议] 转换成 boolean 时,使用 !!。
var num = 3.14; !!num;
[建议] number 去除小数点,使用 Math.floor / Math.round / Math.ceil,不使用 parseInt。
// good var num = 3.14; Math.ceil(num); // bad var num = 3.14; parseInt(num, 10);
3.5 字符串
[强制] 字符串开头和结束使用单引号 '。
解释:
var str = '我是一个字符串'; var html = '<div class="cls">拼接HTML可以省去双引号转义</div>';
[建议] 使用 数组 或 + 拼接字符串。
解释:
示例:
// 使用数组拼接字符串 var str = [ // 推荐换行开始并缩进开始第一个字符串, 对齐代码, 方便阅读. '<ul>', '<li>第一项</li>', '<li>第二项</li>', '</ul>' ].join(''); // 使用 + 拼接字符串 var str2 = '' // 建议第一个为空字符串, 第二个换行开始并缩进开始, 对齐代码, 方便阅读 + '<ul>', + '<li>第一项</li>', + '<li>第二项</li>', + '</ul>';
[建议] 复杂的数据到视图字符串的转换过程,选用一种模板引擎。
解释:使用模板引擎有如下好处:
3.6 对象
[强制] 使用对象字面量 {} 创建新 Object。
// good var obj = {}; // bad var obj = new Object();
[强制] 对象创建时,如果一个对象的所有 属性 均可以不添加引号,则所有 属性 不得添加引号。
var info = { name: 'someone', age: 28 };
[强制] 对象创建时,如果任何一个 属性 需要添加引号,则所有 属性 必须添加 '。
解释:如果属性不符合 Identifier 和 NumberLiteral 的形式,就需要以 StringLiteral 的形式提供。
// good var info = { 'name': 'someone', 'age': 28, 'more-info': '...' }; // bad var info = { name: 'someone', age: 28, 'more-info': '...' };
[强制] 不允许修改和扩展任何原生对象和宿主对象的原型。
// 以下行为绝对禁止 String.prototype.trim = function () { };
[建议] 属性访问时,尽量使用 .。
解释:属性名符合 Identifier 的要求,就可以通过 . 来访问,否则就只能通过 [expr] 方式访问。
通常在 JavaScript 中声明的对象,属性命名是使用 Camel 命名法,用 . 来访问更清晰简洁。部分特殊的属性(比如来自后端的JSON),可能采用不寻常的命名方式,可以通过 [expr] 方式访问。
info.age; info['more-info'];
[建议] for in 遍历对象时, 使用 hasOwnProperty 过滤掉原型中的属性。
var newInfo = {}; for (var key in info) { if (info.hasOwnProperty(key)) { newInfo[key] = info[key]; } }
3.7 数组
[强制] 使用数组字面量 [] 创建新数组,除非想要创建的是指定长度的数组。
// good var arr = []; // bad var arr = new Array();
[强制] 遍历数组不使用 for in。
解释:数组对象可能存在数字以外的属性, 这种情况下 for in 不会得到正确结果.
var arr = ['a', 'b', 'c']; arr.other = 'other things'; // 这里仅作演示, 实际中应使用Object类型 // 正确的遍历方式 for (var i = 0, len = arr.length; i < len; i++) { console.log(i); } // 错误的遍历方式 for (i in arr) { console.log(i); }
[建议] 不因为性能的原因自己实现数组排序功能,尽量使用数组的 sort 方法。
解释:自己实现的常规排序算法,在性能上并不优于数组默认的 sort 方法。以下两种场景可以自己实现排序:
[建议] 清空数组使用 .length = 0。
3.8 函数
3.8.1 函数长度
[建议] 一个函数的长度控制在 50 行以内。
解释:将过多的逻辑单元混在一个大函数中,易导致难以维护。一个清晰易懂的函数应该完成单一的逻辑单元。复杂的操作应进一步抽取,通过函数的调用来体现流程。
特定算法等不可分割的逻辑允许例外。
function syncViewStateOnUserAction() { if (x.checked) { y.checked = true; z.value = ''; } else { y.checked = false; } if (!a.value) { warning.innerText = 'Please enter it'; submitButton.disabled = true; } else { warning.innerText = ''; submitButton.disabled = false; } } // 直接阅读该函数会难以明确其主线逻辑,因此下方是一种更合理的表达方式: function syncViewStateOnUserAction() { syncXStateToView(); checkAAvailability(); } function syncXStateToView() { if (x.checked) { y.checked = true; z.value = ''; } else { y.checked = false; } } function checkAAvailability() { if (!a.value) { displayWarningForAMissing(); } else { clearWarnignForA(); } }
3.8.2 参数设计
[建议] 一个函数的参数控制在 6 个以内。
解释:
除去不定长参数以外,函数具备不同逻辑意义的参数建议控制在 6 个以内,过多参数会导致维护难度增大。
某些情况下,如使用 AMD Loader 的 require 加载多个模块时,其 callback 可能会存在较多参数,因此对函数参数的个数不做强制限制。
[建议] 通过 options 参数传递非数据输入型参数。
解释:有些函数的参数并不是作为算法的输入,而是对算法的某些分支条件判断之用,此类参数建议通过一个 options 参数传递。
如下函数:
/** * 移除某个元素 * * @param {Node} element 需要移除的元素 * @param {boolean} removeEventListeners 是否同时将所有注册在元素上的事件移除 */ function removeElement(element, removeEventListeners) { element.parent.removeChild(element); if (removeEventListeners) { element.clearEventListeners(); } }
可以转换为下面的签名:
/** * 移除某个元素 * * @param {Node} element 需要移除的元素 * @param {Object} options 相关的逻辑配置 * @param {boolean} options.removeEventListeners 是否同时将所有注册在元素上的事件移除 */ function removeElement(element, options) { element.parent.removeChild(element); if (options.removeEventListeners) { element.clearEventListeners(); } }
这种模式有几个显著的优势:
3.8.3 闭包
[建议] 在适当的时候将闭包内大对象置为 null。
解释:
在 JavaScript 中,无需特别的关键词就可以使用闭包,一个函数可以任意访问在其定义的作用域外的变量。需要注意的是,函数的作用域是静态的,即在定义时决定,与调用的时机和方式没有任何关系。
闭包会阻止一些变量的垃圾回收,对于较老旧的JavaScript引擎,可能导致外部所有变量均无法回收。
首先一个较为明确的结论是,以下内容会影响到闭包内变量的回收:
Chakra、V8 和 SpiderMonkey 将受以上因素的影响,表现出不尽相同又较为相似的回收策略,而JScript.dll和Carakan则完全没有这方面的优化,会完整保留整个 LexicalEnvironment 中的所有变量绑定,造成一定的内存消耗。
由于对闭包内变量有回收优化策略的 Chakra、V8 和 SpiderMonkey 引擎的行为较为相似,因此可以总结如下,当返回一个函数 fn 时:
对于Chakra引擎,暂无法得知是按 V8 的模式还是按 SpiderMonkey 的模式进行。
如果有 非常庞大 的对象,且预计会在 老旧的引擎 中执行,则使用闭包时,注意将闭包不需要的对象置为空引用。
[建议] 使用 IIFE 避免 Lift 效应。
解释:在引用函数外部变量时,函数执行时外部变量的值由运行时决定而非定义时,最典型的场景如下:
var tasks = []; for (var i = 0; i < 5; i++) { tasks[tasks.length] = function () { console.log('Current cursor is at ' + i); }; } var len = tasks.length; while (len--) { tasks[len](); }
以上代码对 tasks 中的函数的执行均会输出 Current cursor is at 5,往往不符合预期。
此现象称为 Lift 效应 。解决的方式是通过额外加上一层闭包函数,将需要的外部变量作为参数传递来解除变量的绑定关系:
var tasks = []; for (var i = 0; i < 5; i++) { // 注意有一层额外的闭包 tasks[tasks.length] = (function (i) { return function () { console.log('Current cursor is at ' + i); }; })(i); } var len = tasks.length; while (len--) { tasks[len](); }
3.8.4 空函数
[建议] 空函数不使用 new Function() 的形式。
var emptyFunction = function () {};
[建议] 对于性能有高要求的场合,建议存在一个空函数的常量,供多处使用共享。
var EMPTY_FUNCTION = function () {}; function MyClass() { } MyClass.prototype.abstractMethod = EMPTY_FUNCTION; MyClass.prototype.hooks.before = EMPTY_FUNCTION; MyClass.prototype.hooks.after = EMPTY_FUNCTION;
3.9 面向对象
[强制] 类的继承方案,实现时需要修正 constructor。
解释:通常使用其他 library 的类继承方案都会进行 constructor 修正。如果是自己实现的类继承方案,需要进行 constructor 修正。
/** * 构建类之间的继承关系 * * @param {Function} subClass 子类函数 * @param {Function} superClass 父类函数 */ function inherits(subClass, superClass) { var F = new Function(); F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; }
[建议] 声明类时,保证 constructor 的正确性。
function Animal(name) { this.name = name; } // 直接prototype等于对象时,需要修正constructor Animal.prototype = { constructor: Animal, jump: function () { alert('animal ' + this.name + ' jump'); } }; // 这种方式扩展prototype则无需理会constructor Animal.prototype.jump = function () { alert('animal ' + this.name + ' jump'); };
[建议] 属性在构造函数中声明,方法在原型中声明。
解释: 原型对象的成员被所有实例共享,能节约内存占用。所以编码时我们应该遵守这样的原则:原型对象包含程序不会修改的成员,如方法函数或配置项。
function TextNode(value, engine) { this.value = value; this.engine = engine; } TextNode.prototype.clone = function () { return this; };
[强制] 自定义事件的 事件名 必须全小写。
解释:在 JavaScript 广泛应用的浏览器环境,绝大多数 DOM 事件名称都是全小写的。为了遵循大多数 JavaScript 开发者的习惯,在设计自定义事件时,事件名也应该全小写。
[强制] 自定义事件只能有一个 event 参数。如果事件需要传递较多信息,应仔细设计事件对象。
解释:一个事件对象的好处有:
[建议] 设计自定义事件时,应考虑禁止默认行为。
解释:常见禁止默认行为的方式有两种:
3.10 动态特性
3.10.1 eval
[强制] 避免使用直接 eval 函数。
解释:直接 eval,指的是以函数方式调用 eval 的调用方法。直接 eval 调用执行代码的作用域为本地作用域,应当避免。
如果有特殊情况需要使用直接 eval,需在代码中用详细的注释说明为何必须使用直接 eval,不能使用其它动态执行代码的方式,同时需要其他资深工程师进行 Code Review。
[建议] 尽量避免使用 eval 函数。
3.10.2 动态执行代码
[建议] 使用 new Function 执行动态代码。
解释:通过 new Function 生成的函数作用域是全局使用域,不会影响当当前的本地作用域。如果有动态代码执行的需求,建议使用 new Function。
var handler = new Function('x', 'y', 'return x + y;'); var result = handler($('#x').val(), $('#y').val());
3.10.3 with
[建议] 尽量不要使用 with。
解释:使用 with 可能会增加代码的复杂度,不利于阅读和管理;也会对性能有影响。大多数使用 with 的场景都能使用其他方式较好的替代。所以,尽量不要使用 with。
3.10.4 delete
[建议] 减少 delete 的使用。
解释:如果没有特别的需求,减少或避免使用delete。delete的使用会破坏部分 JavaScript 引擎的性能优化。
[建议] 处理 delete 可能产生的异常。
解释:
对于有被遍历需求,且值 null 被认为具有业务逻辑意义的值的对象,移除某个属性必须使用 delete 操作。
在严格模式或IE下使用 delete 时,不能被删除的属性会抛出异常,因此在不确定属性是否可以删除的情况下,建议添加 try-catch 块。
try { delete o.x; } catch (deleteError) { o.x = null; }
3.10.5 对象属性
[建议] 避免修改外部传入的对象。
解释:
JavaScript 因其脚本语言的动态特性,当一个对象未被 seal 或 freeze 时,可以任意添加、删除、修改属性值。
但是随意地对 非自身控制的对象 进行修改,很容易造成代码在不可预知的情况下出现问题。因此,设计良好的组件、函数应该避免对外部传入的对象的修改。
下面代码的 selectNode 方法修改了由外部传入的 datasource 对象。如果 datasource 用在其它场合(如另一个 Tree 实例)下,会造成状态的混乱。
function Tree(datasource) { this.datasource = datasource; } Tree.prototype.selectNode = function (id) { // 从datasource中找出节点对象 var node = this.findNode(id); if (node) { node.selected = true; this.flushView(); } };
对于此类场景,需要使用额外的对象来维护,使用由自身控制,不与外部产生任何交互的 selectedNodeIndex 对象来维护节点的选中状态,不对 datasource 作任何修改。
function Tree(datasource) { this.datasource = datasource; this.selectedNodeIndex = {}; } Tree.prototype.selectNode = function (id) { // 从datasource中找出节点对象 var node = this.findNode(id); if (node) { this.selectedNodeIndex[id] = true; this.flushView(); } };
除此之外,也可以通过 deepClone 等手段将自身维护的对象与外部传入的分离,保证不会相互影响。
[建议] 具备强类型的设计。
解释:
4 浏览器环境
4.1 模块化
4.1.1 AMD
[强制] 使用 AMD 作为模块定义。
解释:
AMD 作为由社区认可的模块定义形式,提供多种重载提供灵活的使用方式,并且绝大多数优秀的 Library 都支持 AMD,适合作为规范。
目前,比较成熟的 AMD Loader 有:
[强制] 模块 id 必须符合标准。
解释:模块 id 必须符合以下约束条件:
4.1.2 define
[建议] 定义模块时不要指明 id 和 dependencies。
解释:
在 AMD 的设计思想里,模块名称是和所在路径相关的,匿名的模块更利于封包和迁移。模块依赖应在模块定义内部通过 local require 引用。
所以,推荐使用 define(factory) 的形式进行模块定义。
define( function (require) { } );
[建议] 使用 return 来返回模块定义。
解释:使用 return 可以减少 factory 接收的参数(不需要接收 exports 和 module),在没有 AMD Loader 的场景下也更容易进行简单的处理来伪造一个 Loader。
define( function (require) { var exports = {}; // ... return exports; } );
4.1.3 require
[强制] 全局运行环境中,require 必须以 async require 形式调用。
解释:模块的加载过程是异步的,同步调用并无法保证得到正确的结果。
// good require(['foo'], function (foo) { }); // bad var foo = require('foo');
[强制] 模块定义中只允许使用 local require,不允许使用 global require。
解释:
[强制] Package在实现时,内部模块的 require 必须使用 relative id。
解释:对于任何可能通过 发布-引入 的形式复用的第三方库、框架、包,开发者所定义的名称不代表使用者使用的名称。因此不要基于任何名称的假设。在实现源码中,require 自身的其它模块时使用 relative id。
define( function (require) { var util = require('./util'); } );
[建议] 不会被调用的依赖模块,在 factory 开始处统一 require。
解释:有些模块是依赖的模块,但不会在模块实现中被直接调用,最为典型的是 css / js / tpl 等 Plugin 所引入的外部内容。此类内容建议放在模块定义最开始处统一引用。
define( function (require) { require('css!foo.css'); require('tpl!bar.tpl.html'); // ... } );
4.2 DOM
4.2.1 元素获取
[建议] 对于单个元素,尽可能使用 document.getElementById 获取,避免使用document.all。
[建议] 对于多个元素的集合,尽可能使用 context.getElementsByTagName 获取。其中 context 可以为 document 或其他元素。指定 tagName 参数为 * 可以获得所有子元素。
[建议] 遍历元素集合时,尽量缓存集合长度。如需多次操作同一集合,则应将集合转为数组。
解释:原生获取元素集合的结果并不直接引用 DOM 元素,而是对索引进行读取,所以 DOM 结构的改变会实时反映到结果中。
<div></div> <span></span> <script> var elements = document.getElementsByTagName('*'); // 显示为 DIV alert(elements[0].tagName); var div = elements[0]; var p = document.createElement('p'); document.body.insertBefore(p, div); // 显示为 P alert(elements[0].tagName); </script>
[建议] 获取元素的直接子元素时使用 children。避免使用childNodes,除非预期是需要包含文本、注释和属性类型的节点。
4.2.2 样式获取
[建议] 获取元素实际样式信息时,应使用 getComputedStyle 或 currentStyle。
解释:通过 style 只能获得内联定义或通过 JavaScript 直接设置的样式。通过 CSS class 设置的元素样式无法直接通过 style 获取。
4.2.3 样式设置
[建议] 尽可能通过为元素添加预定义的 className 来改变元素样式,避免直接操作 style 设置。
[强制] 通过 style 对象设置元素样式时,对于带单位非 0 值的属性,不允许省略单位。
解释:除了 IE,标准浏览器会忽略不规范的属性值,导致兼容性问题。
4.2.4 DOM 操作
[建议] 操作 DOM 时,尽量减少页面 reflow。
解释:页面 reflow 是非常耗时的行为,非常容易导致性能瓶颈。下面一些场景会触发浏览器的reflow:
[建议] 尽量减少 DOM 操作。
解释:DOM 操作也是非常耗时的一种操作,减少 DOM 操作有助于提高性能。举一个简单的例子,构建一个列表。我们可以用两种方式:
第一种方法看起来比较标准,但是每次循环都会对 DOM 进行操作,性能极低。在这里推荐使用第二种方法。
4.2.5 DOM 事件
[建议] 优先使用 addEventListener / attachEvent 绑定事件,避免直接在 HTML 属性中或 DOM 的 expando 属性绑定事件处理。
解释:expando 属性绑定事件容易导致互相覆盖。
[建议] 使用 addEventListener 时第三个参数使用 false。
解释:标准浏览器中的 addEventListener 可以通过第三个参数指定两种时间触发模型:冒泡和捕获。而 IE 的 attachEvent 仅支持冒泡的事件触发。所以为了保持一致性,通常 addEventListener 的第三个参数都为 false。
[建议] 在没有事件自动管理的框架支持下,应持有监听器函数的引用,在适当时候(元素释放、页面卸载等)移除添加的监听器。
作者:前端切图小弟,个人运营的公众号:前端读者(fe_duzhe)
HTML(HyperTextMark-upLanguage)即超文本标记语言或超文本链接标示语言,是WWW的描述语言。
HTML文档的结构
2.页面背景色或背景图像
Hello World!
</body>
(网页背景图像)
Hello World!
</body>
(网页背景色彩)
3.文本相关标签
标题标签<h1>-<h6>,<font>标签。
段落标签<p>,换行标签<br>。
<h#> ... </h#>,#=1, 2, 3, 4, 5, 6 (说明:<h1>到<h6>字体大小依次递减)
<sub>下标文字,<sup>上标文字,<del>删除线。
段落标签<p>,换行标签<br>。
<HR> 标签用于在页面上绘制水平线。
图像的基本语法:<img src=“images/adv_2.jpg” width=“300” height=“150” alt=“在线报名” >
要链接到同一目录 (C:\HTML) 下的页面,可编写 <A HREF = “Doc1.htm”> 或 <A HREF = “C:\html\Doc2.htm”>
链接到本页面:
<a href=“http://www.it.com”>
<img src=“images/adv_2.jpg” border=“0” width="300"height="150">
</a>
<marquee scrolldelay=“100” direction=“up”>
滚动文字或图像
</marquee>
说明:scrolldelay:表示滚动延迟时间,默认值为90;direction:表示滚动的方向,默认为从右向左。
目标:掌握列表的用法
使用表格的基本结构实现简单表格
使用表格相关标签实现跨行、跨列的复杂表格
会使用表单的基本结构制作表单页面
会使用各种表单元素实现注册页面
能理解post和get两种提交方式的区别
格式: <ul type=“”>
type属性设置标号的类型,值可以取:
1 disc :实心圆点
2 circle :空心圆点
3 square :实心方块
无序列表
格式:<ol type=“” start=“”>
type设置标号的类型,值可以取:
1 1:显示数字
2 A:显示大写字母
3 a:显示小写字母
4 I:显示大写罗马数字
5 i:显示小写罗马数字
有序列表
嵌套列表
门户网站应用表格
<table>...</ table >定义表格
创建表格
表格表现
域名数量报表的创建
域名数量报表
1.跨多列的表格
2.跨多行的表格
3.如何创建跨行跨列的表格
品牌商城表的创建
width用来设置表格的宽度;height用来设置表格的高度;border用来设置表格边框尺寸大小;bordercolor用来设置表格边框颜色。
品牌商城表
背景:background属性用来设置表格的背景图片;bgcolor属性用来设置表格、行、列的背景色。
对其方式:align属性用来设置表格、行、列的对齐方式。
<input type=“text” value="张三" size="20">
文本框的建设
文本框
<input type=“password” value=“123456” size=“22”>
密码框的建设
密码框,22个字符宽度
<input type="radio" value="男" checked="checked">
单选按钮的建设
单选按钮框
<input type=“checkbox” name="cb2" value="talk">
<textarea name=“textarea” cols=“40” rows=“6”>内容</textarea>
<input type="reset" name=“reset" value=" 重填 ">
其他表单元素:<input type=“hidden”/>表单隐藏域
<input type=“image”/>表单图片按钮
<input type=“file”/>文件浏览
<label>标签可以绑定某个表单元素,用于扩展可以相应点击等事件的区域
如:当点击复选框右边的提示文字时,该复选框也可被选中。
内容有限,关于css,div和网页布局的部分就下次在和大家分享吧!
tyle 修饰
width 宽度
height 高度
title 想说明的
text-align 水平对齐方式
center 居中 left 居左 right 居右
line-height 垂直对齐方式/行高 当行高等于高度时候垂直居中
background 背景
image 引入背景图片(url)
background-position: 背景定位(x轴,y轴;)
background-repeat 背景平铺
:no-repeat;不平铺 repeat-x;水平平铺 repeat-y;垂直平铺
background:url() repeat left center #00;
顺序:背景图片 重复 定位 颜色
top/right/bottom/left/center 方向英文:上、右、下、左,中
color 颜色
font 文字
font-family 字体
font-size 字号
font-weight:normal 正常 :bold 加粗
font-style: normal;取消倾斜 :italic;斜体
font:italic bold 24px/24px '楷体';
顺序:是否斜体 是否粗体 字体大小/行高 字体
文本修饰属性:
text-decoration:
overline 顶划线
underline 下划线
line-through 中划线/删除线
none 无/取消下划线
display 转化显示模式 元素转化
block 块
inline 行内
inline-block 行内块
省略号
white-space:nowrap 强制不换行
overflow:hidden 溢出隐藏
text-overflow:ellipsis 省略号
font-family:‘微软雅黑’ 让省略号在下面
必须给宽度
---------------------------------------------------------------------------------------
伪类
a:link 设置未访问时候的颜色 点击后变成a的正常颜色
a:visited 设置访问过后颜色
a:hover 当鼠标放上去会变颜色
a:active 鼠标点击变颜色
顺序 lvha 驴哈
auto 自动居中
margin 外边距
margin-top 上外边距
margin-right 右外边距
margin-bottom 下外边距
margin-left 左外边距
padding 内边距
padding-top 上内边距
padding-right 右内边距
padding-bottom 下外边距
padding-left 左外边距
float 浮动 :left|right|none 左|右|不浮动
cursor:pointer 小手的代码。。
clear:left|right|both 清除浮动
overflow:hidden 溢出隐藏
index 首页
base 里面写清除默认样式的
text-indent:em 首行缩进 (LOGO名字)
以后logo 必须用H1引背景图片 里面写上字
position:relative|absolute|fixed 定位
relative 相对定位
absolute 绝对定位
fixed 固定定位
Left/top/right/bottom 定位的偏移量
z-index 改变标签z轴堆叠顺序
opacity 透明代码 1不透明(0.9 0.8.。。。。) 0透明
filter:alpha(opacity:0-100)
input{outline:none} 取消焦点
<form action="链接" method="">
post 相对安全 get 不安全
input 表单 单标签
type="text" 账号/文本
type="password" 密码
type="submit" 提交
type="button" 只是一个点击按钮
type="radio" 单选框 label双标签 选项内容
type="checkbox" 复选框 label双标签 选项内容
value="提示 如 请输入密码"
placeholder="也是提示"
select
option 选项栏
textarea 下拉框
resize:none 禁止任意拖放
name="user" 账号
name="password" 密码
table{ border-collapse:collapse;} 让border合并
tr加
colspan="3" 横向合并
rowspan="3" 纵向合并
align 左右对齐方式 middle(左)left center right
valign 上下对齐方式 top center bottom
cellspacing="0" 清除外面的边距
cellpadding="0" 清楚里面的边距
<table cellspacing="0" cellpadding="0">
<thead><tr><th>表头</th></tr></thead>
<tbody><tr><td>表身</td></tr></tbody>
<tfoot><tr><td>表低</td></tr></tfoot>
</table>
frameborder="0" 取消边框
screlling="no" 取消滚动条
iframe src
<frameset>
<frame />
</frameset>
letter-spacing:具体数值 字母间距
word-spacing:数值 单词间距
overflow:auto 溢出滚动
visibility:hidden 隐藏
charset 字符集
utf-8 国际编码
gb2312/gbk 中国编码
author 作者
copyright 版权
keywords 关键词
description 介绍
---------------------------------------------------------------------------------------
js
@media screen and (max-width:900px){}; 屏幕自适应
媒体 屏幕 最大
push :添加一个数组元素
document :文档
pop :删除最后一个数组元素
console :控制台
shift :删除第一个数组元素
string :字符串
Concat 组合数组
undefined :未定义
typeof :关键字
join:数组转化为指定分隔符
slice:返回指定数组
length:数组长度
Array:数组
number:数字
boolean:布尔
alert:提示框
parseInt:转化为整型数值
continue:继续
is NaN:非数字
sort:升序
break:截断 跳出
reverse:倒序
object:对象类型
parseFloat:转化为浮点值
index:索引
floor:向下取整
variable:变量
ceil:向上取整
round:四舍五入
abs:返回绝对值
eval:解析字符串并运算
max:比较最大值
return:返回
min:比较最小值
addEventListener:事件名 函数
to.fixed:保留小数点
attachEvant:(on)事件名
random:随机数
eletment:元素
eventName:事件名
function:函数
removeEventListener:事件解除
detachEvent:删除已注册事件
open():弹出一个新窗口
function:函数(方法)
showModalDialog:弹出一个模式窗口
close():关闭当前窗口
new Date():日期对象
getFullYear():年份
getMonth():月份(0--11)
getDate():几号
getDay():星期几(周一至周六)
getHours():小时(0--23)
getMinites():分钟
getSeconds():秒数(0--59)
getMilliseconds():毫秒数
getTime():从1970至今的毫秒数
Date.now():从1970至今的毫秒值
tolocaleDatestring():输出本地化的日期
setTimeout:延迟时间
tolocaleTimestring():输出本地化得时间
clearTimeout:定时器对象
tolocalestring:输出本地化的日期和时间
setInterval:间隔时间
clearInterval:停止
window.status:浏览器状态栏信息
window.screen:屏幕信息
screen.width:屏幕宽度
screen.height:屏幕高度
screen.availwidth:去掉任务栏宽度
screen.avaiheight:去掉任务栏高度
history:浏览历史记录
location:地址栏对象
navigator:用于获取用户浏览器信息
appCodeName:浏览器代码名的字符串表示
appName:返回浏览器的名称
appVersion:返回浏览器的平台和版本信息
platform:返回运行浏览器的操作系统平台
userAgent:返回由客户机发送服务器的
user-agent:头部的值
Exception:异常 意外情况(try---catch)
获取元素对象方式:
getElementByld:
getElementsByName:
gatElementsByTagName:
getElementByClassName:
onlick 当点击的时候
onmouseover 鼠标移入
onmouseout 鼠标移出
onblur:失去焦点事件
onkeydown:键盘按下事件(前)
onkeypress:键盘按下事件(后)
onload:当页面加载完成之后触发
onchange;内容改变事件
onkeydown;键盘按下事件(前)
onkeyup;键盘松开事件
onkeypress;键盘按下事件(后)
onmouseout:鼠标移出事件
onmouseover:鼠标移入事件
onselect:内容被选中事件
ondblclick:鼠标双击事件
onfocus:获得焦点事件
onkeyup:键盘松开事件
复选框操作 checked=" "
checked 默认选中
false 不选中
true 选中
typeof 查看数据类型
object 对象
number 数字
string 字符串
function 函数
boolean 布尔值 true false
undefined 未定义
parseInt 整数
parseFloat 浮点数/小数
Number 数字
hide 隐藏
show 显示
skin 皮肤
code 代码
even 事件
array 数组
integer 整数
veruant 变量
common 公用
switch
case 情况
break 中断整个循环
continue 跳出本次循环
default 不履行/所有情况都不满足的时候走这个
null 没有/空对象
computed 计算后/生效的
eval(JS可以读懂的代码:如‘1+1’->字符串) 这个代码会把()里面的字符串换成计算机读懂的代码来计算 + - * % 都行 (计算用的)
return 返回
write 输入
find 查找
interval 间隔
setInterval(函数名,1000/) 间隔定时器
clearInterval 清除间隔定时器
Timeout 超时
setTimeout 延迟定时器
clearTimeout 清除延迟定时器
obj.disabled 让按钮/变成不可使用
true 不可用
false 可用
date 时间
get 获取
set 设置
Fullyear 满年
month 月 (从0月开始)
day 日 获取需要 date
week 星期 获取需要day (从0到6)
hours 小时
minutes 分钟
seconds 秒
single 一个/一倍
dubble 两个/两倍
triple 三个/三倍
arguments 函数传参-实参的集合
arguments.length 函数传参-实参的长度
arr.push() 向数组最后添加一项
arr.unshift() 向数组前面添加一项
arr.pop()删除数组最后一位.
arr.shift() 删除数组第一位
arr.splice(开始的位置,删除的个数,添加的东西1。。。)
arr.join('') 变字符串 是中间的隔开东西 如- ,空格 等等。。。
arr.concat(arr1,arr2,arr..要拼接的数组...); 数组拼接/合并数组
arr.reverse() 反转/颠倒数组
arr.sort() 数组排序 按照字符串比大小的方法来排序
arr.sort(function(a1,a2){ return a1-a2 //从小到大 return a2-a1 //从大到小 }) a1 a2随便起 代表的是数组中随机的某两项
str.charAt() 字符串里面的下标
str.indexOf(‘’) 下字符串对应的下标数(相同的就取第一个)
str.lastIndexOf(‘’)下字符串对应的下标数(相同的就取最后一个)
str.substring (开始位置,结束位置)/(开始位置-不写结束位置默认就从开始位置到最后) 截取子串
str.toUpperCase() 大写字母
str.toLowerCase() 小写字母
str.split(切割的方式 '-' '' '空格'等) 切割变成数组
str.charCodeAt('a') 输入字符查找对应的编码
String.fromCharCode(编码) 输入编码查找对应的字符
json.name=value; 添加
delete json.name 删除
token 括号
try{} catch(e) 异常
parseInt(math.random()(m-n)+n) 求n-m之间随机的整数, 前包括后不包括
Math.random() 求随机数
Math.abs() 求绝对值
Math.max(,,,) 求最大值
Math.min(,,,) 求最小值
Math.pow(n,m) 求n的m次方
Math.sqrt(a) 开方
Math.PI π
Math.ceil(12.3) 向上取整 13
Math.floor(12.3) 向下取整 12
Math.round(a) 四舍五入
!important Css样式值后面加这个 权重最大
navigator.userAgent UA 例子判断浏览器的类型
navigator.language 语言
navigator.platform 操作系统
Sibling 兄弟
next 下一个
previous 上一个
获取元素/节点:
(父级) obj.children 找:儿子/子级 子节点
(子级) obj.parentNode 找:父亲/父级 父节点
(同级) obj.nextElementSibling || obj.nextSibling 下一个同级/节点 (同级) obj.previousElementSibling || obj.prenviousSibling 上一个同级/节点
(父级) obj.firstElementChild ||obj.firstChild 首节点
(父级) obj.lastElementChild || obj.lastChild 尾节点
创建元素:
document.createElement_x('标签名') 创建元素
添加插入
(父级) obj.appendChild(谁) 往元素里面最后添加一个
带剪切效果
(父级) obj.insertBefore(把谁,加在谁的前面) 往元素里面添加一个
带剪切效果
删除元素:
(父级) obj.removeChild(子级) 删除子级
window.open() 打开
window.close() 关闭
a标签:target=""
不填 默认新页面打开
_blank 新页面打开
_self 本页面打开
window.location 地址栏信息
window.location.href 链接信息
window.location.search 数据信息
window.location.hash 锚点信息
*了解就行 面试背住
window.location.procotol 协议信息
window.location.hostname 域名信息
window.location.port 端口号信息
window.location.pathname 路径信息
back 返回
forward 向前
history 历史
window.history.back 返回历史记录 退
window.history.forward 返回历史记录 前
alert() 弹
confirm 询问提示框
prompt 问答提示框
console.log() 在F12中显示;
document.write(*) 在页面中输入
scroll 滚动 有兼容问题
client 客户端/可视区
offsetHeight/Width 物体盒子模型的宽高
offsetTop/Bottom/方向 物体距上/下/左/右的距离
offsetparent 定位父级
window.onScroll 当滚动的时候 滚动事件
window.onresize 当缩放的时候 缩放事件
onfocus 当获取焦点的时候
onblur 当失去焦点的时候
obj.getAttribute('属性名') 获取属性名对应的属性值
obj.setAttribute('属性名','属性值') 设置属性
obj.removeAttribute('属性名') 删除属性
event 事件
onmousemove 鼠标移动事件
onload 当图片加载完成时
onerror 当图片加载失败时
cancelBubble 取消冒泡
onkeydown 当按键按下的时候
onkeyup 当按键抬起的时候
oEvent.keycode 键盘编码
oncontextmenu 当按右键的时候
return false 阻止浏览器右键菜单
cache 缓存
onmousedown 鼠标按下时
onmouseup 鼠标抬起时
onmousemove 鼠标移动事件
obj.setCapture() 开始捕获
obj.releaseCapture() 取消捕获
obj.cloneNode() 克隆复制一个节点
document/obj.addEventListener('不加on的事件名',函数名,false) 添加事件绑定 兼容高级
document/obj.attachEvent('加on的事件名',函数名) 添加事件绑定 兼容IE系列
document/obj.removeEventListener('不加on的事件名',函数名,false) 解除事件绑定
document/obj.detachEvent('加on的事件名',函数名) 解除事件绑定
onmouseenter 鼠标移入
onmouseleave 鼠标移出
onmousewheel 鼠标滚轮事件
DOMMouseScroll 鼠标滚动事件
oEvent.wheelDelta 非火狐 测试鼠标滚轮向上向下弹得数字
oEvent.detail 火狐 测试鼠标滚轮向上向下弹得数字
return false 阻止浏览器默认事件 但是在事件绑定中失效
oEvent.preventDefoult 在事件绑定中用 阻止浏览器默认事件(如果单独用只兼容高级浏览器)
oninput 当输入的时候 iE9- 没有此方法
onpropertychange 当属性改变的时候 IE系列
oEvent.srcElement 事件源 非火狐
oEvent.target 事件源 高级浏览器
duration 期间
start 开始
count 次数
complete 完成
var bFlag=false/ture 开关 自定义
easing 速度类型:
linear 匀速
ease-in 加速
ease-out 减速
window.onload 页面加载完毕后执行(代码、资源)
DOMReady 页面加载完毕后执行(代码)
DOMContentLoaded DOM加载事件
obj.onreadystatechange 监控事件(模拟DOM加载事件)
readyState 加载状态
document/obj.readyState 加载状态
ondbclick 鼠标双击
queryselector 新的获取元素方法
window.location.reload 重新加载
cookie
expires 期限
session 一个会话(浏览器打开和关闭)
path 路径
define 定义
require 引用其他模块
exports 导出模块
module 批量导出模块,
data-main 主要数据/初始化接口
success 成功
error 失败
Request 请求
ActiveX 浏览器插件
XMLHttpRequest() ajax 创建/ 不兼容ie6-
ActiveXObject('Microsoft.XMLHTTP') 创建/(插件) ie系列
oAjax.open()打开
oAjax.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
oAjax.send() 发送
onreadystatechange 接收/当通信状态变化
oAjax.abort() 使中止
oAjax.readyState 是否完成/加载状态
oAjax.status 是否成功
response 回答/响应
oAjax.responseText 返回结果
JSON.parse() 可以把字符串json变成json 不过json要正规些 双引号
JSON.stringify() json打印出来的方法
encode 编码
decode 解码
Component 组件/元件
encodeURIComponent('中文') 中文转化成编码
decodeURIComponent('编码') 编码转化成中文
str.replace 替换
new RegExp() 正则表达式
str.search() 跟indexOf一样 在正则用
str.match 匹配
正则.test(你要校验的str) true 正确满足 false 不满足 用这个的时候一定配合行首和行尾
转译
\d 数字 [0-9]
\w 数字、英文、下划线 [0-9a-z]
\s 空白字符 所有的空白字符
. 代表任意字符
\D 非数字 [^0-9]
\W 非数字、英文、下划线 [^0-9a-z]
\S 非空白字符
\u4e00-\u9fa5 中文
---------------------------------------------------------------------------------------
量词
{n} n个
{n,m} n-m个
{n,} 最少n个,最多随便
{0,m} 最少随便 最多m个
{1,} 就是 若干个
{0,} 任意个 可以没有
? {0,1} 最少没有 最多1个
\ 转译特殊字符
| 或的意思
i 忽略大小写
g 全局匹配
m 多行模式
^ 行首 如果在方括号里面是除了
$ 行尾
*jq
hide 隐藏
show 显示
toggle 点击
hover 移入
fadeIn 淡入
fadeOut 淡出
animate 运动函数(move)
slideDown 滑动从上往下出来
slideUp 滑动从下往上隐藏
eq(下标) 标签获取的下标
li>a li下面的第一级a
伪类选择器:
li:last li最后一个
li:first li第一个
li:eq(2) 第三个li
obj:even 偶数
obj:odd 奇数
obj:has("p/标签名") 里面包含‘p’这个标签的就会选取
obj:contains("p/内容") 内容有得‘p’ 就都会选取
event/自己起行参名字.pageX X轴坐标
event/自己起行参名字.pageY Y轴坐标
offset().top 物体绝对的位置 ->getPos()函数
offset().left 物体绝对的位置
position().top 物体距定位父级距离 ->offsetTop
position().left 物体距定位父级距离
document.scrollTop 和原生一样
document.scrollLeft 和原生一样
.width/.height 物体本身的宽高
innerHeight/Width 物体内部的宽高 包括padding 不包括边框
outerHeight/Width 物体盒子模型宽高
父级.append(子级) 在父级内的后部追加
父级.prepend(子级) 在父级内的前面追加
子级.appendTo(父级) 在父级后部追加
子级.prependTo(父级) 在父级前部追加
obj1.after(obj2) 把2放在1的后面
obj1.before(obj2) 把2放在1的前面
bind() 事件绑定
unbind() 事件解绑
live() 事件委托
die() 解除事件委托
**以上四种不推荐 因为原理还是昂 所以推荐on
obj.on() 可以事件绑定/委托
each 循环
$.trim() 去除首尾空格
extend() 延伸
height() 就是宽度
innerHeight 包括padding、不包括边框
outerHeight 盒子模型的
offset().left -> getPos()
position().left -> offsetLeft()
scrollTop() -> scrollTop
eve.pageX/Y 坐标
maxlength 表单元素最大长度 属性
$.fn.函数名=function(){} 建立jq封装函数
$.fn.extend({函数名1:function(){},函数名2:function(){},...})
汉字:[0x4e00,0x9fa5](或十进制[19968,40869])
数字:[0x30,0x39](或十进制[48, 57])
小写字母:[0x61,0x7a](或十进制[97, 122])
大写字母:[0x41,0x5a](或十进制[65, 90])
parent() 父级
offsetParent() 定位父级
parents() 所有父级 括号里面可以筛选 比如放class名字或...
str/arr.slice(开始位置,结束位置) 切 从开始到结束 如果只有开始 就从开始到最后。 前包后不包
prototype 原型
form表单中 submit 提交 reset 重置
xxx instanceOf xxx 检测一个对象属于某个类
xxx.constructor==xxx 看构造函数 双等是判断 直接父级属不属于xxx 一个等号是赋值让直接父级等于xxx
fn.call(this的指向,参数一,参数二,....) 改变this的指向 fn中的this=
fn.apply(this的指向,[参数一,参数二,....]) 改变this的指向 fn中的this=
init 开始
localStorage 本地存储
一般的规范
localStorage.name=value 存
localStorage.name 取
delete localStorage.name 删除一条
localStorage.clear() 删除全部
规范的存取
localStorage.setItem(name,value)
localStorage.getItem(name)
localStorage.removeItem(name)
sessionStorage 临时存储 和localStorage一样用法
include() 包含
template.defaults.openTag=''; 自定义模板开始样子
template.defaults.closeTag=''; 自定义模板结束样子
template.config('openTag','')
template.config('closeTag','')
template.config('escape',true/false) true不默认转译 false默认转译
m model 模型
v view 视图
c controller 控制器
scope 范围 作用域
then 然后
model模型
bind绑定
ng-app=""; 引用其他模块
ng-model="" 数据从哪来
ng-bind="" 或 model 或 {{xxx}} 数据到哪去
ng-init 初始化
ng-repeat 循环
angular.module('名字',[依赖模块]).controller('名字',function(依赖项){})
$scope
$http
$interval
$timeout
`变量` 反引号包裹变量 ${} ES6模板字符串
|currency:"" 货币
date:"" 时间戳转化处理
route 路由/状态
filter 过滤器
directive 指令
restrict 类型 E:'element' C:'class' M:'comment' A:'attribute'
service 依赖
oDate.toString() 获取正常时间
creator.ionic.io 做手机端的框架网站不错
ng-show true false 显示 隐藏
ng-hide true false 隐藏 显示
ng-clock
comment 注释
bundle 打包
transclude 嵌入
params 参数
provider 提供者
.config() 配置
$scope.$watch(数据,fn)
angular.bind(this的指向,要改变指向的函数名,参数)
template 模板
templateUrl:'模板地址' 模板
$ bower install * bower工具安装组件
ReactDOM.render(什么东西,渲染到哪)
type='text/babel'
state 状态
extends 延伸 继承
constructor 创建
super 超类/父类
component 组件
React.Component
this.props.属性
组件中 ref和正常的ID类似
vue
el:'id'
data:{}
$index
capitalize 首字母大写
uppercase 变大写字母
lowercase 变小写字母
ev.stoppropagation() 阻止冒泡
ev.preventDefault() 阻止默认事件 angular
bootstrap 开启应用模式
copy(复制谁,复制到哪里) 复制/克隆
equals(a,b) 比较
forEach 循环
fromJson 字符串json转化成json
extend(obj,obj1,obj2。。。) 扩展
标签里面属性 transition="名字" 过渡 动画
.名字-
transition 过渡
transition:时间 让谁变/all ease;
enter 进来
leave 出去
route 路由/状态
watch 监控
props 存东西 可在替换模板身上用
Router-view 状态视图
v-link="{path:名字}"
animation:8s test/名字 linear infinite/数值/次数;
background-size 背景尺寸
contain 以最合适的状态展示 可能会留白
cover 尽可能填满
nth-child(下标 注意:从1开始) 注意:项目不用这个。禁用
nth-of-type(下标 注意:从1开始) 注意:项目不用这个。禁用
background-origin: 背景从哪里开始
content-box
border-box //盒模型
padding-box
background-clip: 背景从哪里开切
content-box
border-box
padding-box
text 注意:这个background-clip前面要加上webkit-
*请认真填写需求信息,我们会在24小时内与您取得联系。