Skip to content

jQuery 编程最佳实践(译) #1

@codingEcho

Description

@codingEcho

jQuery 编程最佳实践


1.1 用变量缓存jQuery对象

DOM遍历是昂贵的,所以用变量来缓存需要复用的对象。

// bad
if ($('#userName').length) {
    var userName = $('#username');
    // ...
    $('#username').val();
}

// good
var $userName = $('#userName');
if ($userName.length) {
    var userName = $userName.val();
    // ...
    $userName.val(userName);
}

区分普通JavaScript变量和jQuery变量,变量前加美元符$,如上面示例中的:$userName

!!!更好的做法!!!
并不是所有的元素都有val()方法,有时候需要text()方法,所以
HTML这样写:

<input type="text" id="txtUserName" name="userName" />

JavaScript就可以写为:

var $txtUserName = $('txtUserName'),
    userName = $txtUserName.val();

1.2 避免意外的全局变量

// bad
$userName = $('#userName');
if ($userName.length) {
    var userName = $userName.val();
    // ...
    $userName.val(userName);
}

// good
var $userName = $('#userName');

1.3 使用使用$前缀区分jQuery对象和普通变量

// bad
var first = $('#first'); 
var second = $('#second'); 

// better - we use to put $ symbol before jQuery-manipulated objects
var $first = $('#first');
var $second = $('#second');
var value = $first.val(); 

1.4 单var模式

var $first = $('#first'),
    $second = $('#second'),
    value = $first.val(),
    k = 3,
    cookiestring = 'SOMECOOKIESPLEASE',
    myArray = {},
    i,
    j;

1.5 优先使用on来绑定事件

// bad
$first.click(function () {
    $first.css('border', '1px solid red');
    $first.css('color', 'blue');
});

$first.hover(function () {
    $first.css('border', '1px solid red');
});

// better(比上面的写法要好点)
$first.on('click', function () {
    $first.css('border', '1px solid red');
    $first.css('color', 'blue');
});

$first.on('hover', function () {
    $first.css('border', '1px solid red');
});

// good
function changeStyle() {
    // 这样的写法同样不好
    $first.css('border', '1px solid red');
    $first.css('color', 'blue');
    /*
     * // 更好的写法,定义一个CSS样式,比如:.checked
     * $first.css('checked');
     */
}

function tiggerHoverStyle() {
    $first.css('border', '1px solid red');
}

$first.on('click', changeStyle)
      .on('hover', tiggerHoverStyle);

1.6 使用jQuery链式写法

// bad
$second.html(value);
$second.on('click', function () { alert('hello everybody'); });
$second.fadeIn('slow');
$second.animate({ height: '120px' }, 500);

// good
$second.html(value);
$second.on('click', function () {alert('hello everybody');}).fadeIn('slow').animate({ height: '120px' }, 500);

1.7 让你的代码具有可读性

// bad
$second.html(value);
$second.on('click', function () { alert('hello everybody'); }).fadeIn('slow').animate({ height: '120px' }, 500);

// good
$second.html(value);
$second.on('click', function () { alert('hello everybody'); })
       .fadeIn('slow')
       .animate({ height: '120px' }, 500);

1.8 使用短路求值

// bad
function initVar($myVar) {
    if (!$myVar) {
        $myVar = $('#selector');
    }
}

// good
function initVar($myVar) {
    $myVar = $myVar || $('#selector');
}

// good 
function getValue($myVar) {
    var val;
    $myVar = $myVar || $('#selector');
    val = $myVar && $myVar.val();
}

1.9 简写表达式

// bad
if (collection.length > 0) {
    //..
}

// better
if (collection.length) {
    //..
}

1.10 Detach Elements When Doing Heavy Manipulations

// bad    
var $container = $('#container'),
    $containerLi = $('#container li'),
    $element = null;
$element = $containerLi.first();
// ... a lot of complicated things

// better
var $container = $('#container'),
    $containerLi = $container.find('li'),
    $element = null;
$element = $containerLi.first().detach();
// ...a lot of complicated things                               
$container.append($element);

1.11 你应该知道jQuery技巧

// bad
$('#id').data(key, value);

// better (faster)
$.data('#id', key, value);

1.11.1 Use Subqueries Caching Parents

// bad
var $container = $('#container'),
    $containerLi = $('#container li'),
    $containerLiSpan = $('#container li span');

// better (faster)
var $container = $('#container'),
    $containerLi = $container.find('li'),
    $containerLiSpan = $containerLi.find('span');

1.11.2 Avoid Universal Selectors(避免通用选择器)

// bad                                                         
$('.container > *');

// better                                                      
$('.container').children();

1.11.3 Avoid Implied Universal Selectors(避免隐式通用选择器)

When you leave off the selector, the universal selector (*) is still implied.

// bad     
$('.someclass :radio');

// better                                                     
$('.someclass input:radio');

1.11.4 优化选择器

别画蛇添足,耗时且代码不美观。

// bad 
$('div#myid');                                                
$('div#footer a.myLink');

