如何做到 jQuery-free?

作者: 阮一峰

日期: 2013年5月11日

jQuery是现在最流行的JavaScript工具库。

统计,目前全世界57.3%的网站使用它。也就是说,10个网站里面,有6个使用jQuery。如果只考察使用工具库的网站,这个比例就会上升到惊人的91.7%。

虽然jQuery如此受欢迎,但是它臃肿的体积也让人头痛不已。jQuery 2.0的原始大小为235KB,优化后为81KB;如果是支持IE6、7、8的jQuery 1.8.3,原始大小为261KB,优化后为91KB。

这样的体积,即使是宽带环境,完全加载也需要1秒或更长,更不要说移动设备了。这意味着,如果你使用了jQuery,用户至少延迟1秒,才能看到网页效果。考虑到本质上,jQuery只是一个操作DOM的工具,我们不仅要问:如果只是为了几个网页特效,是否有必要动用这么大的库?

2006年,jQuery诞生的时候,主要用于消除不同浏览器的差异(主要是IE6),为开发者提供一个简洁的统一接口。相比当时,如今的情况已经发生了很大的变化。IE的市场份额不断下降,以ECMAScript为基础的JavaScript标准语法,正得到越来越广泛的支持。开发者直接使用JavScript标准语法,就能同时在各大浏览器运行,不再需要通过jQuery获取兼容性。

下面就探讨如何用JavaScript标准语法,取代jQuery的一些主要功能,做到jQuery-free。

一、选取DOM元素

jQuery的核心是通过各种选择器,选中DOM元素,可以用querySelectorAll方法模拟这个功能。

  var $ = document.querySelectorAll.bind(document);

这里需要注意的是,querySelectorAll方法返回的是NodeList对象,它很像数组(有数字索引和length属性),但不是数组,不能使用pop、push等数组特有方法。如果有需要,可以考虑将Nodelist对象转为数组。

  myList = Array.prototype.slice.call(myNodeList);

二、DOM操作

DOM本身就具有很丰富的操作方法,可以取代jQuery提供的操作方法。

尾部追加DOM元素。

  // jQuery写法
  $(parent).append($(child));

  // DOM写法
  parent.appendChild(child)

头部插入DOM元素。

  // jQuery写法
  $(parent).prepend($(child));

  // DOM写法
  parent.insertBefore(child, parent.childNodes[0])

删除DOM元素。

  // jQuery写法
  $(child).remove()

  // DOM写法
  child.parentNode.removeChild(child)

三、事件的监听

jQuery的on方法,完全可以用addEventListener模拟。

  Element.prototype.on = Element.prototype.addEventListener;

为了使用方便,可以在NodeList对象上也部署这个方法。

  NodeList.prototype.on = function (event, fn) {
    []['forEach'].call(this, function (el) {
      el.on(event, fn);
    });
    return this;
  };

四、事件的触发

jQuery的trigger方法则需要单独部署,相对复杂一些。

  Element.prototype.trigger = function (type, data) {
    var event = document.createEvent('HTMLEvents');
    event.initEvent(type, true, true);
    event.data = data || {};
    event.eventName = type;
    event.target = this;
    this.dispatchEvent(event);
    return this;
  };

在NodeList对象上也部署这个方法。

  NodeList.prototype.trigger = function (event) {
    []['forEach'].call(this, function (el) {
      el['trigger'](event);
    });
    return this;
  };

五、document.ready

目前的最佳实践,是将JavaScript脚本文件都放在页面底部加载。这样的话,其实document.ready方法(jQuery简写为$(function))已经不必要了,因为等到运行的时候,DOM对象已经生成了。

六、attr方法

jQuery使用attr方法,读写网页元素的属性。

  $("#picture").attr("src", "http://url/to/image");

DOM元素允许直接读取属性值,写法要简洁许多。

  $("#picture").src = "http://url/to/image";

需要注意,input元素的this.value返回的是输入框中的值,链接元素的this.href返回的是绝对URL。如果需要用到这两个网页元素的属性准确值,可以用this.getAttribute('value')和this.getAttibute('href')。

