随着JavaScript本身的完善,越来越多的人喜欢使用原生JavaScript开发,而不是各种库,其中不少人提出了用原生JavaScript替换jQuery的需求。这不是坏事,但也未必是好事。如果你真的想去掉前端依赖库中的jQuery,建议你慎重考虑。首先jQuery是一个第三方库。库的价值之一是它极大地简化了开发。一般来说,第三方库都是通过原生语言特性和基础API库来实现的。因此,理论上,任何第三方库都可以被原生语言特性替代。问题是值不值得?jQuery的作用引用了jQuery官网的一段话:jQueryisafast,small,andfeature-richJavaScriptlibrary。它使用可跨多种浏览器工作的易于使用的API,使HTML文档遍历和操作、事件处理、动画和Ajax等事情变得更加简单。这段话非常谦虚地介绍了jQuery在处理DOM和跨浏览器方面的贡献。其实这也是我们选择jQuery的主要原因,并且使用它自带的一些工具,比如数组工具,Deferred等。对我来说,最常用的功能包括在DOM树中查询,修改DOM树和DOM相关的操作,事件处理,AjaxDeferred和Promise对象和数组处理,还有一个我一直在用但是做列表的时候很难想到的——跨浏览器谁在代替谁?上面提到的所有功能都可以在本地代码中实现。本质上,jQuery是用来代替native实现,达到减少代码,增强可读性的目的——那么,到底是用jQuery代替native代码,还是用native代码代替jQuery呢?这种因果关系能理解吗?当我看到用的是querySelectorAll()而不是$()时,我不禁在想,jQuery一个字符就可以解决了,为什么要写十六个字符呢?大多数浏览器都实现了$(),但是你在写原生代码的时候会考虑$()的浏览器兼容性吗?jQuery已被考虑!当我看到一大堆创建DOM结构的原生JavaScript代码时,我不禁想到jQuery只需要一个方法链就可以解决。我什至可以使用类似HTML结构的代码(包括缩进),比如这段代码使用document.createElement()实现完全没有问题,但是代码量要大很多,而且会有很多重复(或类似的)代码。当然,把这些重复的代码抽离出来写成函数也是可以的……不过jQuery已经做到了。请注意,拼写HTML的方法确实很弱,容易出错且难以阅读。如果你有ES6的字符串模板,用它来写HTML也是个好主意。就DOM操作而言,jQuery仍然是一个非常有用的工具。这是jQuery取代原生JavaScript,过去是,现在仍然是。没落的jQuery效用函数2006年发明jQuery时,还没有ES5(2011年6月发布)。即使在ES5发布很久之后,也并非所有浏览器都支持它。因此,在这一时期,除了DOM操作之外,jQuery的巨大贡献在于解决了跨浏览器的问题,并提供了方便的对象和数组操作工具,如each()、index()、filter。现在ECMAScript刚刚发布了2017标准,浏览器标准混淆的问题得到了很好的解决。前端界还有Babel等翻译工具和TypeScript等新语言。所以现在大家可以放心的使用各种新的语言特性,即使ECMAScript的相关标准还在制定中。在这期间,jQuery提供的大量工具和方法已经有了原生的替代品——在使用差异不大的情况下,我更倾向于使用原生实现。其实jQuery也是在尽可能的使用native实现来提高执行效率。jQuery并没有放弃这些原生实现的工具功能/方法,主要是为了向后兼容,一如既往地提供浏览器兼容性——毕竟不是每个使用jQuery的开发者都会使用翻译工具。嗯,对于JavaScript开发人员来说,jQuery确实有许多实用方法可以被原生JavaScript函数/方法替代。比如$.parseJSON()可以用JSON.parse()代替,而JSON.stringify()也弥补了jQuery没有$.toJSON()的不足;$.extend()的部分功能可以用Object.assign()代替`$.fn中的一些数据处理工具方法,如each()、index()等,可以用Array中对应的工具方法代替.prototype,例如forEach()、indexOf()等。$.Deferred()和jQueryPromises在某些情况下可以用原生Promises代替。它们在ES6之前是非常好的Promise实现。......$.fn就是jQuery.prototype,也就是jQuery对象的原型。所以在它上面定义的方法是jQuery对象的方法。这些工具和方法在原生JavaScript中已经逐渐得到补充和完善,但仍然只能在某些情况下被替代...因为jQuery对象是一种独特的数据结构,为jQuery本身创建的工具和方法作用于jQuery对象时会有是一些具体的实现——既然DOM操作还是离不开jQuery,那么这些方法就不能被完全替代。jQuery和本机JavaScript的组合有时需要jQuery,有时则不需要。如何区分?jQuery的优势在于它的DOM操作、Ajax和跨浏览器。如果项目中引入了jQuery,多半是因为对这些功能的需求。至于不操作DOM,不需要考虑跨浏览器的部分(比如翻译工具),尽量考虑用原生JavaScript实现。这样一来,jQuery和原生JavaScript肯定有交集,所以不得不说一下需要注意的地方。jQuery对象实现了一些数组函数的伪数组。首先要注意的是jQuery对象是伪数组,是对原生数组或者伪数组(比如DOM节点列表)的封装。如果想获取一个元素,可以使用[]操作符或者get(index)方法;如果想得到一个包含所有元素的数组,可以使用toArray()方法,或者通过ES6引入的Array.from()进行转换。注意each/map和forEach/map回调函数的参数顺序。jQuery在$.fn上定义的each()和map()方法对应于在Array.prototype上定义的原生方法forEach()和map()。它们的参数都是回调函数,只是它们的回调函数定义在细节上有些差异。$.fn.each()的回调定义如下:Function(Integerindex,Elementelement)回调的第一个参数为数组元素的位置(序号,从0开始),第二个参数为元素本身。Array.prototype.forEach()的回调定义是Function(currentValue,index,array)回调的第一个参数是数组元素本身,第二个参数是元素的位置(序号)。而这个回调还有第三个参数,是对整个数组的引用。请特别注意两个回调定义的第一个参数和第二个参数的含义,完全互换,jQuery和native代码混用时容易出错。$.fn.map()和Array.prototype.map()的回调也是如此,由于这两个方法同名,出错的几率更大。请注意,each()/map()中的this$.fn.each()和$.fn.map()回调经常使用this,它指向当前数组元素。正是因为这种方便,jQuery在定义返回元素时,并没有把元素本身作为第一个参数,而是把序号作为第一个参数。但是ES6带来了箭头函数。箭头函数最常见的用途是回调。箭头函数中的this是相对于箭头函数定义的上下文的,不像普通函数中的this是相对于调用者的。现在问题来了,如果使用箭头函数作为$.fn.each()或$.fn.map()的回调,需要特别注意this的使用——箭头函数中的this是不再是元素本身。针对这个问题,建议在非必要情况下,使用函数表达式作为$.fn.each()和$.fn.map()的回调,保持原有的jQuery编程习惯。如果你真的需要使用箭头函数来引用上下文this,记得使用它的回调定义的第二个参数作为元素引用而不是this。$.fn.map()不返回数组。与Array.prototype.map()不同,$.fn.map()返回的不是一个数组,而是一个jQuery对象,是一个伪数组。如果需要获取原生数组,可以使用toArray()或Array.from()输出。jQueryPromisejQuery是由$.Deferred()实现的Promise函数。在ES6之前,如果引用jQuery,基本不需要专门引用一个Promise库。jQuery已经实现了Promise的基本功能。不过jQueryPromise虽然实现了then(),但是并没有实现catch(),所以不兼容原生的Promise,但是async/awaitforco或者ES2017没有压力。jQuery的Promise虽然没有catch(),但是提供了fail事件处理,在Deferredreject()时触发。相应的,有done事件,在Deferredresovle()时触发,还有always事件,无论什么情况都会触发。与一次性的then()不同,一个事件可以注册多个handler,当事件被触发时,相应的handler会依次执行。另外,事件是不可传递的,所以fail()不能写在then()链的末尾。结论总的来说,在大量操作DOM的前端代码中使用jQuery可以带来极大的便利,同时也使得操作DOM的相关代码更易于阅读。另一方面,原生JavaScript带来的新特性确实可以替代jQuery的一些工具函数/方法,减少项目对jQuery的依赖。jQuery和原生JavaScript应该是共生的,而不是相互排斥的。应该在合适的时间选择合适的方法,而不是绝对要用人来代替人。