// better
$('#myid');
$('#footer .myLink');
// bad
$('#outer #inner'); 

// better
$('#inner'); 

1.12 尝试使用最新版本的jQuery库

(不要使用已经过时的方法)

// bad - live is deprecated
$('#stuff').live('click', function () {
    console.log('hooray');
});

// better
$('#stuff').on('click', function () {
    console.log('hooray');
});

2 最佳实践

2.1 加载jQuery

(1)坚持使用CDN来加载jQuery,这种别人服务器免费帮你托管文件的便宜干嘛不占呢

<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/jquery-2.1.4.min.js" type="text/javascript"><\/script>')</script>

(2)安全起见,最好还是提供一个本地备份以便在无法从远程CDN服务器获取jQuery时网站也能工作,如上面代码所示。详情见此。

(3)使用裸协议的URL(也就是说去掉http:或者https:),如上面代码展示的那样。

(4)如果可能,尽量将你的JavaScriptjQuery代码放到页面底部。详情移步这里。

(5)该使用哪个版本?

如果你想兼容IE678请不要用2.x的版本针对极少数不用考虑兼容性的幸运儿,极力推荐使用最新版本的jQuery当从CDN服务器加载jQuery时,最好把版本写全(比如1.11.0而不是1.11或者直接写个1)千万莫重复加载

(6)如果你同时还使用了其他JS框架诸如Prototype, MooTools, Zepto云云,因为他们也使用了$符号,所以你就不要再用美刀符号来进行jQuery 编码了,而请用'jQuery'代替。并且调用$.noConflict()保证不会有冲突出现。

(7)要检测浏览器对一些新特性是否支持,请用Modernizr

2.2 关于变量

(1)jQuery类型的变量最好加个$前缀。

(2)时常将jQuery选择器返回的内容存进变量以便重用

var $products = $('div.products'); // 慢
var $products = $('.products'); // 快

(3)使用驼峰命名

var orderList;

2.3 关于选择器

(1)尽量ID选择器。其背后机理其实是调用原生的document.getElementById(),所以速度较其他选择器快。

(2)使用类选择器时不要指定元素的类型。

var $products = $('div.products'); // 慢
var $products = $('.products'); // 快

(3)ID父亲容器下面再查找子元素请用.find()方法。这样做快的原因是通过id选择元素不会使用Sizzle引擎。详情看这里

(4)多级查找中,右边尽量指定得详细点而左边则尽量简单点。

// 丑陋
$('div.data .gonzalez');

// 优化后
$('.data td.gonzalez');

(5)避免冗余。详情或者查看性能比较

$('.data table.attendees td.gonzalez');

// 好的方式:去掉了中间的冗余
$('.data td.gonzalez');

(6)指定选择的上下文。

// 劣质的代码:因为需要遍历整个DOM来找到.class
$('.class');

// 高品代码:因为只需在指定容器范围内进行查找
$('.class', '#class-container');

(7)不要使用万能选择器。查看具体阐释

$('div.container > *'); // 差
$('div.container').children(); // 棒

8.警惕隐式的万能选择器。省略的情况下其实使用的就是*号通配符。

$('div.someclass :radio'); // 差
$('div.someclass input:radio'); // 棒

9.ID已经表示唯一了,背后使用的是document.getElementById(),所以不要跟其他选择器混搭了。

$('#outer #inner'); // 脏
$('div#inner'); // 乱
$('.outer-container #inner'); // 差
$('#inner'); // 干净利落,后台只需调用document.getElementById()

2.4 DOM操作相关

(1)操作任何元素前先将其从文档卸载,完了再贴回去。

var $myList = $("#list-container > ul").detach();
//...一大堆对$myList的处理
$myList.appendTo("#list-container");

(2)代码里将HTML组织好后再一次性贴到DOM中去。具体来说,性能比较

// 这样不好
var $myList = $("#list");
for (var i = 0; i < 10000; i++) {
    $myList.append("<li>" + i + "</li>");
}

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

// 但这样更好var array = []; 
for (var i = 0; i < 10000; i++) {
    array[i] = "<li>" + i + "</li>";
}
$myList.html(array.join(''));

(3)不要处理不存在的元素。

// 无良的做法:jQuery后台要跑完三个函数后才会知道这个元素其实根本不存在
$("#nosuchthing").slideUp();
// 应该这样
var $mySelection = $("#nosuchthing");
if ($mySelection.length) {
    $mySelection.slideUp();
}

2.5事件相关

(1)一个页面只写一个文档ready事件的处理程序。这样代码既清晰好调试,又容易跟踪代码的进程。

(2)不要用匿名函数来做事件的回调。匿名函数不易调试维护测试和复用。或许你想较真,看看这里吧

// 不要这样
$("#myLink").on("click", function(){
    //...
});

// 这样
function myLinkClickHandler() {
 //...
}

$("#myLink").on("click", myLinkClickHandler);

3.处理文档ready事件的回调也不要用匿名函数,匿名函数不易调试维护测试和复用

$(function () {
    // ... 
}); // 糟糕的做法:无法利用此函数也无法为其写测试用例

