$() 即调用了jQuery.fn.init方法

jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
}

下面是init方法代码:

 init: function( selector, context, rootjQuery ) {
var match, elem;
if ( !selector ) {
return this;
}
if ( typeof selector === "string" ) {
// code
} else if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
if ( selector.selector !== undefined ) {
this.selector = selector.selector;
this.context = selector.context;
}
return jQuery.makeArray( selector, this );
}

可以看到,里面对参数 selector 可能出现的值都做了判断处理。

1.是否为错误的值,如:$(""), $(null), $(undefined), $(false)。

2.是否为字符串。

3.是否为节点元素对象。如:$(this), $(document)。

4.是否为函数。如:$(function(){})。

5.是否为jQuery对象。如:$($(element))。

6.是否为数组或json。

当参数是字符串的时候

if ( typeof selector === "string" ) {
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
match = [ null, selector, null ];
} else {
match = rquickExpr.exec( selector );
} // 创建元素或者选择ID
if ( match && (match[1] || !context) ) { // 创建元素
if ( match[1] ) {
// code // 选择ID
} else {
// code
} // 其他选择器
} else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector );
} else {
return this.constructor( context ).find( selector );
}
}

首先给变量match进行赋值

第一种情况

if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
match = [ null, selector, null ];
}

charAt方法可返回指定位置的字符。符合条件的字符串如:

"<div>",  "<div></div>",  "<div>111</div>"

第二种情况

match = rquickExpr.exec( selector );

rquickExpr前面已经定义过

rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,

这种语法创建了一个RegExp对象

exec方法找到匹配内容后会返回一个数组,包含表达式的完整匹配以及子表达式的匹配等,否则返回null。符合条件的字符串如:

"<div>111",   "#id"

接着看后面的代码:

if ( match && (match[1] || !context) ) {
if ( match[1] ) {
// code 创建元素
} else {
// code 选择ID
}
}

由上面对match的赋值分析可以知道

这里面是针对创建元素和选择id两种情况进行处理,即我们平时这样使用的时候:

$('<div>'), $('#id')

内部又一个if-else语句则分别是对创建元素和选择ID进行处理

下面看处理创建元素部分:

if ( match[1] ) {
context = context instanceof jQuery ? context[0] : context; jQuery.merge( this, jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
) ); if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
for ( match in context ) {
if ( jQuery.isFunction( this[ match ] ) ) {
this[ match ]( context[ match ] );
} else {
this.attr( match, context[ match ] );
}
}
} return this;
}

这里简单介绍一下parseHTML方法和merge方法。

jQuery.parseHTML方法的作用是将字符串转换成节点数组,如:

jQuery.merge方法的作用一般是合并数组

在这里也可以合并json

不过json的形式有一定特殊性,需要是类似这样的:

var obj = {
0 : 'a',
1 : 'b',
length : 2
}

在我们平时使用jQuery选取或创建元素后,jQuery对象中都会为节点元素创建出一个类似数组的结构,方便后续的操作。

继续往后看还有一段代码:

if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
for ( match in context ) {
if ( jQuery.isFunction( this[ match ] ) ) {
this[ match ]( context[ match ] );
} else {
this.attr( match, context[ match ] );
}
}
}

这段代码的作用是给元素标签添加属性,如:

第一个条件

rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,

test() 方法用于检测一个字符串是否匹配某个模式,有则返回true,无返回false。

符合这个正则的字符串如:

"<div>", "<div></div>",也就是单标签。

第二个条件

jQuery.isPlainObject( context ) 判断第二个参数是否为对象字面量。

接着for...in 语句遍历对象中的属性,如果存在与属性同名的方法,就调用此方法(例如上面例子中调用了html方法),否则就调用attr方法。

创建元素就到这里。接下来就是选择id了

if ( match[1] ) {
// code
} else {
elem = document.getElementById( match[2] );
if ( elem && elem.parentNode ) {
// Inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
}

这里就很简单了,直接用getElementById方法获取目标元素,然后就是对应进行赋值,创建之前说过的类似数组的结构。

下面看除了创建元素和选择id之外的情况

if ( match && (match[1] || !context) ) {
// code
} else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector );
} else {
return this.constructor( context ).find( selector );
}

可以看到,不管走后面哪条分支,最终调用的都是find方法,所以,选择类,选择元素和更加复杂的选择器都并没有在init方法中做处理,而是调用了find,这个就到后面再说。

最后我们来看一下参数除了字符串以外其他情况:

if ( typeof selector === "string" ) {
// code
} else if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
} if ( selector.selector !== undefined ) {
this.selector = selector.selector;
this.context = selector.context;
} return jQuery.makeArray( selector, this );

当参数为元素对象或jQuery对象时,对一些属性进行赋值。

当参数为函数时,调用了ready方法,

所以,$(function(){})这种写法算是文档加载$(document).ready(function(){})的一种简写方式。

makeArray方法类似于之前提到的merge方法,一般可以用来把节点元素转换为数组

也可以转换为json,同样第二参数需要是类数组的形式

好了,总结一下, jQuery.fn.init方法对不同类型的参数进行处理,并且参数为字符串时,内部主要对创建元素和选择id作了处理,其他情况则交给find方法,最终构造出一个关于节点元素的类数组结构以及对一些属性的初始化。

