HTML5技术

【深入浅出jQuery】源码浅析2--奇技淫巧 - ChokCoco(3)

字号+ 作者:H5之家 来源:博客园 2016-03-29 18:00 我要评论( )

这里的 hook 只是 jQuery 大量使用钩子的冰山一角,在对 DOM 元素的操作一块,attr 、val 、prop 、css 方法大量运用了钩子,用于兼容 IE 系列下的一些怪异行为。在遇到钩子函数的时候,要结合具体情境具体分析,这

这里的 hook 只是 jQuery 大量使用钩子的冰山一角,在对 DOM 元素的操作一块,attr 、val 、prop 、css 方法大量运用了钩子,用于兼容 IE 系列下的一些怪异行为。在遇到钩子函数的时候,要结合具体情境具体分析,这些钩子相对于表驱动而言更加复杂,它们的结构大体如下,只要记住钩子的核心原则,保持代码整体逻辑的流畅性,在特殊的情境下去处理一些特殊的情况:

var someHook = { get: function(elem) { // obtain and return a value return "something"; }, set: function(elem, value) { // do something with value } }

从某种程度上讲,钩子是一系列被设计为以你自己的代码来处理自定义值的回调函数。有了钩子,你可以将差不多任何东西保持在可控范围内。

 

   连贯接口

无论 jQuery 如今的流行趋势是否在下降,它用起来确实让人大呼过瘾,这很大程度归功于它的链式调用,接口的连贯性及易记性。很多人将连贯接口看成链式调用,这并不全面,我觉得连贯接口包含了链式调用且代表更多。而 jQuery 无疑是连贯接口的佼佼者。

1、链式调用:链式调用的主要思想就是使代码尽可能流畅易读,从而可以更快地被理解。有了链式调用,我们可以将代码组织为类似语句的片段,增强可读性的同时减少干扰。(链式调用的具体实现上一章有详细讲到)

// 传统写法 var elem = document.getElementById("foobar"); elem.style.background = "red"; elem.style.color = "green"; elem.addEventListener('click', function(event) { alert("hello world!"); }, true); // jQuery 写法 $('xxx') .css("background", "red") .css("color", "green") .on("click", function(event) {   alert("hello world"); });

2、命令查询同体:这个上一章也讲过了,就是函数重载。正常而言,应该是命令查询分离(Command and Query Separation,CQS),是源于命令式编程的一个概念。那些改变对象的状态(内部的值)的函数称为命令,而那些检索值的函数称为查询。原则上,查询函数返回数据,命令函数返回状态,各司其职。而 jQuery 将 getter 和 setter 方法压缩到单一方法中创建了一个连贯的接口,使得代码暴露更少的方法,但却以更少的代码实现同样的目标。

3、参数映射及处理:jQuery 的接口连贯性还体现在了对参数的兼容处理上,方法如何接收数据比让它们具有可链性更为重要。虽然方法的链式调用是非常普遍的,你可以很容易地在你的代码中实现,但是处理参数却不同,使用者可能传入各种奇怪的参数类型,而 jQuery 作者想的真的很周到,考虑了用户的多种使用场景,提供了多种对参数的处理。

// 传入键值对 jQuery("#some-selector") .css("background", "red") .css("color", "white") .css("font-weight", "bold") .css("padding", 10); // 传入 JSON 对象 jQuery("#some-selector").css({ "background" : "red", "color" : "white", "font-weight" : "bold", "padding" : 10 });

jQuery 的 on() 方法可以注册事件处理器。和 CSS() 一样它也可以接收一组映射格式的事件,但更进一步地,它允许单一处理器可以被多个事件注册:

// binding events by passing a map jQuery("#some-selector").on({ "click" : myClickHandler, "keyup" : myKeyupHandler, "change" : myChangeHandler }); // binding a handler to multiple events: jQuery("#some-selector").on("click keyup change", myEventHandler);

 

   无 new 构造

怎么访问 jQuery 类原型上的属性与方法,怎么做到做到既能隔离作用域还能使用 jQuery 原型对象的作用域呢?重点在于这一句:

// Give the init function the jQuery prototype for later instantiation jQuery.fn.init.prototype = jQuery.fn;

这里的关键就是通过原型传递解决问题,这一块上一章也讲过了,看过可以跳过了,将文字搬过来。

嘿,回想一下使用 jQuery 的时候,实例化一个 jQuery 对象的方法:

// 无 new 构造 $('#test').text('Test'); // 当然也可以使用 new var test = new $('#test'); test.text('Test');

大部分人使用 jQuery 的时候都是使用第一种无 new 的构造方式,直接 $('') 进行构造,这也是 jQuery 十分便捷的一个地方。当我们使用第一种无 new 构造方式的时候,其本质就是相当于 new jQuery(),那么在 jQuery 内部是如何实现的呢?看看:

(function(window, undefined) { var // ... jQuery = function(selector, context) { // The jQuery object is actually just the init constructor 'enhanced' // 看这里,实例化方法 jQuery() 实际上是调用了其拓展的原型方法 jQuery.fn.init return new jQuery.fn.init(selector, context, rootjQuery); }, // jQuery.prototype 即是 jQuery 的原型,挂载在上面的方法,即可让所有生成的 jQuery 对象使用 jQuery.fn = jQuery.prototype = { // 实例化化方法,这个方法可以称作 jQuery 对象构造器 init: function(selector, context, rootjQuery) { // ... } } // 这一句很关键,也很绕 // jQuery 没有使用 new 运算符将 jQuery 实例化,而是直接调用其函数 // 要实现这样,那么 jQuery 就要看成一个类,且返回一个正确的实例 // 且实例还要能正确访问 jQuery 类原型上的属性与方法 // jQuery 的方式是通过原型传递解决问题,把 jQuery 的原型传递给jQuery.prototype.init.prototype // 所以通过这个方法生成的实例 this 所指向的仍然是 jQuery.fn,所以能正确访问 jQuery 类原型上的属性与方法 jQuery.fn.init.prototype = jQuery.fn; })(window);

大部分人初看 jQuery.fn.init.prototype = jQuery.fn 这一句都会被卡主,很是不解。但是这句真的算是 jQuery 的绝妙之处。理解这几句很重要,分点解析一下:

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • Android -- 带你从源码角度领悟Dagger2入门到放弃(一) - 阿呆哥哥

    Android -- 带你从源码角度领悟Dagger2入门到放弃(一) - 阿呆哥哥

    2017-04-21 11:02

  • ASP.NET Core MVC 源码学习:详解 Action 的激活 - Savorboard

    ASP.NET Core MVC 源码学习:详解 Action 的激活 - Savorboard

    2017-04-14 13:04

  • 深入浅出数据库索引原理 - 陈宏鸿

    深入浅出数据库索引原理 - 陈宏鸿

    2017-04-03 10:00

  • 车大棒浅谈jQuery源码(二) - 车大棒

    车大棒浅谈jQuery源码(二) - 车大棒

    2017-04-02 10:07

网友点评
o