// 好的做法
$(initPage);
// 或 $(document).ready(initPage);
function initPage() {
    // 这里你可以进行程序的初始化了
}

// 自己的写法
(function ($) {

    var MyApp = {};
    MyApp.init = function () {
        console.log('初始化工作');
    };

    $(MyApp.init);

}(jQuery));

(4)进一步,最好也将ready事件的处理程序放到外部文件中引入到页面,而页面中内嵌的代码只需调用即可。

<script src="my-document-ready.js"></script>
<script>
// 初始化一些必要的全局变量
    $(document).ready(initPage); // 或 $(initPage);
</script>

(5)千万不要写内联到HTML的JS代码,这是调试的梦魇!应该总是用jQuery来绑定事件自带程序,这样也方便随时动态地取消绑定。

<a id="myLink" href="#" onclick="myEventHandler();">my link</a> <!--不好 -->
$("#myLink").on("click", myEventHandler); // GOOD

6.如果可能尽量在绑定事件处理程序时使用一个命名空间,这样可以方便地取消绑定而不会影响其他绑定。

$("#myLink").on("click.mySpecialClick", myEventHandler); // 不错
// 之后,让我们优雅地解除绑定
$("#myLink").unbind("click.mySpecialClick");

2.6 异步操作

(1) 直接用$.ajax()而不要去用$.getJson()$.get(),因为jQuery内部还是将其转为前者

(2)不要对HTTPS站点使用HTTP去发起请求,最好干脆就不要指定(将HTTP或者HTTPS从你的URL中移除)

(3)不要在链接里面嵌参数,请使用专门的参数设置来传递

// 不易阅读的代码
$.ajax({
    url: "something.php?param1=test1&param2=test2",
    //....
});

// 更易阅读
$.ajax({
    url: "something.php",
    data: {
        param1: test1,
        param2: test2
    }
});

(4)尽量指明数据类型以便你自己清楚要处理什么样的数据(见下方会提到的Ajax模板)

(5)对于异步动态加载的内容,最好使用代理来绑定事件处理程序。这样的好处是对于之后动态加载的元素事件同样有效。

$('#parent-container').on('click', 'a', delegatedClickHandlerForAjax);

(6)使用Promise模式

$.ajax({
    //...
}).then(successHandler, failureHandler);

// 抑或
var jqxhr = $.ajax({
    // ...
});
jqxhr.done(successHandler);
jqxhr.fail(failureHandler);

(7)标准的Ajax模板一分。追寻根源

var jqxhr = $.ajax({
    url: url,
    type: 'GET', // 默认为GET,你可以根据需要更改
    cache: true, // 默认为true,但对于script,jsonp类型为false,可以自行设置
    data: {}, // 将请求参数放这里.
    dataType: 'json', // 指定想要的数据类型
    jsonp: 'callback', // 指定回调处理JSONP类型的请求
    statusCode: { // 如果你想处理各状态的错误的话
        404: handler404,
        500: handler500
    }
});
jqxhr.done(successHandler);
jqxhr.fail(failureHandler);

2.7 动画与特效

(1)保持一个始终如一风格统一的动画实现

(2)紧遵用户体验,不要滥用动画特效

  • 使用简洁的显示隐藏,状态切换,滑入滑出等效果来展示元素使用预设值来设置动画的速度'fast','slow',或者400(中等速度)

2.8 插件相关

(1)始终选择一个有良好支持,完善文档,全面测试过并且社区活跃的插件
(2)注意所用插件与当前使用的jQuery版本是否兼容
(3)一些常用功能应该写成jQuery插件。一分jQuery插件的编写模板

2.9链式句法

(1)除了用变量将jQuery选择器返回的结果保存,还可以利用好链式调用。

$("#myDiv").addClass("error").show();

(2)当链式调用多达3次以上或代码因绑定回调略显复杂时,使用换行和适当的缩进来提高代码的可读性。

$("#myLink")
    .addClass("bold")
    .on("click", myClickHandler)
    .on("mouseover", myMouseOverHandler)
    .show();

(3)对于特别长的调用最好还是用变量保存下中间结果来简化代码。

2.10 其他

(1)使用对象字面量来传递参数

// 糟糕:调用了三次attr
$myLink.attr('href', '#').attr('title', 'my link').attr('rel', 'external');

// 不错,只调用了一次attr
$myLink.attr({
    href: '#',
    title: 'my link',
    rel: 'external'
});

(2)不要将CSS与jQuery杂揉

$('#mydiv').css({'color':red, 'font-weight':'bold'}); // 不好
/* 不错 */
.error {
    color: red;
    font-weight: bold;}
$('#mydiv').addClass('error'); 

(3)时刻关注官方Changelog,不要使用摒弃了的方法。点此查看所有废弃的方法
(4)适时地使用原生JavaScript。一些与此有关的性能比较

$("#myId"); // 多少还是会逊色于`document.getElementById("myId")`

REFERENCE

原文:Coding Standards & Best Practices http://lab.abhinayrathore.com/jquery-standards/

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions