jQuery源码简析-开篇:jQuery作为模块实现的底层机制

引言:

        要成为一名的优秀的前端工程师,首先最基本的就是要成为一名优秀的“JavaScripter”(杜撰词,意为使用JS编写代码的人)。一名优秀的Javascripter,除了要对JS基础知识如数家珍,更要对JS的运行机制、底层原理了然于心。对于想要在前端长期、深度发展的Javascripter,读懂JS类库源码是前进道路上不可或缺的一关。

        jQuery作为前端发展史上的一个经典类库、前端模块化的起点,对前端发展有不可磨灭的贡献。如今的前端,虽然是框架大行其道,难见jQuery踪影,但jQuery中的很多优秀而经典编程思想依然影响着现在的Javascripters。那么就站在jQuery的肩膀上,开启JS进阶之路。

        写此文章以作为阅读的记录,小标题大部分是曾经产生的疑问。

目录:

        一、为什么引入jQuery后,jQuery中定义的变量不会与同名的全局变量冲突,而且都可以正常使用?

        二、为什么引入jQuery后,能直接以$.xxx或$().xxx的形式调用,而不是定义一个命名空间接收返回值?


一、为什么jQuery中定义的变量不会与同名全局变量冲突而且都可以正常使用?

        答案很简单,是「闭包」,但单纯的知道闭包并没有太大意义,因为在闭包的背后,关系的是前端的发展。

        1995年,网页从静态跨入动态后,后端需要完成页面数据绑定的工作,SSR兴起。在SSR时代,前端要做的工作很少,只需完成页面结构+样式这样简单的工作,绝大部分工作都由后端完成,前端的代码量非常少。这个时代前端还不被重视,甚至前端的活后端人员就能完成。

        AJAX技术出现后,谷歌基于AJAX开发了Gmail和Google Map两款应用,在当时可谓惊艳众人,自此,WEB迎来CSR时代,服务器分层,并且不再负责数据绑定,前后端分离有了雏形。这时的前端不仅要写页面和结构,还要渲染数据,代码量逐渐增多,因此也引发了一个问题:全局变量污染。当时解决这个问题的方法是,使用对象的形式来储存变量,这一操作大量减少了全局变量,只需要有意使用不同的对象名称即可,这里的对象也被称为「命名空间 nameSpace」。使用命名空间的这种方式也叫「单例设计模式」,而在实际开发中,单例设计模式常与闭包一起出现:利用函数私有上下文的特点,需求都在函数内部完成,避免变量污染问题,而函数拥有返回值的特性就能达到暴露内部成员供外部使用的目的命名空间接收函数返回值即可。jQuery实现的核心技术之一就是对函数闭包的使用。

let name = 'window' // 全局变量
let nameSpace = (function () {
  // ...
  let age = "19";
  let name = 'nameSpace' // 同名私有变量
  function sum(a, b) { // 内部方法
    return a + b;
  }
  return {
    //将提供给外部使用的功能、数据等放在对象中返回给命名空间
    sum: sum,
  };
})();
// 外部要使用sum这个功能,只需nameSpace.sum
let res = nameSpace.sum(1, 2);
console.log(res); // => 3
// 私有作用域内的变量全局无法直接访问
console.log(age);// => Uncaught ReferenceError: age is not defined
// 全局变量name不会被污染
console.log(name)// => window

二、为什么引入jQuery.js后,能直接以$.xxx或$().xxx的形式调用,而不是定义一个命名空间接收返回值?

        先思考这样一个问题:为什么document.getElementById()中的document不需要定义就能直接使用?

        如果不知道答案:浏览器执行代码时,是基于window这个对象的,document的实质是全局执行环境window的一个属性,相当于window.document。

        jQuery正是使用了这一点。在「jQuery.js」的尾部有这么一行代码:window.jQuery = window.$ = jQuery; --> 将 jQuery/$挂载到window下,如此就可以直接使用$,那么$.xxx形式的实质就是:对象的xxx属性,$其实就是一个普通的对象。问题又来了,$()等于是对象后加(),但对象是不允许加()的,那$()是什么?

$().xxx/jQuery()

        js中,变量名后跟小括号是函数执行,所以$不仅是普通对象,也是函数,而可以.xxx的不止是对象,$()返回了什么是关键。我们在使用jQuery的过程中知道$()返回的是jQuery的实例,但是要通过构造函数创建实例不应该先new一个jQuery()么?看一段代码

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

        好家伙,一旦调用$(),jQuery 自己就new了一个jQuery.prototype.init的实例并返回,根本不用别人来new,只管拿实例来用就行,我只能说:jQuery牛逼。

        不过问题也来了,实际使用中,都是$().xxx()的形式,实例调用的都是jQuery构造函数原型上的方法,但这里new的并不是jQuery的实例,那么jQuery.prototype上的方法,非jQuery实例是不能调用的,那凭什么还可以$().xxx()?再看一段代码

jQuery.fn = jQuery.prototype = {//一堆代码...}
init.prototype = jQuery.fn;

        以上代码回答了该问题:原型重定向-->面向对象编程的思想,jQuery实现的另一个核心技术就是原型和原型链,而核心思想就是面向对象

        基于闭包、原型、原型链,jQuery就实现了最初的“模块化”。而这些技术和思想,如今的框架也依旧在使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值