七、addClass方法

jQuery的addClass方法,用于为DOM元素添加一个class。

  $('body').addClass('hasJS');

DOM元素本身有一个可读写的className属性,可以用来操作class。

  document.body.className = 'hasJS';

  // or

  document.body.className += ' hasJS';

HTML 5还提供一个classList对象,功能更强大(IE 9不支持)。

  document.body.classList.add('hasJS');

  document.body.classList.remove('hasJS');

  document.body.classList.toggle('hasJS');

  document.body.classList.contains('hasJS');

八、CSS

jQuery的css方法,用来设置网页元素的样式。

  $(node).css( "color", "red" );

DOM元素有一个style属性,可以直接操作。

  element.style.color = "red";;

  // or

  element.style.cssText += 'color:red';

九、数据储存

jQuery对象可以储存数据。

  $("body").data("foo", 52);

HTML 5有一个dataset对象,也有类似的功能(IE 10不支持),不过只能保存字符串。

  element.dataset.user = JSON.stringify(user);

  element.dataset.score = score;

十、Ajax

jQuery的Ajax方法,用于异步操作。

  $.ajax({
    type: "POST",
    url: "some.php",
    data: { name: "John", location: "Boston" }
  }).done(function( msg ) {
    alert( "Data Saved: " + msg );
  });

我们可以定义一个request函数,模拟Ajax方法。

  function request(type, url, opts, callback) {

    var xhr = new XMLHttpRequest();

    if (typeof opts === 'function') {
      callback = opts;
      opts = null;
    }

    xhr.open(type, url);

    var fd = new FormData();

    if (type === 'POST' && opts) {
      for (var key in opts) {
        fd.append(key, JSON.stringify(opts[key]));
      }
    }

    xhr.onload = function () {
      callback(JSON.parse(xhr.response));
    };

    xhr.send(opts ? fd : null);

  }

然后,基于request函数,模拟jQuery的get和post方法。

  var get = request.bind(this, 'GET');

  var post = request.bind(this, 'POST');

十一、动画

jQuery的animate方法,用于生成动画效果。

  $foo.animate('slow', { x: '+=10px' });

jQuery的动画效果,很大部分基于DOM。但是目前,CSS 3的动画远比DOM强大,所以可以把动画效果写进CSS,然后通过操作DOM元素的class,来展示动画。

  foo.classList.add('animate');

如果需要对动画使用回调函数,CSS 3也定义了相应的事件。

  el.addEventListener("webkitTransitionEnd", transitionEnded);

  el.addEventListener("transitionend", transitionEnded);

十二、替代方案

由于jQuery体积过大,替代方案层出不穷。

其中,最有名的是zepto.js。它的设计目标是以最小的体积,做到最大兼容jQuery的API。zepto.js 1.0版的原始大小是55KB,优化后是29KB,gzip压缩后为10KB。

如果不求最大兼容,只希望模拟jQuery的基本功能,那么,min.js优化后只有200字节,而dolla优化后是1.7KB。

此外,jQuery本身采用模块设计,可以只选择使用自己需要的模块。具体做法参见它的github网站,或者使用专用的Web界面

十三、参考链接

  - Remy Sharp,I know jQuery. Now what?
  - Hemanth.HM,Power of Vanilla JS
  - Burke Holland,5 Things You Should Stop Doing With jQuery

(完)

珠峰培训

简寻

留言(48条)

这篇文章适合那些从 jQuery 入门 JavaScript 的同学学习啊.

写了很多年JS,基本都在写vanilla JS。用过Google closure library,用过angular.js,从来不用jQuery。

对jQuery及其厌恶,无非就是少量syntactic sugar,把代码变得更不优雅且带来各种overhead。

jQuery的优化缩减支持IE低版本,也说明了标准化的趋势,只是国内的银行、大型国企还在使用IE6...

jquery在删除dom元素前对元素上的已绑定的事件做了清理操作,防止内存泄漏,在用原生js操作dom时也应该注意这一点。

