jQuery 对象和 DOM 对象
- DOM 对象:通过原生 javascript(如
getElementsByTagName
或getElementId
)获取的 html 节点。
var dom = document.getElementById("app"); // 获取DOM对象
var html = dom.innerHTML; // 获取DOM元素内的HTML代码
- jQuery 对象:被 jQuery 包装过的 DOM 对象。
var jq = $("#app"); // 获取jQuery对象
var html = jq.html(); // 获取jQuery对象内的HTML代码
不能交换使用 jQuery 对象、DOM 对象上的属性,例如上面代码中的
innerHTML
与html()
。
jQuery 对象->DOM 对象
jQuery 提供了 2 种转换 DOM 对象的方法:
(1)jQuery 对象是一个类似于数组的对象,因此可以通过数组运算符[]
获取指定索引的 DOM 对象。
var jq = $(".test"); // jQuery对象
var dom = jq[0]; // DOM对象
(2)通过 jQuery 本身提供的get(index)
方法来获取指定 index 的对象。
var jq = $(".test"); // jQuery对象
var dom = jq.get(0); // DOM对象
DOM 对象->jQuery 对象
将 DOM 对象通过$()
函数包装起来,就可以获得 jQuery 对象。
var dom = document.getElementById("test");
var jq = $(dom);
可以考虑使用****作为前缀为 jQuery 对象进行命名,例如上面代码中的变量`jq`可以命名为`jq`。
jQuery 选择器性能
提升选择器性能的有效途径是为选择器指定上下文,并以上下文为基础使用first()
、last()
、find()
、filter()
、hasClass()
等 jQuery 筛选 API。
下面对 jQuery 选择器的性能由高向低进行排序:
1、ID 选择器
底层通过调用document.getElementById()
实现。
$("#id");
2、标签选择器
底层通过调用document.getElementsByTagName()
实现。
$("input");
3、类选择器
底层通过调用document.getElementsByClassName()
实现。
$(".class");
4、属性及其它选择器
底层通过对 HTML 字符串进行正则表达式匹配来实现。
$("[contenteditable]");
jQuery 底层有使用原生
document.querySelectorAll()
,可以有效提升 IE8 及以上浏览器当中选择器的性能。
jQuery 作者已经将选择器引擎独立为Sizzle库,而 Sizzle 会按照从右到左的顺序来解析选择器字符串,从而提高查询效率,缩小查找范围和遍历次数。
缓存常用的 jQuery 选择器对象
将需要常用的 jQuery 选择器对象赋值给一个局部或全局变量,是有效提升 jQuery 运行性能的良好开端。
var $jq = $("#app");
$jq.find("div.tree").append("string");
$jq.find("[contenteditable].test").html();
$jq.find(".demo.test").html();
减少循环时的 DOM 操作
在for
、while
、$.each()
等循环语句中,尽量减少 DOM 操作的次数,最好先将模板在循环中组装完成之后再一次性插入 DOM。
var $app = $("#app");
var template = "";
for (var i = 0; i <= 100; i++) {
template += "<p>This is a paragraph!<p>";
}
$app.find("div").html(template);
使用原生方式处理 jQuery 数组
jQuery 选择器的结果是一个数组类型的对象,建议使用for
或while
等原生语法对其进行处理,而非 jQuery 封装过的$.each()
。
<body>
<div id="app">
<div class="demo">1</div>
<div class="demo">2</div>
<div class="demo">3</div>
<div class="demo">4</div>
<div class="demo">5</div>
</div>
</body>
var $demo = $(".demo");
for (var i = 0; i < $demo.length; i++) {
// 通过数组索引提取后,jQuery对象转换成DOM对象,所以这里使用了DOM对象的innerHTML属性
console.info($demo[i].innerHTML);
}
可以通过关键字length
检查数组长度,从而判断 jQuery 对象是否存在。
var $demo = $(".demo");
if ($demo.length !== 0) {
// do something
}
尽可能使用事件委托
jQuery3.x 版本继续简化了事件委托函数,仅剩下on()
、off()
、one()
、trigger()
、triggerHandler()
五个事件处理函数。
<div id="app">
<div id="parent">
<p>parent</p>
<div id="current">
<p>current</p>
<div id="child">child</div>
</div>
</div>
</div>
/* on可以用于处理冒泡事件,但是无法捕获事件 */
$("#current").on("click", function () {
console.info("current is clicked!");
});
$("#child").trigger("click"); // on可以处理向上冒泡的click事件
$("#parent").trigger("click"); // on无法捕获父级元素的click事件
单页面场景下绑定的
on
事件,必须在路由切换时通过off
解除事件绑定,否则会造成大量无用的事件句柄堆积在内存。
通过 extend()封装可复用代码
jQuery.extend()
:拓展**全局对象**,例如下面例子中的`.test(),
$.demo()`;jQuery.fn.extend()
:拓展jQuery 对象数组,例如下面例子中的$("div").test()
,$("div").demo()
;
(function ($) {
/* 标准写法 */
$.extend({
test: function () {
alert("$.extend");
},
});
/* 简便写法 */
$.demo = function () {
// 返回全局对象$,便于链式调用
return this;
};
/* 标准写法 */
$.fn.extend({
test: function () {
alert("$.fn.extend");
},
});
/* 简便写法 */
$.fn.demo = function () {
// 返回jQuery对象数组,便于链式调用
return this;
};
})(jQuery);
两种方式的最大区别在于自定义方法所属的宿主对象不同。
使用 HTML5 的 data 属性绑定数据
通过 HTML5 提供的 data 属性可以更加方便的完成数据绑定,特别是在不借助handlebar
、lodash.template()
等模板引擎的时候。
<div
id="app"
data-number="13.2"
data-string="uinika"
data-boolean="true"
data-null="null"
data-undefine="undefine"
data-object='{"name": "hank"}'
data-array='["demo1", "demo2"]'
></div>
$("#app").data("number");
$("#app").data("string");
$("#app").data("boolean");
$("#app").data("null");
$("#app").data("undefine");
$("#app").data("object").name;
$("#app").data("array")[1];
尽量使用原生 JavaScript
在不影响浏览器兼容性的情况下,尽量使用 JavaScript 原生 API。
var $demo = $(".demo"); // 缓存选择器
$demo.is(":checked"); // 通过jQuery封装过的is()方法
$demo[0].checked; // 通过DOM原生的checked属性
$demo.css({ color: "red" }); // 通过jQuery封装过的css()方法
$demo[0].style.color = "red"; // 通过DOM原生的style.color属性
$("<p></p>"); // 通过jQuery新建<p>标签
$(document.createElement("p")); // 通过DOM原生的createElement方法
$(document).ready()
该函数内的代码会在 DOM 加载完毕后,内容(如图片)加载完成前执行;生产环境中,尽可能在每个 js 文件下使用该函数。
$(document).ready(function () {
// 标准写法
});
$(function () {
// 简化写法
});
JavaScript 原生的
window.onload()
只会在 DOM 和图片等资源全部加载完成之后才执行。
延迟对象$.Deferred()
Deferred()
是一个工厂函数,用来建立新的 deferred 对象(deferred [dɪ’fɜ:d] adj.延缓的),该对象上可以注册多个回调函数队列,这些函数的执行依赖于任意同步或异步函数的执行结果(sucess
或failure
)。该对象可以视为 jQuery 版本的Promise实现,可以更加优雅的解决 JavaScript 回调嵌套的问题。
jQuery 的 Deferred 对象是基于CommonJS Promises/A规范设计的。
deferred.notify()
触发 Deferred 上progress相关的回调函数。deferred.resolve()
Resolve 一个 Deferred 对象,并触发resolve状态相关的回调函数。deferred.reject()
Reject 一个 Deferred 对象,并触发reject状态相关的回调函数。deferred.progress()
该函数在 Deferred 对象生成progress通知时被调用。deferred.done()
该函数在 Deferred 对象被resolve时调用。deferred.fail()
该函数在 Deferred 对象被rejecte时调用。deferred.catch()
该函数在 Deferred 对象被rejecte时调用。deferred.then()
Deferred 对象resolved、rejected、progress时,都会被触发的回调函数。deferred.promise()
返回一个延迟的 Promise 对象。&.when()
提供一种基于零个或多个 Thenable 对象执行回调函数的方式,其参数是一个代表异步事件的 Deferred 对象。$("selector").promise()
返回一个 Promise 对象去观察所有绑定到集合、队列的确定类型行为是否已经完成。
var deferred = $.Deferred();
var demo = function (deferred) {
var task = function () {
deferred.resolve();
// deferred.notify();
// deferred.reject();
};
setTimeout(task, 2000);
return deferred;
};
$.when(demo(deferred))
.progress(function () {
console.info("progress");
})
.then(function () {
console.info("then");
})
.done(function () {
console.info("done");
})
.fail(function () {
console.info("fail");
})
.catch(function () {
console.info("catch");
});
/*
输出结果:
then
done
*/
$.ajax()
返回的就是一个 deferred 对象。