jQuery外层包装函数
打开任意一个jQuery的源码js文件,都会看到一个匿名自执行函数,如下代码所示。
//()();自执行函数,定义后立马调用
(function(window, undefined) {
//... ...
})(window);
window是一个全局对象,为什么要把window作为参数传递到框架内部?
- 调用函数栈时,收索变量顺序是从内到外的方式进行。window作为全局对象而言,肯定是最后才收搜到,那么放到内部可以提高速度;
- js是具有压缩版本compress,那么在jQuery内部使用window时,压缩后会变成单个字符,如e,那么所有使用window的地方都将访问不都window内的属性,从而造成语法错误,而将window作为参数传递,即使jQuery内window被压缩为字符e,但e任然指向window。
undefined为什么要作为参数?
- undefined是window下的一个属性,其实在早期的浏览器版本中可以对其进行修改,如IE10以下。 如果外部js环境修改了window.undefined值,那么在函数体内部的undefined判断则不成立。
注释use strict
jQuery为什么注释strict模式? 原因:
- strict模式好处
- 在代码中不能使用一些扩展的保留关键字implements、interface、let、package、private、public、static和yield等;
- with语句不能使用;
- 不能申明或重写eval和arguments两个标识符;
- 不能用delete删除显示申明的标识符、名称或函数;
- 不能申明8进制;
- 如果语法检测时发现语法问题,则整个代码块失效,并导致语法异常,如检测对象中的重复键、未申明变量、重复的函数参数;
- 如果在运行期间出现了违反严格模式的代码,则抛出执行异常。
- strict模式限制
- 必须在全局代码或eval代码或函数申明代码或new Function传入的body开始出引入;
- 限制8进制在IE10以下不支持和FireFox 18以下不支持。
从strict中可以看到好处就是规范js代码的书写规范和语法检查等功能,那么程序员自身能书写规范化的代码前提下使用strict则显得有些画蛇添足。同时有些浏览器本身也不支持strict模式。
jQuery全局变量
在jQuery源码js中的21~94行是var定义的jQuery内的局部全局变量,这里的局部是指jQuery外层包装函数的变量,而全局是jQuery对象而言。包括如下变量:rootjQuery、readyList、core_strundefined、location、document、docElem、_jQuery、_$
、class2type、core_deletedIds、core_version、core_concat、core_push、core_slice、core_indexOf、core_toString、core_hasOwn、core_trim和jQuery、core_pnum、core_rnotwhite、rquickExpr、rsingleTag、rmsPrefix、rdashAlpha、completed等26项。26个变量都起到什么作用是开始阅读源码的起始问题,下面我们根据源码中提供的注释进行翻译。
- rootjQuery 根节点对象
“A central reference to the root jQuery(document)”意思是jQuery(document)返回的根节点对象的reference引用,也即在870行有个赋值语句,如下。
// 870行 All jQuery objects should point back to these
rootjQuery = jQuery(document);
- readyList 用于DOM加载的延迟对象
//826行
readyList = jQuery.Deferred();
- core_strundefined 表示undefined的字符形式 ——
'undefined'
// Support: IE9 表示IE6/7/8都不支持在xml文档节点中通过
//xmlNode.method !== undefined方式来检查method是否为undefined
// For `typeof xmlNode.method` instead of`xmlNode.method !== undefined`
core_strundefined = typeof undefined
- window参数对应的属性简写
location = window.location, //URL地址对象
document = window.document, //文档对象
docElem = document.documentElement, //文档HTML元素对象
_jQuery、_$
保存外部jQuery、$
//356行中的noConflict中,解决外部定义$、jQuery对组件内部的影响。
noConflict: function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
}
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
},
- class2type 一个object的对象字面量,用于存储类型简写键值对。
//847行,将常用类型进行组装成toString类型的键值对缓存
// Populate the class2type map
jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
});
- jQuery版本和通用方法简写
//缓存被删除的
core_deletedIds = [],
core_version = "2.0.3", //jQuery版本
//通过存储对象方法的引用来提高函数查找速度
core_concat = core_deletedIds.concat,
core_push = core_deletedIds.push,
core_slice = core_deletedIds.slice,
core_indexOf = core_deletedIds.indexOf,
core_toString = class2type.toString,
core_hasOwn = class2type.hasOwnProperty,
core_trim = core_version.trim,
- 正则表达式,用于基本的工具表达式
//用于检测数字表达式,如12,12.9,12e10,12.3e3
core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
//用于检测非空白字符,这里\S其实已经一目了然
core_rnotwhite = /\S+/g,
//一种检测选择器是否HTML字符串的正则表达式,关键在于下面的两句话:Prioritize #id over <tag> to avoid XSS via location.hash (#9521);Strict HTML recognition (#11290: must start with <)
//两个子表达式/^(?:\s*(<[\w\W]+>)[^>]*$/和/^#([\w-]*))$/分别是检测HTML字符串、#id选择器
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
//匹配单标签HTML元素,如<input/>、<div></div>
rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
//ms表示micro soft,大家应该明白这是啥意思
rmsPrefix = /^-ms-/,
//匹配虚线后的单字符,数据0-9和小写字母a-z
rdashAlpha = /-([\da-z])/gi,
- camel字符转换函数fcamelCase
//将虚线转换为camel方式的字符,如"a-d"为"a-D",而
fcamelCase = function( all, letter ) {
return letter.toUpperCase();
},
//556行,将字符串转换为camel形式的字符串
camelCase: function( string ) {
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
},
- ready事件处理器complete
completed = function() {
//首次清除load加载事件,然后在手动调用jQuery.ready函数
document.removeEventListener( "DOMContentLoaded", completed, false );
window.removeEventListener( "load", completed, false );
jQuery.ready();
};
- jQuery对象构造器
一般封装组件的构造器是是如何做呢?
//定义组件函数
function myjQuery () {
this.name = "myjQuery";
}
//给组件添加功能
myjQuery.prototype.init = function() {
//初始化组件
}
//先创建,在初始化组件
var myjQueryObj = new myjQuery();
myjQueryObj.init();
在使用jQuery时,jQuery(…)或$(….)获取jQuery对象,那么jQuery对象是如何创建的?下面的代码看出jQuery对象实际是jQuery.fn.init的对象,而jQuery.fn = jQuery.prototype,所以jQuery对象实际是jQuery原型对象函数属性的对象。
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
},
总结
jQuery前期定义了许多变量,有函数、正则表达式和常量。这些变量在jQuery框架中发挥了全局作用,在jQuery框架中作为效率、安全和简便的工具。其中jQuery函数是jQuery框架的构造器,从其中看出jQuery在构造对象独特方式所带来编程的体验感好处。