博主,非常感谢你的这篇文章,这是我从没想过的事,当然我也刚入门。

不过我有一些问题想请教你,能说说你是如何开始构思一篇文章的吗,是如何发现这个思路,然后花了多长时间写文章,这些时间是如何安排出来的,你是同时构思几篇文章,还是一篇写完后才开启第二篇?你可以考虑写篇文章介绍下,相信对其他人也有用的。因为你发文章的速度比我快多了,我经常忙的忘了我还开了博客这件事,所以有这些疑问。

先行道谢了。

好讽刺,jQuery当初干掉其他JS libraries 很重要的一个原因就是小巧的体积,1.3版貌似只有30K出头。

看来 jQuery 终有一天会被淘汰,抑或说 jQuery 也会像 Zepto 那样精简化。jQuery 的语法糖还是设计得很不错的,现在改用 Zepto 也不错。

引用倉優小子的发言:

jquery在删除dom元素前对元素上的已绑定的事件做了清理操作,防止内存泄漏,在用原生js操作dom时也应该注意这一点。

去 Zepto 的 GitHub 看了下源码,发现 $.fn.detach 功能还没弄好,暂时用 $.fn.remove 替代着。

jquery的确很大,但是另外一个情况是,大部分网站都加载jquery,在第一次以后jquery就存在用户电脑中了,下次直接调用本地的jquery库。
所以并不是每次加载含有jquery的网页都会延迟一秒钟。
如果用户浏览得越多网页,平均下来加载的延迟就会越低。
比起js来说,jquery在开发上还是简单容易许多的

软老师可否写一些关于linux内核方面的文章啊。不打算写本书吗?

从一开始就不用jQuery的话还可以铁下心来,无视那些丰富美妙的jQuery plugin,通过实践jQuery-free来成长为一个独行大侠。可一旦已经用上了jQuery,恐怕就不可能不用了。

引用墨菲斯托同学的发言:

jquery的确很大,但是另外一个情况是,大部分网站都加载jquery,在第一次以后jquery就存在用户电脑中了,下次直接调用本地的jquery库。

这个前提应该是使用了 CDN

使用公用的jquery cdn链接,是解决这个库文件偏大的更优解。既然已有的网站都有超过50%使用jquery,而且普通用户接触到的大型网站比如微博,淘宝, 都提供了静态的cdn给jquery使用(google,微软也有)。那么自己的小网站在include js文件的时候如果是使用这些cdn,一方面网速很快,延迟小, 另外一方面,这个链接极大可能已经被用户的浏览器缓存了,所以实际上不会花费任何网络流量和延时。

jquery无法被替代,文章名字应该改成《JQuery和原生JS操作的10个区别》

已转载~

写的很好!很简单的网页也用jquery确实太重量了。

发现这个网站引用了你的文章:

http://blog.jobbole.com/39546

但是中间插入了很多广告(e.g 什么教育网),这可能不符合你声明的“Creative Commons BY-NC-ND 3.0”协议。

To @ruanyf:从其他网站复制了内容,没有删除干净那个网站强行添加的内容,这是我们的失误,十分抱歉。我们已删除更新了。

谢谢Tux的提醒。

jquery的加载问题可以通过cdn来解决
用原生js虽然速度快,可是会带来两个问题:
一个是代码量的增多,二是无法利用现有的jquery plugin,
这两点所导致的开发流程延长足够抵消使用原生js的速度优势

已经使用了CDN无压力,包括jquery-ui

减少体积这种事情和优化性能一样都是一条不归路啊
只要没有明显的性能问题,何必去干这个?
jQuery明显成熟而且功能强大,如果其他库没有拿出更好的功能,仅仅精简代码,那就毫无疑义了。
网速问题最终会被时间解决,庞大的人力物力下去就是为了精简功能,甚至使用一个不成熟的库,有意思吗?
我以前也想过类似的事情,现在都发现毫无意义了,太蛋疼了。

感觉各有千秋吧。。

引用greatghoul的发言:

这个前提应该是使用了 CDN

