翻译自:http://lab.abhinayrathore.com/
翻译人员:前端开发whqet,意译为主,不当之处敬请指正。
译者说:临近期末,大部分的基础教学内容已经讲解完毕,在进行比较大型的项目训练之前,如果能让学生了解甚至遵循一些前端开发的编码规范将会是一件非常有意义的事情。因此,本博客准备于近期整理一个编码规范与最佳实践的系列文章,包括html、css、javascript、jquery、php等,希望能对大家有所帮助。
------------------------------------------------------------
--我参加了博客之星评选,如果你喜欢我的博客,求投票~~http://vote.blog.csdn.net/blogstar2014/details?username=whqet#content
-----------------------------------------------------------------------------------------
本文给大家呈现的如何书写更好的jQuery代码的相关规范和最佳实践,不包括javascript方面的规范,有好的意见和建议请大家到我的博客留言赐教,或者看看jQuery API的速查表(cheat sheet)。
加载jQuery
- 在您的页面中优先使用CDN的方式,CDN方式的优点在这里,这里有比较流行的jQueryCDN列表清单(由于国内goolge限制问题,建议使用国内的CDN,例如百度的CDN)。
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script>window.jQuery || document.write('<script src="js/jquery-2.1.1.min.js" type="text/javascript"><\/script>')</script>
- 利用上面代码,预备一个相同版本的本地jQuery库,以备不时之需。
- 使用如上所示的协议独立性URL(去掉http:或https:,直接以//开头,例如‘//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js’)
- 如果可能,尽量保持所有的JS代码和jQuery在页面底部加载,更多信息或看个示例HTML5 Boilerplate。
- 使用哪个版本?
- 如果你要兼容ie6、7、8,不要使用jQuery2.x版本
对于新的应用来说,如果不存在兼容性问题,强烈建议使用最新版本
从CDN加载jQuery时,指定你需要加载版本的完整版本号(例如,使用1.11.0而不是1.11或者1)
不要加载多个jQuery版本
不要使用jquery-latest.js - 如果你的页面同时用到了类似于Prototype、MooTools、Zepto等这些同样使用$的类库,要使用jquery替代$,我们可以使用$.noConflict()把$的控制权还给其他库。
- 使用Modernizr实现高级的浏览器特征检测。
jQuery变量
- 所有用于存储、缓存jQuery对象的变量应该以$前缀命名。
- 最好把使用选择器返回的jQuery对象缓存到变量里,以便重用。
var $myDiv = $("#myDiv"); $myDiv.click(function(){...});
- 使用驼峰法命名变量。
选择器
- 尽可能的使用效率更高的ID选择器,因为仅仅使用“document.getElementById()”实现。
- 使用类(Class)选择器时,不要使用元素类型(Element Type),看看绩效差异。
var $products = $("div.products"); // SLOW var $products = $(".products"); // FAST
- 对于ID->child的方式,使用find的方式比嵌套选择器高效,因为第一个选择器不用使用Sizzle这个选择器引擎,更多信息。
// BAD, a nested query for Sizzle selector engine var $productIds = $("#products div.id"); // GOOD, #products is already selected by document.getElementById() so only div.id needs to go through Sizzle selector engine var $productIds = $("#products").find("div.id");
- 选择器右边越具体越好,左边相反,更多信息。
// Unoptimized $("div.data .gonzalez"); // Optimized $(".data td.gonzalez");
- 避免过度具体,更多信息,看看绩效差异。
$(".data table.attendees td.gonzalez"); // Better: Drop the middle if possible. $(".data td.gonzalez");
- 给你的选择器一个范围。
// SLOWER because it has to traverse the whole DOM for .class $('.class'); // FASTER because now it only looks under class-container. $('.class', '#class-container');
- 避免使用全局选择器,更多信息。
$('div.container > *'); // BAD $('div.container').children(); // BETTER
- 避免隐含的全局选择器,更多信息。
$('div.someclass :radio'); // BAD $('div.someclass input:radio'); // GOOD
- 不要使用重复、交叉使用ID选择器,因为单独的ID选择将使用更高效的document.getElementById()方式,更多信息。
$('#outer #inner'); // BAD $('div#inner'); // BAD $('.outer-container #inner'); // BAD $('#inner'); // GOOD, only calls document.getElementById()
DOM操作
- 处理现存元素之前,先剥离,处理之后再附加,更多信息。
var $myList = $("#list-container > ul").detach(); //...a lot of complicated things on $myList $myList.appendTo("#list-container");
- 使用字符串连接符或者array.join(),比.append高效,更多信息,看看绩效差异。
// BAD var $myList = $("#list"); for(var i = 0; i < 10000; i++){ $myList.append("<li>"+i+"</li>"); } // GOOD var $myList = $("#list"); var list = ""; for(var i = 0; i < 10000; i++){ list += "<li>"+i+"</li>"; } $myList.html(list); // EVEN FASTER var array = []; for(var i = 0; i < 10000; i++){ array[i] = "<li>"+i+"</li>"; } $myList.html(array.join(''));
- 不要操作空缺对象,更多信息。
// BAD: This runs three functions before it realizes there's nothing in the selection $("#nosuchthing").slideUp(); // GOOD var $mySelection = $("#nosuchthing"); if ($mySelection.length) { $mySelection.slideUp(); }
事件
- 每个页面只使用一次document的ready事件,这样便于调试与行为流跟踪。
- 尽量不要使用匿名函数绑定事件,因为匿名函数不利于调试、维护、测试、重用,更多信息。
$("#myLink").on("click", function(){...}); // BAD // GOOD function myLinkClickHandler(){...} $("#myLink").on("click", myLLinkClickHandler);
- 对于document ready事件处理函数,尽量不用匿名函数,理由同上。
$(function(){ ... }); // BAD: You can never reuse or write a test for this function. // GOOD $(initPage); // or $(document).ready(initPage); function initPage(){ // Page load event where you can initialize values and call other initializers. }
- document ready事件处理函数可以包含在外部文件中,然后通过页内js的方式调用。
<script src="my-document-ready.js"></script> <script> // Any global variable set-up that might be needed. $(document).ready(initPage); // or $(initPage); </script>
- 不要使用html中的行为语法调用事件(html的onclick事件属性),那简直是调试者的噩梦。始终使用jquery来绑定、删除事件是一件惬意的事情。
<a id="myLink" href="#" οnclick="myEventHandler();">my link</a> <!-- BAD --> $("#myLink").on("click", myEventHandler); // GOOD
- 可能的时候,使用自定义事件,我们可以很方便的解除该事件绑定而不影响其他事件。
$("#myLink").on("click.mySpecialClick", myEventHandler); // GOOD // Later on, it's easier to unbind just your click event $("#myLink").unbind("click.mySpecialClick");
- 当你给多个对象绑定相同的事件时,可以使用事件委派。事件委派中,当我们给父对象绑定事件后,匹配选择器的后代都可以绑定该事件,无论该后代原来就有,还是新增元素。
$("#list a").on("click", myClickHandler); // BAD, you are attaching an event to all the links under the list. $("#list").on("click", "a", myClickHandler); // GOOD, only one event handler is attached to the parent.
Ajax
- 避免使用.getJson()和.get(), 像它的名字昭示的那样使用$.ajax()。
- 不要在https站点上使用http请求,最好使用独立性URL(不包含http:和https:,直接以//开头)。
- 不要在请求URL上放置参数,使用data对象传递参数。
// Less readable... $.ajax({ url: "something.php?param1=test1¶m2=test2", .... }); // More readable... $.ajax({ url: "something.php", data: { param1: test1, param2: test2 } });
- 最好明确指定数据类型(dataType)以便于明确处理的数据类型(参见下例)。
- 对Ajax加载的内容使用事件委派,事件委派可以很好的解决新增元素的事件绑定问题,更多信息。
$("#parent-container").on("click", "a", delegatedClickHandlerForAjax)
- 使用Promise interface(不知道怎么翻,请大家赐教),更多案例。
$.ajax({ ... }).then(successHandler, failureHandler); // OR var jqxhr = $.ajax({ ... }); jqxhr.done(successHandler); jqxhr.fail(failureHandler);
- Ajax样例,更多信息。
var jqxhr = $.ajax({ url: url, type: "GET", // default is GET but you can use other verbs based on your needs. cache: true, // default is true, but false for dataType 'script' and 'jsonp', so set it on need basis. data: {}, // add your request parameters in the data object. dataType: "json", // specify the dataType for future reference jsonp: "callback", // only specify this to match the name of callback parameter your API is expecting for JSONP requests. statusCode: { // if you want to handle specific error codes, use the status code mapping settings. 404: handler404, 500: handler500 } }); jqxhr.done(successHandler); jqxhr.fail(failureHandler);
效果和动画
- 采用克制和一致的方法去实现动画。
- 不要过度使用动画效果,除非是用户体验所需。尝试使用简单的show/hide,slideUp/slideDown等方法切换对象,尝试使用‘fast’,'slow'和‘medium’。
插件
- 优先选用具有良好支持、测试、社区支持的插件。
- 检查该插件与您所用jQuery版本的兼容性。
- 任意可复用组件都应该形成插件,看看jQuery插件的样本代码。
链式操作
- 将链式操作看成变量缓存和多选择器请求的替代方式。
$("#myDiv").addClass("error").show();
- 当链式操作超过三个或者因为事件绑定变得复杂时,使用换行和缩进提高链式操作的可读性。
$("#myLink") .addClass("bold") .on("click", myClickHandler) .on("mouseover", myMouseOverHandler) .show();
- 对于长的链式操作来说,也可以把中间对象缓存成一个变量。
杂项
- 使用字面对象传递参数。
$myLink.attr("href", "#").attr("title", "my link").attr("rel", "external"); // BAD, 3 calls to attr() // GOOD, only 1 call to attr() $myLink.attr({ href: "#", title: "my link", rel: "external" });
- 不要混写css与jQuery。
$("#mydiv").css({'color':red, 'font-weight':'bold'}); // BAD .error { color: red; font-weight: bold; } /* GOOD */ $("#mydiv").addClass("error"); // GOOD
- 不用使用弃用的方法,了解每个新版本的弃用方法,并且避免使用它,非常重要。
- 必要的时候可以混合jQuery和原生js,了解表现jQuery和原生js的表现差异。
$("#myId"); // is still little slower than... document.getElementById("myId");
参考文献
- jQuery Performance: http://learn.jquery.com/performance/
- jQuery Learn: http://learn.jquery.com
- jQuery API Docs: http://api.jquery.com/
- jQuery Coding Standards and Best Practice: http://www.jameswiseman.com/blog/2010/04/20/jquery-standards-and-best-practice/
- jQuery Cheatsheet: http://lab.abhinayrathore.com/jquery-cheatsheet/
- jQuery Plugin Boilerplate: http://stefangabos.ro/jquery/jquery-plugin-boilerplate-revisited/
Enjoy it.
----------------------------------------------------------
前端开发whqet,关注web前端开发,分享相关资源,欢迎点赞,欢迎拍砖。
---------------------------------------------------------------------------------------------------------