鍍金池/ 教程/ HTML/ JavaScript
工具箱
移動(dòng)端優(yōu)化
HTML
基本原則
CSS
JavaScript
參考

JavaScript

通用約定

注釋

原則

  • As short as possible(如無(wú)必要,勿增注釋):盡量提高代碼本身的清晰性、可讀性。
  • As long as necessary(如有必要,盡量詳盡):合理的注釋、空行排版等,可以讓代碼更易閱讀、更具美感。

單行注釋

必須獨(dú)占一行。// 后跟一個(gè)空格,縮進(jìn)與下一行被注釋說(shuō)明的代碼一致。

多行注釋

避免使用 /*...*/ 這樣的多行注釋。有多行注釋內(nèi)容時(shí),使用多個(gè)單行注釋。

函數(shù)/方法注釋

  • 函數(shù)/方法注釋必須包含函數(shù)說(shuō)明,有參數(shù)和返回值時(shí)必須使用注釋標(biāo)識(shí);
  • 參數(shù)和返回值注釋必須包含類型信息和說(shuō)明;
  • 當(dāng)函數(shù)是內(nèi)部函數(shù),外部不可訪問(wèn)時(shí),可以使用 @inner 標(biāo)識(shí);
/**
 * 函數(shù)描述
 *
 * @param {string} p1 參數(shù)1的說(shuō)明
 * @param {string} p2 參數(shù)2的說(shuō)明,比較長(zhǎng)
 *     那就換行了.
 * @param {number=} p3 參數(shù)3的說(shuō)明(可選)
 * @return {Object} 返回值描述
 */
function foo(p1, p2, p3) {
    var p3 = p3 || 10;
    return {
        p1: p1,
        p2: p2,
        p3: p3
    };
}

文件注釋

文件注釋用于告訴不熟悉這段代碼的讀者這個(gè)文件中包含哪些東西。應(yīng)該提供文件的大體內(nèi)容,它的作者,依賴關(guān)系和兼容性信息。如下:

/**
 * @fileoverview Description of file, its uses and information
 * about its dependencies.
 * @author user@meizu.com (Firstname Lastname)
 * Copyright 2009 Meizu Inc. All Rights Reserved.
 */

命名

變量,使用 Camel 命名法。

var loadingModules = {};

私有屬性、變量和方法以下劃線 _ 開(kāi)頭。

var _privateMethod = {};

常量,使用全部字母大寫,單詞間下劃線分隔的命名方式。

var HTML_ENTITY = {};
  1. 函數(shù),使用 Camel 命名法。
  2. 函數(shù)的參數(shù),使用 Camel 命名法。
function stringFormat(source) {}

function hear(theBells) {}
  1. 類,使用 Pascal 命名法
  2. 類的 方法/屬性,使用 Camel 命名法
function TextNode(value, engine) {
    this.value = value;
    this.engine = engine;
}

TextNode.prototype.clone = function () {
    return this;
};
  1. 枚舉變量使用 Pascal 命名法。
  2. 枚舉的屬性,使用全部字母大寫,單詞間下劃線分隔的命名方式。
var TargetState = {
    READING: 1,
    READED: 2,
    APPLIED: 3,
    READY: 4
};

由多個(gè)單詞組成的縮寫詞,在命名中,根據(jù)當(dāng)前命名法和出現(xiàn)的位置,所有字母的大小寫與首字母的大小寫保持一致。

function XMLParser() {}

function insertHTML(element, html) {}

var httpRequest = new HTTPRequest();

命名語(yǔ)法

類名,使用名詞。

function Engine(options) {}

函數(shù)名,使用動(dòng)賓短語(yǔ)。

function getStyle(element) {}

boolean 類型的變量使用 is 或 has 開(kāi)頭。

var isReady = false;
var hasMoreCommands = false;

Promise 對(duì)象用動(dòng)賓短語(yǔ)的進(jìn)行時(shí)表達(dá)。

var loadingData = ajax.get('url');
loadingData.then(callback);

接口命名規(guī)范

  1. 可讀性強(qiáng),見(jiàn)名曉義;
  2. 盡量不與 jQuery 社區(qū)已有的習(xí)慣沖突;
  3. 盡量寫全。不用縮寫,除非是下面列表中約定的;(變量以表達(dá)清楚為目標(biāo),uglify 會(huì)完成壓縮體積工作)
常用詞 說(shuō)明
options 表示選項(xiàng),與 jQuery 社區(qū)保持一致,不要用 config, opts 等
active 表示當(dāng)前,不要用 current 等
index 表示索引,不要用 idx 等
trigger 觸點(diǎn)元素
triggerType 觸發(fā)類型、方式
context 表示傳入的 this 對(duì)象
object 推薦寫全,不推薦簡(jiǎn)寫為 o,obj 等
element 推薦寫全,不推薦簡(jiǎn)寫為 el,elem 等
length 不要寫成 len,l
prev previous 的縮寫
next next 下一個(gè)
constructor 不能寫成 ctor
easing 示動(dòng)畫平滑函數(shù)
min minimize 的縮寫
max maximize 的縮寫
DOM 不要寫成 dom,Dom
.hbs 使用 hbs 后綴表示模版
btn button 的縮寫
link 超鏈接
title 主要文本
img 圖片路徑(img 標(biāo)簽 src 屬性)
dataset html5 data-xxx 數(shù)據(jù)接口
theme 主題
className 類名
classNameSpace class 命名空間

True 和 False 布爾表達(dá)式

類型檢測(cè)優(yōu)先使用 typeof。對(duì)象類型檢測(cè)使用 instanceof。null 或 undefined 的檢測(cè)使用 == null。

下面的布爾表達(dá)式都返回 false:

  • null
  • undefined
  • '' 空字符串
  • 0 數(shù)字 0

但小心下面的,可都返回 true:

  • '0' 字符串 0
  • [] 空數(shù)組
  • {} 空對(duì)象

不要在 Array 上使用 for-in 循環(huán)

for-in 循環(huán)只用于 object/map/hash 的遍歷,對(duì) Array 用 for-in 循環(huán)有時(shí)會(huì)出錯(cuò). 因?yàn)樗⒉皇菑?0 到 length - 1 進(jìn)行遍歷, 而是所有出現(xiàn)在對(duì)象及其原型鏈的鍵值。

// Not recommended
function printArray(arr) {
  for (var key in arr) {
    print(arr[key]);
  }
}

printArray([0,1,2,3]);  // This works.

var a = new Array(10);
printArray(a);  // This is wrong.

a = document.getElementsByTagName('*');
printArray(a);  // This is wrong.

a = [0,1,2,3];
a.buhu = 'wine';
printArray(a);  // This is wrong again.

a = new Array;
a[3] = 3;
printArray(a);  // This is wrong again.

// Recommended
function printArray(arr) {
  var l = arr.length;
  for (var i = 0; i < l; i++) {
    print(arr[i]);
  }
}

二元和三元操作符

操作符始終寫在前一行,以免分號(hào)的隱式插入產(chǎn)生預(yù)想不到的問(wèn)題。

var x = a ? b : c;

var y = a ?
    longButSimpleOperandB : longButSimpleOperandC;

var z = a ?
        moreComplicatedB :
        moreComplicatedC;
. 操作符也是如此:

var x = foo.bar().
    doSomething().
    doSomethingElse();

條件 (三元) 操作符 (?:)

三元操作符用于替代 if 條件判斷語(yǔ)句。

// Not recommended
if (val != 0) {
  return foo();
} else {
  return bar();
}

// Recommended
return val ? foo() : bar();

&& 和 ||

二元布爾操作符是可短路的,只有在必要時(shí)才會(huì)計(jì)算到最后一項(xiàng)。

// Not recommended
function foo(opt_win) {
  var win;
  if (opt_win) {
    win = opt_win;
  } else {
    win = window;
  }
  // ...
}

if (node) {
  if (node.kids) {
    if (node.kids[index]) {
      foo(node.kids[index]);
    }
  }
}

// Recommended
function foo(opt_win) {
  var win = opt_win || window;
  // ...
}

var kid = node && node.kids && node.kids[index];
if (kid) {
  foo(kid);
}

jQuery 規(guī)范

Latest jQuery

最新版本的 jQuery 會(huì)改進(jìn)性能和增加新功能,若不是為了兼容舊瀏覽器,建議使用最新版本的 jQuery。以下是三條常見(jiàn)的 jQuery 語(yǔ)句,版本越新,性能越好:

$('.elem')
$('.elem', context)
context.find('.elem')

http://wiki.jikexueyuan.com/project/web-development/images/6.png" alt="" />

分別使用 1.4.2、1.4.4、1.6.2 三個(gè)版本測(cè)試瀏覽器在一秒內(nèi)能夠執(zhí)行多少次,結(jié)果 1.6.2 版執(zhí)行次數(shù)遠(yuǎn)超兩個(gè)老版本。

