为什么原生 JavaScript 开发越来越多受欢迎?是否应该跟风用原生JavaScript代替 jQuery等库?

本文标签:  jQuery的作用 原生JavaScript优势 jQuery官网 jQuery处理DOM和跨浏览器 JavaScript新特性 互联网杂谈

随着 JavaScript 本身的完善,越来越多的人开始喜欢使用原生 JavaScript 开发代替各种库,其中不少人发出了用原生 JavaScript 代替 jQuery 的声音。这并不是什么坏事,但也不见得就是好事。如果你真的想把 jQuery从前端依赖库中移除掉,我建议你慎重考虑。

首先 jQuery 是一个第三方库。库存在的价值之一在于它能极大地简化开发。一般情况下,第三方库都是由原生语言特性和基础 API 库实现的。因此,理论上来说,任何库第三方库都是可以用原生语言特性代替的,问题在于是否值得?

jQuery 的作用

引用一段 jQuery 官网的话:

jQuery is a fast, small, and feature-rich JavaScript library. It makes things like HTML document traversal and manipulation,event handlinganimation, and Ajax much simpler with an easy-to-use API that works across a multitude of browsers.

这一段话很谦虚的介绍了 jQuery在处理 DOM 和跨浏览器方面做出的贡献。而事实上,这也正是我们选用 jQuery 的主要原因,并顺带使用了它带来的一些工具,比如数组工具,Deferred 等。

对于我来说,最常用的功能包括

  • 在 DOM 树中进行查询
  • 修改 DOM 树及 DOM 相关操作
  • 事件处理
  • Ajax
  • Deferred 和 Promise
  • 对象和数组处理
  • 还有一个一直在用却很难在列清单时想到的——跨浏览器

到底是谁在替代谁?

上面提到的所有功能都能用原生代码来实现。从本质上来说,jQuery 就是用来代替原生实现,以达到减少代码,增强可读性的目的的——所以,到底是用 jQuery 代替原生代码,还是用原生代码代替 jQuery?这个先后因果关系可否搞明白?

我看到说用 querySelectorAll() 代替 $() 的时候,不禁在想,用 jQuery 一个字符就能解决的,为什么要写十六个字符?大部分浏览器是有实现 $(),但是写原生代码的时候你会考虑 $() 的浏览器兼容性吗?jQuery 已经考虑了!

我看到一大堆创建 DOM 结构的原生 JavaScript代码的时候,不禁在想,用 jQuery 只需要一个方法链就解决了,我甚至可以用和 HTML 结构类似的代码(包含缩进),比如

1 // 创建一个 ul 列表并加在 #container 中
2 $("<ul>").append(
3     $("<li>").append(
4         $("<a>").attr("href", "#").text("first")),
5     $("</a></li><li><a>").append(
6         $("</a><a>").attr("href", "#").text("second")),
7     $("</a></li><li><a>").append(
8         $("</a><a>").attr("href", "#").text("third"))
9 ).appendTo($("#container"));</a></li></ul>

这段代码用 document.createElement() 来实现完全没有问题,只不过代码量要大得多,而且会出现大量重复(或类似)的代码。当然是可以把这些重复代码提取出来写成函数的……不过 jQuery 已经做了。

注,拼 HTML 的方法实在弱爆了,既容易出错,又不易阅读。如果有 ES6 的字符串模板之后,用它来写 HTML 也是个不错的主意。

就 DOM 操作这一部分来说,jQuery 仍然是一个非常好用的工具。这是 jQuery 替代了原生 JavaScript,以前如此,现在仍然如此。

没落的 jQuery 工具函数

jQuery 2006 年被发明出来的时候,还没有 ES5(2011年6月发布)。即使在 ES5 发布之后很长一段时间里,也不是所有浏览器都支持。因此在这一时期,除 DOM 操作外,jQuery 的巨大贡献在于解决跨浏览器的问题,以及提供了方便的对象和数组操作工具,比如each()index() 和 filter 等。

如今 ECMAScript 刚刚发布了 2017 的标准,浏览器标准混乱的问题也已经得到了很好的解决,前端界还出现了 Babel 这样的转译工具和 TypeScript 之类的新语言。所以现在大家都尽可放心的使用各种新的语言特性,哪怕 ECMAScript 的相关标准还在制定中。在这一时期,jQuery 提供的大量工具方法都已经有了原生替代品——在使用上差别不大的情况下,确实宁愿用原生实现。

