jQuery构造函数init参数分析


Posted in Javascript onMay 13, 2015

在我的上一篇随笔里面分析了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原则上可以输入任意值,但并不是所有值都是有意义的,只有undefined、DOM 元素、字符串、函数、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 是选择器表达式且未指定 context、selector 是函数的情况,其实就是$(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 0

length: 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: div
1: div
2: div
context: document
length: 3
prevObject: jQuery.fn.jQuery.init[1]__proto__: jQuery[0]
selector: "div"
.
*/
  </script>

</html>

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

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

// The body element only exists once, optimize finding it

if ( 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: body

context: document

length: 1

prevObject: 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>
 
    <script src='jquery-1.7.1.js'></script>
 
   <script>
 
       $('body')
 
  </script>
 
  </head>
 
  <body>
 
    <div></div>
 
    <div></div>
 
    <div></div>
 
  </body>
 
</html>

然后再jQuery源代码里面输出selector、context和document.body

console.log(selector+context+document.body);

// The body element only exists once, optimize finding it

if ( 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就执行的情况吧

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

以上所述就是本文的全部内容了,希望大家能够喜欢。

Javascript 相关文章推荐
js鼠标左右键 键盘值小结
Jun 11 Javascript
jquery中通过过滤器获取表单元素的实现代码
Jul 05 Javascript
jQuery实现购物车多物品数量的加减+总价计算
Jun 06 Javascript
详解Bootstrap glyphicons字体图标
Jan 04 Javascript
JS验证 只能输入小数点,数字,负数的实现方法
Oct 07 Javascript
解决jquery有正确返回值但不执行success函数的问题
Aug 20 jQuery
vue.js input框之间赋值方法
Aug 24 Javascript
JS实现电话号码的字母组合算法示例
Feb 26 Javascript
Vue 3.x+axios跨域方案的踩坑指南
Jul 04 Javascript
node.js中事件触发器events的使用方法实例分析
Nov 23 Javascript
Javascript数组及类数组相关原理详解
Oct 29 Javascript
JavaScript数组 几个常用方法总结
Nov 11 Javascript
CSS+JS实现点击文字弹出定时自动关闭DIV层菜单的方法
May 12 #Javascript
JavaScript实现DIV层拖动及动态增加新层的方法
May 12 #Javascript
js实现带按钮的上下滚动效果
May 12 #Javascript
js验证上传图片的方法
May 12 #Javascript
js中setTimeout()与clearTimeout()用法实例浅析
May 12 #Javascript
js实现一个链接打开两个链接地址的方法
May 12 #Javascript
js实现鼠标经过表格行变色的方法
May 12 #Javascript
You might like
需要注意的几个PHP漏洞小结
2012/02/05 PHP
如何使用php判断所处服务器操作系统的类型
2013/06/20 PHP
php获取字段名示例分享
2014/03/03 PHP
100多行PHP代码实现socks5代理服务器[2]
2016/05/05 PHP
CI(CodeIgniter)框架视图中加载视图的方法
2017/03/24 PHP
PHP vsprintf()函数格式化字符串操作原理解析
2020/07/14 PHP
一段好玩的JavaScript代码
2006/12/01 Javascript
JavaScript中去掉数组中的重复值的实现方法
2011/08/03 Javascript
Js 导出table内容到Excel的简单实例
2013/11/19 Javascript
javascript获取鼠标点击元素对象(示例代码)
2013/12/20 Javascript
json属性名为什么要双引号(个人猜测)
2014/07/31 Javascript
JavaScript中的数组操作介绍
2014/12/30 Javascript
12行javascript代码绘制一个八卦图
2015/04/02 Javascript
js仿3366小游戏选字游戏
2016/04/14 Javascript
jQuery中事件与动画的总结分享
2016/05/24 Javascript
Vue通过URL传参如何控制全局console.log的开关详解
2017/12/07 Javascript
详解从NodeJS搭建中间层再谈前后端分离
2018/11/13 NodeJs
vueScroll实现移动端下拉刷新、上拉加载
2019/03/22 Javascript
elementUI select组件value值注意事项详解
2019/05/29 Javascript
javascript实现计算器功能
2020/03/30 Javascript
Python中if __name__ == &quot;__main__&quot;详细解释
2014/10/21 Python
使用Python的Twisted框架编写非阻塞程序的代码示例
2016/05/25 Python
flask-socketio实现WebSocket的方法
2018/07/31 Python
python实现字符串和字典的转换
2018/09/29 Python
Python GUI编程完整示例
2019/04/04 Python
Python Charles抓包配置实现流程图解
2020/09/29 Python
C语言面试题
2013/05/19 面试题
舞蹈教师自荐信
2014/01/27 职场文书
会计专业自我鉴定
2014/02/10 职场文书
民间个人借款协议书
2014/09/30 职场文书
清明节寄语2015
2015/03/23 职场文书
工作一年自我鉴定
2019/06/20 职场文书
MySQL8.0无法启动3534的解决方法
2021/06/03 MySQL
Mysql 如何实现多张无关联表查询数据并分页
2021/06/05 MySQL
SONY AN-LP1 短波有源天线放大器图
2022/04/05 无线电
Vue OpenLayer 为地图绘制风场效果
2022/04/24 Vue.js