这个和cdn有什么关系,这个应该是web服务器设置了缓存头信息就可以。

引用bachue的发言:

减少体积这种事情和优化性能一样都是一条不归路啊
只要没有明显的性能问题,何必去干这个?
jQuery明显成熟而且功能强大,如果其他库没有拿出更好的功能,仅仅精简代码,那就毫无疑义了。
网速问题最终会被时间解决,庞大的人力物力下去就是为了精简功能,甚至使用一个不成熟的库,有意思吗?
我以前也想过类似的事情,现在都发现毫无意义了,太蛋疼了。

我非常同意此观点 中小型公司追求的就是效率 高效 中小公司往往在高人才上面比较缺乏,如果上来就让一个前端工程师用原生js 也许速度什么的是高了 但是老板不乐意啊 他们追求的更多的是 RMB 啊
如今的网速(pc:目前查看普遍都是4M网速 手机端:3G 4G wifi) 缓存 用户浏览器的提高(ff chrome ie10份额提升) 加上许多公司开始放弃自己的jquery使用大公司的CDN 楼主如果仅仅是因为大小的问题,则完全可以忽视.
ps:
网传比较好的方法(因避免html标签解析错误 使用中文代替):
使用google CDN:
http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js
然后检测是否加载完毕 (网速 或者 被墙之类的)
if(!jQuery){document.write('你自己的src')}

引用陈玉驰的发言:

jQuery的优化缩减支持IE低版本,也说明了标准化的趋势,只是国内的银行、大型国企还在使用IE6...

深深感觉银行他们严重影响开发人员进步……

这个做法很久之前看到过..不过我觉得满足不了我强大的需求

首张那图片是什么书,好像不是英文版的。难道峰哥还会其它什么语言的?膜拜中...

引用欧文的发言:

首张那图片是什么书,好像不是英文版的。难道峰哥还会其它什么语言的?膜拜中...

德文。

今天在自己的 reveal.js 修改中做到了 jQuery free,哦耶~

…求返回页首按钮

同求增加返回页首。。

试用了一下Zepto,发现其他使用了jQuery的库无法正常工作,放弃!

并非所有的浏览器都有效兼容css3, 为了加快一秒中的加载速度, 愿意抛弃那些用户和开发效率, 也可以放弃jQuery. 随着网速和硬件水平的不断提高, 所有的性能问题都不是问题. 而且我认为用户并不像我们认为的那么急不可待.

看了一下zepto.js 发现官网没打算支持 IE

我也主张如果几个简单的小效果还用jQ就太重了。问题是楼主以上列举的几个方法貌似对IE6的支持性不好。。

jQuery很赞,特别是对现代浏览器,对于IE,那就没有办法了。

引用小牛仔的发言:

这个和cdn有什么关系,这个应该是web服务器设置了缓存头信息就可以。

当然有关系。因为前面大家说的CDN,不是自己域名的CDN,而是ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js这种类型的CDN。这种CDN使用的网站非常多,一个用户访问的某一个网站使用了这个CDN,你的页面再加载时,就不用再次加载了,体积大小也就不是问题了。

这篇文章我是不大赞同的。虽然JQuery体积确实大,但是其带来的开发便利性,对于中小型团队来说是非常重要的。毕竟中小型团队没有Yahoo,淘宝,Twitter这种公司那么强大的实力,自己搞一套好用的框架出来是相当不现实的。
因为体积原因而放弃JQuery,就像因为性能原因只使用C语言,放弃Java,C#,甚至C++一样

引用kmxz的发言:

写了很多年JS,基本都在写vanilla JS。用过Google closure library,用过angular.js,从来不用jQuery。

对jQuery及其厌恶,无非就是少量syntactic sugar,把代码变得更不优雅且带来各种overhead。

恰恰相反,我觉得使用jquery写js代码比原生的写js代码要优雅有趣的多,原生的js代码,感觉写起来像是一坨屎,冗长的方法名,极其厌恶!而写jquery代码和写python有似曾相识的令人愉悦的感觉,而且写jqeury比写python更加舒服。举个例子,简单的一个.each()方法就可以去掉90%的for循环,那个感觉真是爽啊。

