jQuery 的源码看过吗?能不能简单概况一下它的实现原理?
jQuery 的源码看过吗?能不能简单概况一下它的实现原理?
1、闭包机制;
// 以下截取自 jquery 源码片段
(function( window, undefined ) {
/* 源码内容 */
})( window );
上面这一小段代码来自于 1.9.0 当中 jquery 的源码,它是一个无污染的 JS 插件的标准写法,专业名词叫闭包。可以把它简单的看做是一个函数,与普通函数不同的是,这个函数没有名字,而且会立即执行
我们将里面的变量变成了局域变量,这不仅可以提高运行速度,更重要的是我们在引用 jquery 的 JS 文件时,不会因为 jquery 当中的变量太多,而与其它的 JS 框架的变量命名产生冲突;闭包中的变量声明没有污染到外面的全局变量;;
2、作为全局的一个属性;
window.jQuery = window.$ = jQuery;
这一句话将我们在闭包当中定义的 jQuery 对象导出为全局变量 jQuery 和 $,因此我们才可以在外部直接使用 jQuery 和 $。
window 是默认的 JS 上下文环境,因此将对象绑定到 window 上面,就相当于变成了传统意义上的全局变量,
3、最核心的功能,就是选择器;
首先我们进入 jquery 源码中,可以很容易的找到 jquery 对象的声明,看过以后会发现,原来我们的 jquery 对象就是 init 对象。
jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
}
这里出现了 jQuery.fn 这样一个东西,它的由来可以在 jquery 的源码中找到,它其实代表的就是 jQuery 对象的原型。
jQuery.fn = jQuery.prototype;
jQuery.fn.init.prototype = jQuery.fn;
这两句话,第一句把 jQuery 对象的原型赋给了 fn 属性,第二句把 jQuery 对象的原型又赋给了 init 对象的原型。也就是说,init 对象和 jQuery 具有相同的原型,因此我们在上面返回的 init 对象,就与 jQuery 对象有一样的属性和方法。
我们不打算深究 init 这个方法的逻辑以及实现,但是我们需要知道的是,jQuery 其实就是将 DOM 对象加了一层包裹,而寻找某个或者若干个 DOM 对象是由 sizzle 选择器负责的,
jQuery 对象有很多的属性和方法;对于属性来说,我们最需要关注的只有一个属性,就是 [0]
属性,[0]
其实就是原生的 DOM 对象。
很多时候,我们在 jQuery 和 DOM 对象之间切换时需要用到 [0]
这个属性。
从截图也可以看出,jQuery 对象其实主要就是把原生的 DOM 对象存在了 [0]
的位置,并给它加了一系列简便的方法。
这个索引 0 的属性我们可以从一小段代码简单的看一下它的由来,下面是 init 方法中的一小段对 DOMElement 对象作为选择器的源码。
// Handle $(DOMElement)
if ( selector.nodeType ) {
/* 可以看到,这里将 DOM 对象赋给了 jQuery 对象的 [0] 这个位置 */
this.context = this[0] = selector;
this.length = 1;
return this;
}
这一小段代码可以在 jquery 源码中找到,它是处理传入的选择参数是一个 DOM 对象的情况。
可以看到,里面很明显的将 jQuery 对象索引 0 的位置以及 context 属性,都赋予了 DOM 对象
。代码不仅说明了这一点,也同时说明了,我们使用 $(DOMElement) 可以将一个 DOM 对象转换为 jQuery 对象,从而通过转换获得 jQuery 对象的简便方法。
4、ready 方法
$(function(){})
或者是 ready
方法;
实现类似 jquery 的 ready 方法的效果我们是可以简单做到的,它的实现原理就是,维护一个函数数组,然后不停的判断 DOM 是否加载完毕,倘若加载完毕就触发所有数组中的函数。
遵循着这一思想,LZ 拿出很久之前写的一个小例子,来给各位看一下。
(function( window, undefined ) {
var jQuery = {
isReady:false,// 文档加载是否完成的标识
readyList:[],// 函数序列
//onload 事件实现
ready : function(fn){
// 如果是函数,加入到函数序列
if(fn && typeof fn == 'function' ){
jQuery.readyList.push(fn);
}
// 文档加载完成,执行函数序列。
if(jQuery.isReady){
for(var i = 0;i < jQuery.readyList.length ;i++){
fn = jQuery.readyList[i];
jQuery.callback(fn);
}
return jQuery;
}
},
// 回调
callback : function(fn){
fn.call(document,jQuery);
}
};
// 导出对象
window.$ = window.jQuery = jQuery;
// 判断加载是否完成
var top = false;
try {
top = window.frameElement == null && document.documentElement;
} catch(e) {}
if ( top && top.doScroll ) {
(function doScrollCheck() {
try {
top.doScroll("left");
jQuery.isReady = true;
jQuery.ready();
} catch(e) {
setTimeout( doScrollCheck, 50 );
}
})();
}
}(window));
这段代码是 LZ 从之前的例子摘出来的,它的实现逻辑非常简单,但是可以达到 jQuery 的 ready 方法的效果,
5、extend 方法
简单说两个 extend 方法的常用方式。
- 1、使用 jQuery.fn.extend 可以扩展 jQuery 对象,使用 jQuery.extend 可以扩展 jQuery,前者类似于给类添加普通方法,后者类似于给类添加静态方法。
- 2、两个 extend 方法如果有两个 object 类型的参数,则会将后面的参数对象属性扩展到第一个参数对象上面,扩展时可以再添加一个 boolean 参数控制是否深度拷贝。
更多面试题
如果你想了解更多的前端面试题,请点击下面进行选择,这里基本包涵了市场上的所有前端方面的面试题,让你面试更加顺利。
- HTML 面试题
- CSS 面试题
- JavaScript 面试题
- jQuery 面试题
- Vue.js 面试题
- React 面试题
- 算法 面试题
- AJAX/HTTP 面试题
- Babel 面试题
- BootStrap 面试题
- Electron 面试题
- Gulp 面试题
- Node.js 面试题
- 前端经验相关 面试题
- 前端综合 面试题
- Webpack 面试题
- 微信小程序 面试题
这些题库还在更新中,如果你有不错的面试题库欢迎分享给我,我整理后放上来;人人为我,我为人人,互帮互助,共同提高,祝大家都拿到心仪的Offer!