jQuery Variables

  1. 存放 jQuery 對(duì)象的變量以 $ 開(kāi)頭;
  2. 將 jQuery 選擇器返回的對(duì)象緩存到本地變量中復(fù)用;
  3. 使用駝峰命名變量;
var $myDiv = $("#myDiv");
$myDiv.click(function(){...});

Selectors

  1. 盡可能的使用 ID 選擇器,因?yàn)樗鼤?huì)調(diào)用瀏覽器原生方法 document.getElementById 查找元素。當(dāng)然直接使用原生 document.getElementById 方法性能會(huì)更好;
  2. 在父元素中選擇子元素使用 .find()方法性能會(huì)更好, 因?yàn)?ID 選擇器沒(méi)有使用到 Sizzle 選擇器引擎來(lái)查找元素;
// Not recommended
var $productIds = $("#products .class");

// Recommended
var $productIds = $("#products").find(".class");

DOM Manipulation

  1. 當(dāng)要操作 DOM 元素的時(shí)候,盡量將其分離節(jié)點(diǎn),操作結(jié)束后,再插入節(jié)點(diǎn);
  2. 使用字符串連接或 array.join 要比 .append()性能更好;
var $myList = $("#list-container > ul").detach();
//...a lot of complicated things on $myList
$myList.appendTo("#list-container");
// Not recommended
var $myList = $("#list");
for(var i = 0; i < 10000; i++){
    $myList.append("<li>"+i+"</li>");
}

// Recommended
var $myList = $("#list");
var list = "";
for(var i = 0; i < 10000; i++){
    list += "<li>"+i+"</li>";
}
$myList.html(list);

// Much to recommended
var array = [];
for(var i = 0; i < 10000; i++){
    array[i] = "<li>"+i+"</li>";
}
$myList.html(array.join(''));

Events

  1. 如果需要,對(duì)事件使用自定義的 namespace,這樣容易解綁特定的事件,而不會(huì)影響到此 DOM 元素的其他事件監(jiān)聽(tīng);
  2. 對(duì) Ajax 加載的 DOM 元素綁定事件時(shí)盡量使用事件委托。事件委托允許在父元素綁定事件,子代元素可以響應(yīng)事件,也包括 Ajax 加載后添加的子代元素;
$("#myLink").on("click.mySpecialClick", myEventHandler);
$("#myLink").unbind("click.mySpecialClick");
// Not recommended
$("#list a").on("click", myClickHandler);

// Recommended
$("#list").on("click", "a", myClickHandler);

鏈?zhǔn)綄懛?/h3>
  1. 盡量使用鏈?zhǔn)綄懛ǘ皇怯米兞烤彺婊蛘叨啻握{(diào)用選擇器方法;
  2. 當(dāng)鏈?zhǔn)綄懛ǔ^(guò)三次或者因?yàn)槭录壎ㄗ兊脧?fù)雜后,使用換行和縮進(jìn)保持代碼可讀性;
$("#myDiv").addClass("error").show();
$("#myLink")
  .addClass("bold")
  .on("click", myClickHandler)
  .on("mouseover", myMouseOverHandler)
  .show();

Miscellaneous

  1. 多個(gè)參數(shù)使用對(duì)象字面量存儲(chǔ);
  2. 不要將 CSS 寫在 jQuery 里面;
  3. 正則表達(dá)式僅準(zhǔn)用 .test() 和 .exec()。不準(zhǔn)用 "string".match();

jQuery plug template

// jQuery Plugin Boilerplate
// A boilerplate for jumpstarting jQuery plugins development
// version 1.1, May 14th, 2011
// by Stefan Gabos

