读《jQuery技术内幕》(03)

来源:互联网 发布:七哥娃娃淘宝店铺 编辑:程序博客网 时间:2024/06/03 13:55

jQuery构造函数init参数分析(一)

      在我的上一篇随笔里面分析了jQuery的构造函数,jQuery对象中有一个原型方法init才是是真正的构造函数,通过init的原型对象跟jQuery的原型对象保持引用关系使得init的实例可以正常调用jQuery的原型方法,就好像是jQuery的实例一样。下面就来看看init这个幕后的构造函数是怎么写的:

init: function( selector, context, rootjQuery ) {...}

 

可以看到这个方法接受3个参数,其前两个参数是jQuery方法传递过来的

var jQuery = function( selector, context ) {// The jQuery object is actually just the init constructor 'enhanced'return new jQuery.fn.init( selector, context, rootjQuery );},

 

Selector原则上可以输入任意值,但并不是所有值都是有意义的,只有undefinedDOM 元素、字符串、函数、jQuery 对象、普通 JavaScript 对象这几种类型是有效的,这个参数是通常是填写的但是不填写也不会报错

console.log($());//[constructor: function, init: function, selector: "", jquery: "1.7.1", size: function…]

 

Context作为执行上下文或者叫执行范围可以不传入,或者传入 DOM 元素、jQuery 对象、普通 JavaScript 对象之一

参数 rootjQuery:包含了 document 对象的 jQuery 对象,用于 document.getElementById() 查找失败、selector 是选择器表达式且未指定 contextselector 是函数的情况,其实就是$(document)

下面根据参数的不同分为12种情况逐个讨论

1.selector 可以转换为false

// Handle $(""), $(null), or $(undefined)if ( !selector ) {return this;}

 

源码中的注释已经写得很清楚了,当是这三种情况时直接return不进行任何处理

2.参数 selector 是 DOM 元素

例如: $(document)这种写法

// Handle $(DOMElement)if ( selector.nodeType ) {this.context = this[0] = selector;this.length = 1;return this;}

 

只要是dom元素肯定有节点类型,然后把这个节点变成jquery对象的第一个元素并且赋值给上下文context,length属性是jQuery的原型属性默认为0

// The default length of a jQuery object is 0length: 0,

 

这里有了一个元素之后就把length属性修改为1。return this 操作使得函数执行后的结果依然是jQuery对象这样就可以实现类似$(document).each()这样的链式调用了。最终得到的类似这样的{0:document,context:document,length:1….}对象,其实所有的情况最后都会变成这种形式的对象,除了jQuery原型属性和方法之外就是获取的dom节点并且按照阿拉伯数字依次排列,所以我们可以使用$(selector)[0]的形式代替$(selector).get(0)来获取dom对象。例如:

<!doctype html><html>   <head>      <title></title>   </head>   <body>       <div></div>       <div></div>       <div></div>   </body>   <script src='jquery-1.7.1.js'></script>   <script>     console.log($('div'));/*[div, div, div, prevObject: jQuery.fn.jQuery.init[1], context: document, selector: "div", constructor: function, init: function…]0: div1: div2: divcontext: documentlength: 3prevObject: jQuery.fn.jQuery.init[1]__proto__: jQuery[0]selector: "div".*/   </script></html>

 

3.参数是特殊的字符串“body

由于body元素在一个文档对象中只有一个所以单独列出来处理

// The body element only exists once, optimize finding itif ( selector === "body" && !context && document.body ) {this.context = document;this[0] = document.body;this.selector = selector;this.length = 1;return this;}

 

这里有3个条件必须同时满足,第二个必须没有上下文的条件我也不是太理解,$(‘body’,document)这样的看起来很正常的写法也会被这种情况“忽视”     

 console.log($('body',document)); /* jQuery.fn.jQuery.init[1]0: bodycontext: documentlength: 1prevObject: jQuery.fn.jQuery.init[1]selector: "body"__proto__: jQuery[0]*/

 

 

 

虽然和$(‘body’)的结果是一样的,但是却被当做两种情况来看待,可能是因为body只有一个上下文只能是document没有必要添加吧,否则又要判断上下文是不是document。第三个条件是保证document.body必须存在,那么什么情况下会前两个情况满足document.body又不存在呢?首先就是js代码先于html代码加载时会出现这个是初学者经常会犯的错误,通常我们要写成:

$(function(){...})

 

或者

$(document).ready(function(){...})

 

其实这两个是一样的调取的是一个方法,dom加载这一块以后在分析。对此我们可以做个测试html代码如下:

<!doctype html><html>   <head>      <title></title>   </head>   <body>       <div></div>       <div></div>       <div></div>   </body>   <script src='jquery-1.7.1.js'></script>   <script>     console.log($('div'));/*[div, div, div, prevObject: jQuery.fn.jQuery.init[1], context: document, selector: "div", constructor: function, init: function…]0: div1: div2: divcontext: documentlength: 3prevObject: jQuery.fn.jQuery.init[1]__proto__: jQuery[0]selector: "div".*/   </script></html>

然后再jQuery源代码里面输出selectorcontextdocument.body

 

console.log(selector+context+document.body);// The body element only exists once, optimize finding itif ( selector === "body" && !context && document.body ) {this.context = document;this[0] = document.body;this.selector = selector;this.length = 1;return this;}

 

虽然我们只写了一个其实执行了四次,只有最后一次才是是我们调用后的结果,最后一次的结果是bodyundefinednull这个时候前两个就是满足的但是最后一个是null。回想起第一篇jQuery总体架构架构里面undefined会被重新,那么document.body会不会被重写为null呢?当我尝试在代码中修改时就会报错看来是不会的,那这个条件就是预防没有加载html就执行的情况吧

第四种是除了上述的字符串情况之外的其他字符串,情况比较多放在下一篇吧。

原创粉丝点击