事实上,jQuery 也在极尽可能地采用原生实现,以提高执行效率。jQuery 没有放弃这些已有原生实现的工具函数/方法,主要还是因为向下兼容,以及一如既往的提供浏览器兼容性——毕竟不是每一个使用 jQuery 的开发者都会使用转译工具。

那么,对于 JavaScript 开发者而言,jQuery确实有很多工具方法可以被原生 JavaScript 函数/方法替代。比如

  • $.parseJSON() 可以用 JSON.parse() 替代,而且 JSON.stringify() 还弥补了 jQuery 没有 $.toJSON() 的不足;
  • $.extend() 的部分功能可以由 Object.assign() 替代`
  • $.fn 的一些数据处理工具方法,比如 each()index() 等都可以用 Array.prototype 中相应的工具方法替代,比如forEach()indexOf() 等。
  • $.Deferred() 和 jQuery Promise 在某些情况下可以用原生 Promise 替代。它们在没有 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() 来转换。

01 // 将普通数组转换成 jQuery 对象
02 const jo = $([1, 2, 3]);
03 jo instanceof jQuery;   // true
04 Array.isArray(jo);      // false
05  
06 // 从 jQuery 对象获取元素值
07 const a1 = jo[0];       // 1
08 const a2 = jo.get(1);   // 2
09  
10 // 将 jQuery 对象转换成普通数组
11 const arr1 = jo.toArray();      // [1, 2, 3]
12 Array.isArray(arr1);            // true
13 const arr2 = Array.from(jo);    // [1, 2, 3]
14 Array.isArray(arr2);            // true

注意 each/map 和 forEach/map 回调函数的参数顺序

jQuery 定义在 $.fn 上的 each() 和 map() 方法与定义在 Array.prototype 上的原生方法 forEach() 和 map() 对应,它们的参数都是回调函数,但它们的回调函数定义有一些细节上的差别。

$.fn.each() 的回调定义如下:

Function(Integer index, Element element )

回调的第一个参数是数组元素所在的位置(序号,从 0 开始),第二个参数是元素本身。

而 Array.prototype.forEach() 的回调定义是:

Function(currentValue, index, array)

回调的第一个参数是数组元素本身,第二个参数才是元素所有的位置(序号)。而且这个回调有第三个参数,即整个数组的引用。

请特别注意这两个回调定义的第一个参数和第二个参数,所表示的意义正好交换,这在混用 jQuery 和原生代码的时候很容易发生失误。

对于 $.fn.map() 和 Array.prototype.map() 的回调也是如此,而且由于这两个方法同名,发生失误的概率会更大。

注意 each()/map() 中的 this

$.fn.each() 和 $.fn.map() 回调中经常会使用 this,这个 this 指向的就是当前数组元素。正是因为有这个便利,所以 jQuery 在定义回请贩时候没有把元素本身作为第一个参数,而是把序号作为第一个参数。

不过 ES6 带来了箭头函数。箭头函数最常见的作用就是用于回调。箭头函数中的 this 与箭头函数定义的上下文相关,而不像普通函数中的 this 是与调用者相关。

现在问题来了,如果把箭头函数作为 $.fn.each() 或 $.fn.map() 的回调,需要特别注意 this 的使用——箭头函数中的 this 不再是元素本身。鉴于这个问题,建议若非必要,仍然使用函数表达式作为 $.fn.each() 和 $.fn.map() 的回调,以保持原有的 jQuery 编程习惯。实在需要使用箭头函数来引用上下文 this 的情况下,千万记得用其回调定义的第二个参数作为元素引用,而不是this

1 // 将所有输入控制的 name 设置为其 id
2 $(":input").each((index, input) => {
3     // const $input = $(this) 这是错误的!!!
4     const $input = $(input);
5     $input.prop("name", $input.prop("id"));
6 });

$.fn.map() 返回的并不是数组

与 Array.prototype.map() 不同,$.fn.map() 返回的不是数组,而是 jQuery 对象,是伪数组。如果需要得到原生数组,可以采用toArray() 或 Array.from() 输出。

01 const codes = $([97, 98, 99]);
02 const chars = codes.map(function() {
03     return String.fromCharCode(this);
04 });     // ["a", "b", "c"]
05  
06 chars instanceof jQuery;    // true
07 Array.isArray(chars);       // false
08  
09 const chars2 = chars.toArray();
10 Array.isArray(chars2);      // true

jQuery Promise

jQuery 是通过 $.Deferred() 来实现的 Promise 功能。在 ES6 以前,如果引用了 jQuery,基本上不需要再专门引用一个 Promise 库,jQuery 已经实现了 Promise 的基本功能。

不过 jQuery Promise 虽然实现了 then(),却没有实现 catch(),所以它不能兼容原生的 Promise,不过用于 co 或者 ES2017 的async/await 毫无压力。

1 // 模拟异步操作
2 function mock(value, ms = 200) {
3     const d = $.Deferred();
4     setTimeout(() => {
5         d.resolve(value);
6     }, ms);
7     return d.promise();
8 }
01 // co 实现
02 co(function* () {
03     const r1 = yield mock(["first"]);
04     const r2 = yield mock([...r1, "second"]);
05     const r3 = yield mock([...r2, "third"]);
06     console.log(r1, r2, r3);
07 });
08  
09 // [‘first‘]
10 // [‘first‘, ‘second‘]
11 // [‘first‘, ‘second‘, ‘third‘]
01 // async/await 实现,需要 Chrome 55 以上版本测试
02 (async () => {
03     const r1 = await mock(["first"]);
04     const r2 = await mock([...r1, "second"]);
05     const r3 = await mock([...r2, "third"]);
06     console.log(r1, r2, r3);
07 })();
08  
09 // [‘first‘]
10 // [‘first‘, ‘second‘]
11 // [‘first‘, ‘second‘, ‘third‘]

虽然 jQuery 的 Promise 没有 catch(),但是提供了 fail 事件处理,这个事件在 Deferred reject() 的时候触发。相应的还有done 事件,在 Deferred resovle() 的时候触发,以及 always 事件,不论什么情况都会触发。

与一次性的 then() 不同,事件可以注册多个处理函数,在事件触发的时候,相应的处理函数会依次执行。另外,事件不具备传递性,所以 fail() 不能在写在 then() 链的最后。

结语

总的来说,在大量操作 DOM 的前端代码中使用 jQuery 可以带来极大的便利,也使 DOM 操作的相关代码更易读。另一方面,原生 JavaScript 带来的新特性确实可以替代 jQuery 的部分工具函数/方法,以降低项目对 jQuery 的依赖程序。

jQuery 和原生 JavaScript 应该是共生关系,而不是互斥关系。应该在合适的时候选用合适的方法,而不是那么绝对的非要用谁代替谁。

  1. 写在最后:FOR Freedom 看看外边的世界,以及IT这一行,少不了去Google查资料,最后,安利一个V——PN代理。一枝红杏 VPN,去Google查资料是绝对首选,连接速度快,使用也方便。我买的是99¥一年的,通过这个链接(http://my.yizhihongxing.com/aff.php?aff=2509)注册后输上会员中心得优惠码,平摊下来,每月才7块钱,特实惠。

    本文标签:  jQuery的作用 原生JavaScript优势 jQuery官网 jQuery处理DOM和跨浏览器 JavaScript新特性 互联网杂谈

    转自 SUN‘S BLOG - 专注互联网知识,分享互联网精神!

    原文地址 : 为什么原生 JavaScript 开发越来越多受欢迎?是否应该跟风用原生JavaScript代替 jQuery等库?

    相关阅读:Aaron Swartz – 互联网天才开挂的人生历程:每时每刻都问自己,现在这世界有什么最重要的事是我能参与去做的?
    相关阅读:网站环境apache + php + mysql 的XAMPP,如何实现一个服务器上配置多个网站?

    相关阅读:什么是工程师文化?各位工程师是为什么活的?作为一个IT或互联网公司为什么要工程师文化?

    相关阅读: 对程序员有用:2017最新能上Google的hosts文件下载及总结网友遇到的各种hosts问题解决方法及配置详解

    相关阅读:win10永久激活教程以及如何查看windows系统是不是永久激活?

    相关BLOG:SUN’S BLOG - 专注互联网知识,分享互联网精神!去看看:www.whosmall.com

原文地址:http://whosmall.com/?post=196

时间: 2024-10-05 05:32:40

为什么原生 JavaScript 开发越来越多受欢迎?是否应该跟风用原生JavaScript代替 jQuery等库?的相关文章

React Native Android原生模块开发实战|教程|心得|如何创建React Native Android原生模块

尊重版权,未经授权不得转载 本文出自:贾鹏辉的技术博客(http://blog.csdn.net/fengyuzhengfan/article/details/54691503) 前言 一直想写一下我在React Native原生模块封装方面的一些经验和心得,来分享给大家,但实在抽不开身,今天看了一下日历发现马上就春节了,所以就赶在春节之前将这篇博文写好并发布(其实是两篇:要看iOS篇的点这里<React Native iOS原生模块开发>). 我平时在用React Native开发App时会

React Native iOS原生模块开发实战|教程|心得|如何创建React Native iOS原生模块

尊重版权,未经授权不得转载 本文出自:贾鹏辉的技术博客(http://blog.csdn.net/fengyuzhengfan/article/details/54691432) 前言 一直想写一下我在React Native原生模块封装方面的一些经验和心得,来分享给大家,但实在抽不开身,今天看了一下日历发现马上就春节了,所以就赶在春节之前将这篇博文写好并发布(其实是两篇:要看Android篇的点这里<React Native Android原生模块开发>). 我平时在用React Nativ

React Native Android原生模块开发实战|教程|心得|怎样创建React Native Android原生模块

尊重版权,未经授权不得转载 本文出自:贾鹏辉的技术博客(http://blog.csdn.net/fengyuzhengfan/article/details/54691503) 告诉大家一个好消息.为大家精心准备的React Native视频教程公布了,大家现能够看视频学React Native了. 前言 一直想写一下我在React Native原生模块封装方面的一些经验和心得.来分享给大家,但实在抽不开身.今天看了一下日历发现立即就春节了.所以就赶在春节之前将这篇博文写好并公布(事实上是两篇

JavaScript开发原生App模式能否突出重围?

移动应用制作的第三方服务市场已经被瓜分得差不多了,对于刚起步的中小企业来说,这些公司的 IT 部门人员比较熟悉的是 Appcan ,但随着互联网公司对 App 开发的需求持续升温,也有不少后来的闯入者试图用模式的改变在这个市场中突围. “DeviceOne” 就是其中之一,为了解决原生 App 开发面临的技术门槛高.人才成本大的问题,DeviceOne使用 自主研发作为技术框架.可视化界面的IDE为开发方式,并在网站上提供地图.支付.拍照等各式各样的延展功能组件,帮助大部分掌握软件开发入门技术的

JavaScript 开发的45个经典技巧

JavaScript 开发的45个经典技巧 分类 编程技术 JavaScript 是一个绝冠全球的编程语言,可用于Web开发.移动应用开发(PhoneGap.Appcelerator).服务器端开发(Node.js和 Wakanda)等等.JavaScript还是很多新手踏入编程世界的第一个语言.既可以用来显示浏览器中的简单提示框,也可以通过nodebot或 nodruino来控制机器人.能够编写结构清晰.性能高效的JavaScript代码的开发人员,现如今已成了招聘市场最受追捧的人. 在这篇文

JAVASCRIPT开发规范

JAVASCRIPT开发规范 一.JavaScript 语言规范 JavaScript 是一种客户端脚本语言, Google 的许多开源工程中都有用到它. 这份指南列出了编写 JavaScript 时需要遵守的规则. Alipay 前端 JavaScript 以些规范为准,局部有所修改 注:http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml 1. 变量  声明变量必须加上 var 关键字. Decision:

JavaScript开发工具大全

译者按: 最全的JavaScript开发工具列表,总有一款适合你! 原文: THE ULTIMATE LIST OF JAVASCRIPT TOOLS 译者: Fundebug 为了保证可读性,本文采用意译而非直译.另外,本文版权归原作者所有,翻译仅用于学习. 简介 2017年1月,Stack Overflow年度开发者调研一共访问了64000个程序员,发现JavaScript已经连续5年成为最流行的编程语言. 这篇博客将介绍一些常用的JavaScript开发工具: 构建&自动化 IDE&

稍微谈一下 javascript 开发中的 MVC 模式

随着前台开发日益受到重视,客户端代码比重日益增加的今天,如何在javascript开发里应用MVC模式,这个问题似乎会一直被提到,所以偶在这里粗略的谈一下自己的看法吧. MVC模式的基本理念,是通过把一个application封装成model, view和controller三个部分达到降低耦合,简化开发的目的.这么说很空洞,大家可以实际看个例子: 1<select id="selAnimal"> 2    <option value="cat"&

模块化的JavaScript开发的优势在哪里

如今模块化的 JavaScript 的开发越来越火热,无论是模块加载器还是优秀的 JavaScript 模块,都是层出不穷.既然这么火,肯定是有存在的理由,肯定是解决了某些实际问题.很多没接触过模块化 JavaScript 开发者不禁要问,我真的需要模块化吗,模块化相比于传统的模式有什么优势? JavaScript 本身是没有模块化支持的,很多语言多有,就连 CSS 都有这样的加载方式. 虽然因为性能问题不推荐 CSS 这样来进行加载,但这是一种模块化的思想,这种思想对于 JavaScript