// remember to change every instance of "pluginName" to the name of your plugin!
(function($) {

    // here we go!
    $.pluginName = function(element, options) {

        // plugin's default options
        // this is private property and is  accessible only from inside the plugin
        var defaults = {

            foo: 'bar',

            // if your plugin is event-driven, you may provide callback capabilities
            // for its events. execute these functions before or after events of your
            // plugin, so that users may customize those particular events without
            // changing the plugin's code
            onFoo: function() {}

        }

        // to avoid confusions, use "plugin" to reference the
        // current instance of the object
        var plugin = this;

        // this will hold the merged default, and user-provided options
        // plugin's properties will be available through this object like:
        // plugin.settings.propertyName from inside the plugin or
        // element.data('pluginName').settings.propertyName from outside the plugin,
        // where "element" is the element the plugin is attached to;
        plugin.settings = {}

        var $element = $(element), // reference to the jQuery version of DOM element
             element = element;    // reference to the actual DOM element

        // the "constructor" method that gets called when the object is created
        plugin.init = function() {

            // the plugin's final properties are the merged default and
            // user-provided options (if any)
            plugin.settings = $.extend({}, defaults, options);

            // code goes here

        }

        // public methods
        // these methods can be called like:
        // plugin.methodName(arg1, arg2, ... argn) from inside the plugin or
        // element.data('pluginName').publicMethod(arg1, arg2, ... argn) from outside
        // the plugin, where "element" is the element the plugin is attached to;

        // a public method. for demonstration purposes only - remove it!
        plugin.foo_public_method = function() {

            // code goes here

        }

        // private methods
        // these methods can be called only from inside the plugin like:
        // methodName(arg1, arg2, ... argn)

        // a private method. for demonstration purposes only - remove it!
        var foo_private_method = function() {

            // code goes here

        }

        // fire up the plugin!
        // call the "constructor" method
        plugin.init();

    }

    // add the plugin to the jQuery.fn object
    $.fn.pluginName = function(options) {

        // iterate through the DOM elements we are attaching the plugin to
        return this.each(function() {

            // if plugin has not already been attached to the element
            if (undefined == $(this).data('pluginName')) {

                // create a new instance of the plugin
                // pass the DOM element and the user-provided options as arguments
                var plugin = new $.pluginName(this, options);

                // in the jQuery version of the element
                // store a reference to the plugin object
                // you can later access the plugin and its methods and properties like
                // element.data('pluginName').publicMethod(arg1, arg2, ... argn) or
                // element.data('pluginName').settings.propertyName
                $(this).data('pluginName', plugin);

            }

        });

    }

})(jQuery);

此 jQuery 插件模板出自:jQuery Plugin Boilerplate, revisited

性能優(yōu)化

避免不必要的 DOM 操作

瀏覽器遍歷 DOM 元素的代價(jià)是昂貴的。最簡(jiǎn)單優(yōu)化 DOM 樹(shù)查詢的方案是,當(dāng)一個(gè)元素出現(xiàn)多次時(shí),將它保存在一個(gè)變量中,就避免多次查詢 DOM 樹(shù)了。

// Recommended
var myList = "";
var myListHTML = document.getElementById("myList").innerHTML;

for (var i = 0; i < 100; i++) {
  myList += "<span>" + i + "</span>";
}

myListHTML = myList;

// Not recommended
for (var i = 0; i < 100; i++) {
  document.getElementById("myList").innerHTML += "<span>" + i + "</span>";
}

緩存數(shù)組長(zhǎng)度

循環(huán)無(wú)疑是和 JavaScript 性能非常相關(guān)的一部分。通過(guò)存儲(chǔ)數(shù)組的長(zhǎng)度,可以有效避免每次循環(huán)重新計(jì)算。

注: 雖然現(xiàn)代瀏覽器引擎會(huì)自動(dòng)優(yōu)化這個(gè)過(guò)程,但是不要忘記還有舊的瀏覽器。

var arr = new Array(1000),
    len, i;
// Recommended - size is calculated only 1 time and then stored
for (i = 0, len = arr.length; i < len; i++) {

}

// Not recommended - size needs to be recalculated 1000 times
for (i = 0; i < arr.length; i++) {

}

異步加載第三方內(nèi)容

當(dāng)你無(wú)法保證嵌入第三方內(nèi)容比如 Youtube 視頻或者一個(gè) like/tweet 按鈕可以正常工作的時(shí)候,你需要考慮用異步加載這些代碼,避免阻塞整個(gè)頁(yè)面加載。

(function() {

    var script,
        scripts = document.getElementsByTagName('script')[0];

    function load(url) {
      script = document.createElement('script');
      script.async = true;
      script.src = url;
      scripts.parentNode.insertBefore(script, scripts);
    }

    load('//apis.google.com/js/plusone.js');
    load('//platform.twitter.com/widgets.js');
    load('//s.widgetsite.com/widget.js');

}());

避免使用 jQuery 實(shí)現(xiàn)動(dòng)畫

  1. 禁止使用 slideUp/Down() fadeIn/fadeOut()等方法;
  2. 盡量不使用 animate()方法;
上一篇:CSS下一篇:移動(dòng)端優(yōu)化