看团队能力吧,个人想法普通的小团队也包括我的,用jquery会比较妥当。

其实jquery没那么可恶,对于敏捷开发而言,利于整个团队的开发进度。不过,如果个人想在前端领域更进一步,自然需要摒弃对jquery的依赖。其实,当年我开始自学前端时,听都没听说过jquery,哈哈,还是换了一家公司之后才被要求用jquery。不过如今想起来,还真是庆幸当年傻了叭唧的只知道埋头学自己的。

好文。不过还没用过jQuery,用了下zepto,发现这个东西确实是方便,但是会导致像我这样的入门者基础不牢。

拿到手机上就知道jQuery真的是不行!!

开发中 必须用到代码库的 不管是jQuery 还是其他的库 直接用原生代码来开发 还是得写成一个库嘛 不然冗余代码多 维护性差

只是jQuery作为一个给大家用的库 要考虑的东西非常的多 所以代码量大是必然的

只用原生JS不用框架的路过。

如果你们去开发移动端, 就会发现, 性能开销是个多么重要的问题.
自从转移动端WEB开发之后, 基本没用过任何库了, 全部原生Js.
原生js操作dom, 也并非我最开始想的那么棘手, 反而让我对jQuery的一些机制更加明白了.
特效用css3.
基本和博主建议的差不多.

引用初学者的发言:

如果你们去开发移动端, 就会发现, 性能开销是个多么重要的问题.
自从转移动端WEB开发之后, 基本没用过任何库了, 全部原生Js.
原生js操作dom, 也并非我最开始想的那么棘手, 反而让我对jQuery的一些机制更加明白了.
特效用css3.
基本和博主建议的差不多.

移动端有个好处就是环境极其统一,而且支持各种最新的特性,因为andriod和iOS的浏览器都是webkit,这样用原生JS写起来基本不需要多少兼容性处理。web版的firefox和WP的浏览器虽然内核不同,但好歹都是支持了新标准的,而且占比不高。而且移动端窘迫的性能和带宽也跟适合使用原生JS。

然而到了PC端,各种浏览器新旧版本并存,运行环境五花八门,除非你下定决心只支持最新浏览器,否则各种兼容性问题层出不穷。不过PC拥有更高的性能和更快的带宽,配合CDN的话,jQuery的大小并不是什么问题。

从个人学习的角度来看,脱离jQuery是必要的,但是从项目开发的角度来看,jQuery能让开发人员更专心于业务逻辑的实现。


其实我是挺喜欢JQuery的,而且觉得现在的网络环境下一个JQuery库大概也不算什么。脱离不脱离JQuery其实对JavaScript本身的水平影响不大吧?不过可能会更加清楚DOM的那些东西。

CSS3动画据说有硬件加速,然而前一阵子(大概一两年前?)不知道为什么性能还是很差,尤其是移动端,非常差,现在不知道怎么样了。DOM动画的话,有个小问题需要注意是,要发生动画的元素得拿出来,别让整个DOM陪它重绘去……

最近经常用Typescript+Angular1.x,虽然没有什么因果关系,但是微妙的发现自己好像不怎么用JQuery了。

请问阮老师NodeList.prototype.on这个肿么使用,没看懂。。

引用陈玉驰的发言:

jQuery的优化缩减支持IE低版本,也说明了标准化的趋势,只是国内的银行、大型国企还在使用IE6...

还有各种医院...

引用kmxz的发言:

写了很多年JS,基本都在写vanilla JS。用过Google closure library,用过angular.js,从来不用jQuery。

对jQuery及其厌恶,无非就是少量syntactic sugar,把代码变得更不优雅且带来各种overhead。

怎么就用其他框架就用出优越感,极其厌恶了,只能显示自己是个lowB

jquery无法被替代,文章名字应该改成《JQuery和原生JS操作的10个区别》

我要发表看法

«-必填

«-必填,不公开

«-我信任你,不会填写广告链接