Jquery源码中的Javascript基础知识(四)— jQuery.fn.init方法的更多相关文章

  1. Jquery源码中的Javascript基础知识(三)

    这篇主要说一下在源码中jquery对象是怎样设计实现的,下面是相关代码的简化版本: (function( window, undefined ) { // code 定义变量 jQuery = fun ...

  2. Jquery源码中的Javascript基础知识(一)

    jquery源码中涉及了大量原生js中的知识和概念,文章是我在学习两者的过程中进行的整理和总结,有不对的地方欢迎大家指正. 本文使用的jq版本为2.0.3,附上压缩和未压缩版本地址: http://a ...

  3. Jquery源码中的Javascript基础知识(二)

    接上一篇,jquery源码的这种写法叫做匿名函数自执行 (function( window, undefined ) { // code })( window ); 函数定义了两个参数window和u ...

  4. jquery源码中noConflict(防止$和jQuery的命名冲突)的实现原理

    jquery源码中noConflict(防止$和jQuery的命名冲突)的实现原理 最近在看jquery源码分析的视频教学,希望将视频中学到的知识用博客记录下来,更希望对有同样对jquery源码有困惑 ...

  5. jQuery源码中的“new jQuery.fn.init()”什么意思?

    所有文章搬运自我的个人主页:sheilasun.me 引子 最近打算试试看看jQuery的源码,刚开个头就卡住了.无论如何都理解不了jQuery源码入口部分中的 return new jQuery.f ...

  6. jQuery源码中的赌博网站

    前言 jQuery源码中有赌博网站? 起因是公司发的一份自查文件,某银行在日常安全运营过程中发现在部分jQuery源码中存在赌博和黄色网站链接. 链接分为好几个: www.cactussoft.cn ...

  7. 关于jQuery源码中(function(window,undefined){//dosomething()})(window)写法解释

    一.首先是最常见的闭包 (Closure) 范式自执行函数的写法,这里用匿名函数封装(构造块级作用域),避免了匿名函数内部的代码与外部之间发生冲突(如使用了相同的变量名). (function() { ...

  8. jQuery源码逐行分析学习02(第一部分:jQuery的一些变量和函数)

    第一次尝试使用Office Word,方便程度大大超过网页在线编辑,不过初次使用,一些内容不甚熟悉,望各位大神见谅~ 在上次的文章中,把整个jQuery的结构进行了梳理,得到了整个jQuery的简化结 ...

  9. jQuery 源码中的 camelCase

    先看一下源码 //65-72行 // Matches dashed string for camelizing //匹配连字符 ‘-’ 和其后的第一个字母或数字,如果是字母,则替换为大写,如果是数字, ...

随机推荐

  1. UVALive6571 It Can Be Arranged(最小路径覆盖)

    题意:现在有n个课程,每个课程有一定的参与人数,然后每个课程有开始时间和结束时间ai,bi. 而且给定了一个矩阵clean(ij),表示的是上完i课程需要clean[i][j]的时间打扫卫生才能继续上 ...

  2. .htaccess文件的作用(访问控制)

    在线工具: http://www.htaccesseditor.com/sc.shtml 说到.htaccess文件,我想对于wordpress新手或者老手都应该不是很熟悉,也没有多少这方面的概念吧, ...

  3. VS2003 下GridControl的列显示成图片+文字的形式实现

    public RC_CustomerSolicitListUC() { // 该调用是 Windows.Forms 窗体设计器所必需的. InitializeComponent(); // TODO: ...

  4. eclipse创建python项目

    http://jingyan.baidu.com/article/19192ad8173300e53f570757.html

  5. pycharm控制台中文乱码问题

    pycharm控制台中文乱码问题一般是因为之前有配置保存到了文件里, C盘下.pycharm文件夹下有配置文件,删除文件后重装pycharm,配置会重置 不过最后解决问题的做法是删除配置文件后,重新装 ...

  6. converntion

    One convention that we have is to use the names of fruits and vegetables for variables(only in small ...

  7. run fsck manually

    就出现unexpected inconsistency run fsck manually这个问题了. 磁盘出问题,需要用 Fsck修复... 解决方案: 在命令行输入#mount | grep ”o ...

  8. 天使投资、VC 以及 PE 的区别是什么?

    如果满足于“阶段不同”这个简单的回答,那你可能错过了一个思考资本与企业发展之间关系的机会. 首先要交待一下,在大众语境中,angel/VC/PE三者都可认为是VC,也就是人们常说的风险投资,在国内官方 ...

  9. 几个Unicode新知识:扩展ANSI有很多种(256个字符),Unicode表示ANSI字符时高字节为0,Unicode不包括古代字符

    都是有些模糊的概念,特别是Unicode不包括古代字符让我有点惊讶.看来Unicode只适用于大多数情况,一旦有无法表示的字符,那该怎么办呢? ANSI针对英语设计的,当处理带有音调标号(形如汉语的拼 ...

  10. iOS 多线程下安全的使用定时器

    iOS中timer相关的延时调用,常见的有NSObject中的performSelector:withObject:afterDelay:这个方法在调用的时候会设置当前runloop中timer,还有 ...