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动态加载当前时间的方法
Feb 09 Javascript
javascript实现炫酷的拖动分页
May 11 Javascript
深入理解js中this的用法
May 28 Javascript
原生JS实现风箱式demo,并封装了一个运动框架(实例代码)
Jul 22 Javascript
Vue.js实战之利用vue-router实现跳转页面
Apr 01 Javascript
JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题
Jun 30 Javascript
解决npm管理员身份install时出现权限的问题
Mar 16 Javascript
vscode中vue-cli项目es-lint的配置方法
Jul 30 Javascript
Vue 实现拖动滑块验证功能(只有css+js没有后台验证步骤)
Aug 24 Javascript
Vue 实现手动刷新组件的方法
Feb 19 Javascript
vue+vant实现购物车全选和反选功能
Nov 17 Vue.js
使用vue编写h5公众号跳转小程序的实现代码
Nov 27 Vue.js
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+jQuery制作的列表分页的功能模块
2014/10/14 PHP
PHP框架Laravel的小技巧两则
2015/02/10 PHP
thinkphp自带验证码全面解析
2016/09/18 PHP
js中格式化日期时间型数据函数代码
2010/11/08 Javascript
详解JS函数重载
2014/12/04 Javascript
jQuery中:radio选择器用法实例
2015/01/03 Javascript
jQuery scrollFix滚动定位插件
2015/04/01 Javascript
CascadeView级联组件实现思路详解(分离思想和单链表)
2016/04/12 Javascript
jQuery如何获取动态添加的元素
2016/06/24 Javascript
jQuery插件ajaxFileUpload异步上传文件
2016/10/19 Javascript
js实现炫酷的左右轮播图
2017/01/18 Javascript
详解angularjs结合pagination插件实现分页功能
2017/02/10 Javascript
JavaScript手风琴页面制作
2017/05/17 Javascript
微信小程序下拉刷新PullDownRefresh的使用方法
2018/11/29 Javascript
微信小程序实现的点击按钮 弹出底部上拉菜单功能示例
2018/12/20 Javascript
JS使用for in有序获取对象数据
2020/05/19 Javascript
[02:53]DOTA2亚洲邀请赛 NewBee战队巡礼
2015/02/03 DOTA
python里将list中元素依次向前移动一位
2014/09/12 Python
Python+request+unittest实现接口测试框架集成实例
2018/03/16 Python
如何基于pythonnet调用halcon脚本
2020/01/20 Python
TensorFlow实现从txt文件读取数据
2020/02/05 Python
详解python变量与数据类型
2020/08/25 Python
详解numpy.ndarray.reshape()函数的参数问题
2020/10/13 Python
Web前端绘制0.5像素的几种方法
2017/08/11 HTML / CSS
ONLY瑞典官网:世界知名服装品牌
2018/06/19 全球购物
几个常见的消息中间件(MOM)
2014/01/08 面试题
师范教师大学生职业生涯规划范文
2014/01/05 职场文书
政府采购方案
2014/06/12 职场文书
信息管理与信息系统专业求职信
2014/06/21 职场文书
毕业实习自我鉴定范文2014
2014/09/26 职场文书
美丽的大脚观后感
2015/06/03 职场文书
个人催款函范文
2015/06/23 职场文书
廉洁自律准则学习心得体会
2016/01/13 职场文书
新员工入职感言范文!
2019/07/04 职场文书
企业内部管理控制:银行存款控制制度范本
2020/01/10 职场文书
Keras多线程机制与flask多线程冲突的解决方案
2021/05/28 Python