by zhangxinxu from http://www. 一、看似偶然的东西实际是必然会发生的我大学时候在图书馆翻过一本很破旧的书,讲生物理论的,主要内容就是探讨生命的产生是偶然还是必然。里面很多亚里士多德都看不懂的公式计算什么的,还有模拟原始地球环境出现了有机物的实验什么的 这种理论类似于,你是个过马路非常小心的人,且你万寿无疆,除了怕被汽车撞。给你100万年的寿命,你最后必然还是被车撞死。 如果以这种理论来看jQuery的出现,结论也应该是必然的! 二、需求、动力、发展、事物产生与jQuery的诞生一个成熟的东西显然不是一口气就出来的,所谓“一铲子挖不了一口井”,我想jQuery的原作者再天才,也是循序渐进过来的,如何个循序渐进法,我想,很有可能就是需求驱动而产生的,好比上图刀削面机器人,据说现在已经第八代了! 1. gelElementById太长了 <button id="button">点击我</button> <img id="image" src="xxx.jpg"> 于是,我的脚本可能就这样: var button = document.getElementById("button") , image = document.getElementById("image") button.onclick = function() { image.style.display = "none"; }; 有何问题?人几乎都是天生的“懒惰者”, var $ = function(id) { return document.getElementById(id); }; $("button").onclick = function() { $("image").style.display = "none"; }; 这里的 2. 我需要一个简洁的暗号,就像“芝麻开门” $("button").onclick = function() { $("image1").style.display = "none"; $("image2").style.display = "none"; }; 好像又看见长长的重复的东西, 这里每次隐藏都要 就是要变成下面的效果: $("button").onclick = function() { $("image1").hide(); $("image2").hide(); }; 3. 如何识别“芝麻开门”的暗号 哦,扩展,立马想到了JS中的 HTMLElement.prototype.hide = function() {
this.style.display = "none";
};
上面代码的demo地址应该不会被人看到吧…… 虽然在身体上钻了个窟窿插进入了一个方法,毕竟浏览器有有效果啊,切肤之痛就不算什么了。但是,我们是在泱泱天朝,很多IE6~IE8老顽固,这些老东西不认识 因此,由于兼容性,我们需要想其他扩展方法。 4. 条条大路通罗马,此处不留爷,自有留爷处 var F = function() {};
F.prototype.hide = function() {
this?.style.display = "none";
};
new F().hide(); // 这个实现隐藏? 本文至少还有一半的内容,但是,全文的最难点就在这里的,对 上面的代码,new F()您可以看做是
上面的引用来自这里。什么意思呢?说白了就是, 举例说明: var F = function(id) {
return document.getElementById(id);
};
new F("image1") == document.getElementById("image1"); // true 说明看上去返回DOM对象,实际确实就是DOM对象 var F = function(id) {
return id;
};
new F("image1") == "image1"; // false 说明看上去返回字符串值,实际并不是字符串 回到上面天真的想法。要想使用 因此, var F = function(id) { this.element = document.getElementById(id); }; F.prototype.hide = function() { this.element.style.display = "none"; }; new F("image").hide(); // 看你还不隐藏 上面代码的demo地址应该不会被人看到吧…… 5. 我不喜欢太暴露 new F("image").hasOwnProperty("element"); // true 太暴露了,我不喜欢~~ 如何隐藏?代码如下: var F = function(id) { return this.getElementById(id); }; F.prototype.getElementById = function(id) { this.element = document.getElementById(id); return this; }; F.prototype.hide = function() { this.element.style.display = "none"; }; new F("image").hide(); // 看你还不隐藏 元素获取方法放在 于是乎,现在就没有直接暴露的API了。 上面代码的demo地址应该不会被人看到吧…… 6. 我不喜欢new, 我喜欢$ 好吧,把 var $ = function(id) { return new F(id); }; 于是,上面的图片隐藏的直接执行代码就是: $("image").hide(); 上面代码的demo地址应该不会被人看到吧…… IE6浏览器也是支持的哦!是不是已经有些jQuery的样子啦! 7. 你怎么就一种姿势啊,人家都腻了诶 在IE8+浏览器中,我们有选择器API, var F = function(selector, context) {
return this.getNodeList(selector, context);
};
F.prototype.getNodeList = function(selector, context) {
context = context || document;
this.element = context.querySelectorAll(selector);
return this;
};
var $ = function(selector, context) {
return new F(selector, context);
}; 此时,我们就可以使用各种选择器了,例如, 8. IE6/IE7肿么办? jQuery就使用了一个比较强大的选择器框架- 8. 遍历是个麻烦事 F.prototype.hide = function() { var i=0, length = this.element.length; for (; i<length; i+=1) { this.element[i].style.display = "none"; } }; 于是乎: $("img").hide(); // 页面所有图片都隐藏啦! 上面代码的demo地址应该不会被人看到吧…… 单纯一个 因此,急需一个遍历包装器元素的方法,姑且叫做 于是有: F.prototype.each = function(fn) { var i=0, length = this.element.length; for (; i<length; i+=1) { fn.call(this.element[i], i, this.element[i]); } return this; }; F.prototype.hide = function() { this.each(function() { this.style.display = "none"; }); }; $("img").hide(); // 页面所有图片都隐藏啦! 上面代码的demo地址应该不会被人看到吧…… 9. 我不喜欢this.element, 可以去掉吗? F.prototype = { element: [NodeList], each: function() {}, hide: function() {} }
于是, F.prototype.init = function(selector, context) { var nodeList = (context || document).querySelectorAll(selector); this.length = nodeList.length; for (var i=0; i<this.length; i+=1) { this[i] = nodeList[i]; } return this; }; 此时, F.prototype.each = function(fn) { var i=0, length = this.length; for (; i<length; i+=1) { fn.call(this[i], i, this[i]); } return this; }; 我们也可以直接使用索引访问包装器中的DOM元素。例如: 上面代码的demo地址应该不会被人看到吧…… 10. 我是完美主义者,我特不喜欢F名称,可以换掉吗? 这个……
就有: 上图代码的demo地址应该不会被人看到吧…… 显然,运行是OK的。似乎也非常有jQuery的模样了,但是,实际上,跟jQuery比还是有差别的,有个较大的差别。如果是上图代码所示的JS结构,则包装器对象要扩展新方法,每个都需要再写一个原型的。例如,扩展一个 $.fn.prototype.attr = function() {
// ...
}; 又看到 脑子动一下就知道了,把 $.fn.attr = function() {
// ...
}; 至此,就使用上讲,与jQuery非常接近了。 但是,还有几个 F 怎么办呢,总不能就像下面这样放着吧:var $ = function(selector, context) { return new F(selector, context); }; var F = function(selector, context) { return this.init(selector, context); }; $.fn = F.prototype; $.fn.init = function(selector, context) { // ... return this; }; $.fn.each = function(fn) { // ... }; $.fn.hide = function() { // ... }; 数学中,我们都学过合并同类项。仔细观察上面的的代码: 于是,一番调整有: var $ = function(selector, context) { return new $.fn.init(selector, context); }; var F = function() { }; $.fn = F.prototype; $.fn.init = function(selector, context) { // ... return this; }; // ... 上面代码显然是有问题的, $.fn.init.prototype = $.fn 于是, 于是乎,大功告成。慢着…… 上面明明还有残留的
var $ = function(selector, context) { return new $.fn.init(selector, context); }; 上图代码的demo地址应该不会被人看到吧…… 实际上,如果你不是非得一个 至此,jQuery大核心已经一步一步走完了,可以看到,所有的这些进阶都是根据需求、实际开发需要来的,慢慢完善,慢慢扩充的! 11. 每个扩展方法都要$.fn.xxxx, 好闹心的来 $.fn.css = function() {}
$.fn.attr = function() {}
$.fn.data = function() {}
// ... 每个扩展前面都有个 于是,jQuery搞了个 $.fn.extend({
css: function() {},
attr: function() {},
data: function() {},
// ...
}); 12. $()不仅可以是选择器字符串,还可以是DOM 以下13~?都是完善啊,补充啊,兼容性处理啊什么的,没有价值,到此为止! 三、排了很长队的结束语网上也有其他一些介绍jQuery原理或机制的文章,可能当事人自己理解,而阅读者本来就不懂,说来说去,越说越绕,可能更不懂了。 jQuery是很优秀,好比身为灵长类的人类。但是,其诞生显然是从简单开始的。因此,要了解人类,可以通过追溯其起源。如果你是上帝,要让你造一个人,你会怎么造,是一口气出来?女娲造人还要捏泥人呢!不妨从单细胞生物开始,随着自然进化,淘汰,自然而然,就会出现人类,上帝他就是这么干的。 jQuery的诞生也大致如此,要想了解jQuery,可以试试踏着本文jQuery的成长足迹,一点一点逐步深入,您就会了解为何jQuery要这么设计,它是如何设计的等。 虽然,内容由浅及深,但是,其中涉及的原型以及 感谢您的阅读至此,欢迎指出文章可能书写不准确的地方,再次感谢! 月底在百姓网有个小分享,演示文档连个肉渣子还没准备呢。因此,未来一周休文。 原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.] (本篇完) 相关文章
标签: dom, extend, jQuery, prototype, querySelectorAll, this上下文, 原型, 继承
|
|