jQuery源码初探(1)

来源:互联网 发布:c语言大括号的用法 编辑:程序博客网 时间:2024/06/05 20:31

前言

本人也是刚入坑的一枚小白,到现在差不多快一年了啊…
对于前端的同志来说,jQuery应该是再熟悉不过了吧,因为就目前来看,80%左右的网站或多或少的都直接或间接引用jQuery,可以毫不客气地说它目前来说最流行的,面向对象的JavaScript框架,因为平时使用频率很高,所以也就萌生了阅读源码的想法,并结合自己的目前知识,照着源码一点点的分析吧…
(ps:本人前端小白,也是最近才开始阅读源码,边读边写,所以如果有分析不对或者分析不当的地方,还请谅解,也会很乐意接收大家的批评和指正..)

下面进入正题吧

1. 本文分析jQuery版本为3.0.0版本,在官网上下载对应未压缩版即可(jQuery官网)
2. 转载请注明出处

ok;打开jQuery-3.0.0的源码我们发现,一开始就是这么一段代码

( function( global, factory ) {    "use strict";    if ( typeof module === "object" && typeof module.exports === "object" ) {        module.exports = global.document ?            factory( global, true ) :            function( w ) {                if ( !w.document ) {                    throw new Error( "jQuery requires a window with a document" );                }                return factory( w );            };    } else {        factory( global );    }}( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {    /******此处省略若干行*******/}));

一开始看的时候,可能会找不到 function( window , noGlobal){} 这个函数的结束部分,其实,这个函数是jQuery的主体,贯穿整个jQuery的框架,我们所使用的所有的jQuery方法都是写在这个部分。

我们先抛开里面的代码不看,只看外部的框架,我们可以将其简化为

( function( global, factory ) {    /******此处省略若干行*******/}( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {    /******此处省略若干行*******/}));

这种写法叫做IIFE (immediately-invoked function expression),也叫‘’立即执行函数‘’‘’即时执行方法‘’等,意思就是函数会在创建完成的时候自动执行一次,一般来说写法有主要有两种写法:

  1. 第一种:就如同jQuery写法一样
    ( function( a , b , c ){        /***执行的代码***/    }( 参数1 , 参数2 , 参数3 ) );
  1. 第二种
    ( function( a , b , c ){        /***执行的代码***/    })( 参数1 , 参数2 , 参数3 );

这两种写法 参数1,参数2,参数3分别对应的匿名函数的 a , b , c;

ok,问题来了,为什么jQuery要采用IIFE?那么使用IIFE有什么好处?

因为在ES6以前,JS是没有块级作用域的概念,只有函数作用域,作为一种对块级作用域的模拟就只能用function模拟,就是为了使模块相互独立,降低模块间的耦合性,避免全局作用域的污染和全局变量的冲突。

举个例子

    /**用IIFE创建一个闭包**/    var foo = (function(){        var txt = "hello";        return {            get: function(){                return txt             },            set: function( val ){                txt = val            }        }    })();    console.log( foo.get() ); // 'hello'    foo.set( 'world' );    console.log( foo.get() ); // 'world'    foo.txt;             //'undefinded'    console.log( txt )  // 'ReferenceError : txt is not defined'

可以看出,我们就是可以通过 导出方法 从函数外部的外部去更改 改变函数内部变量的值,所以就可以利用这个特点来隔离作用域,模拟一种“私有”的效果,jQuery正是利用这一点,在我们调用jQuery代码时,保护jQuery内部变量。(ps:如果有不熟悉的同学,可以去看看作用域链和闭包的相关知识哈~)

好的,我们回到上面jQuery的部分,

( function( global, factory ) {    /******此处省略若干行*******/}( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {    /******此处省略若干行*******/}));

在函数 参数 global 中 , jQuery采用了 一个三元运算符去赋值

typeof window !== "undefined" ? window : this

首先用 typeof 来判断 当前的 window 存不存在 , 如果存在 , 就将 window对象传入 , 否在就传入this对象。jQuery之所以这么写,是因为 global 如果是在浏览器环境就是 window , 如果不是在浏览器环境则是其他的全局对象,这样 传递this可以保存当前的上下文环境;

接下来理一理这一部分代码。

这里写图片描述

我直接截取了源码的一段

首先我们 看这个判断 :

 if ( typeof module === "object" && typeof module.exports === "object" ) 

结合注释,我们 能大概看懂, 这一段判断是 为了 兼容 commonjs 或者 类似 commonjs 规范的一些框架;
了解过node.js的同学应该能看出来 module.exports 是 node.js 中用来创建模块的方法,那么可以理解为如果这个条件成立,那么 首先判断当前的环境是否支持 global.document 属性 , 也就是window.document 属性 , 如果支持 , 我们调用

 `factory( global, true ) { /* jQuery code * / }`

将 jQuery 的方法绑定到当前模块上,

如果 window.document 不存在呢? 直接调下面的方法

    function( w ) {        if ( !w.document ) {            throw new Error( "jQuery requires a window with a document" );        }        return factory( w );    };

该方法抛出一个异常 , 告诉用户 jQuery 需要 window.document 环境 , 并依旧返回 factory( w ) 方法(ps:其实 我也不知道 为什么 不支持 ,还要返回 factory( w ) 方法 , 0.0 );

如果

 if ( typeof module === "object" && typeof module.exports === "object" ) 

这个条件不成立,也就是我们 一般 遇到的情况,(一般情况下,typeof module 都是 ‘undefined’),
这样就好办了,直接调用 factory( global ) 将 jQuery 方法引入到我们当前的执行环境中…

不知不觉也码了不少字了,开篇部分就先到这里吧,后面我继续学习,在继续更新吧~ :)

2 1