{"action":"created","issue":{"url":"https://api.github.com/repos/chunpu/blog/issues/81","labels_url":"https://api.github.com/repos/chunpu/blog/issues/81/labels{/name}","comments_url":"https://api.github.com/repos/chunpu/blog/issues/81/comments","events_url":"https://api.github.com/repos/chunpu/blog/issues/81/events","html_url":"https://github.com/chunpu/blog/issues/81","id":63729079,"number":81,"title":"即便是在现代浏览器中, 你也应该使用 jQuery","user":{"login":"chunpu","id":4565306,"avatar_url":"https://avatars.githubusercontent.com/u/4565306?v=3","gravatar_id":"","url":"https://api.github.com/users/chunpu","html_url":"https://github.com/chunpu","followers_url":"https://api.github.com/users/chunpu/followers","following_url":"https://api.github.com/users/chunpu/following{/other_user}","gists_url":"https://api.github.com/users/chunpu/gists{/gist_id}","starred_url":"https://api.github.com/users/chunpu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/chunpu/subscriptions","organizations_url":"https://api.github.com/users/chunpu/orgs","repos_url":"https://api.github.com/users/chunpu/repos","events_url":"https://api.github.com/users/chunpu/events{/privacy}","received_events_url":"https://api.github.com/users/chunpu/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/chunpu/blog/labels/javascript","name":"javascript","color":"f15501"},{"url":"https://api.github.com/repos/chunpu/blog/labels/jquery","name":"jquery","color":"0052cc"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-03-23T13:57:52Z","updated_at":"2015-03-25T15:00:12Z","closed_at":null,"body":"即便是在现代浏览器中, 你也应该使用 jQuery\r\n\r\n近来各大浏览器都很好的支持了 es5, chrome 和 firefox 更是支持了部分 es6 功能, 有不少同行就表示不再需要 jQuery 了, 用 [Vanilla.js](http://vanilla-js.com/) 足以, 我书读得不多, 查了一下词典才知道这是个 joke, 就是说什么不用任何 javascript 框架的意思\r\n\r\n以 winter 老师为首, jQuery 是这样被黑的\r\n\r\n[从jQuery谈库与框架的设计之优劣](http://www.cnblogs.com/winter-cn/archive/2013/02/20/2919855.html)\r\n\r\n[设计优秀的 API 有什么特征？](http://www.zhihu.com/question/23180366/answer/23831860?utm_source=weibo&utm_medium=weibo_share&utm_content=share_answer&utm_campaign=share_button)\r\n\r\n诚然 winter 老师的水平是我的十倍百倍, 但没到 winter 老师的水平, 我还是会用 jQuery\r\n\r\n相信大家在 jQuery 中主要用到这三个特性\r\n\r\n- arraylike 的元素集合操作\r\n- 方便的 ajax\r\n- 统一的事件管理\r\n\r\n$ 是一个 arraylike 的构造函数, 就像 NodeList 一样, 可以进行批量的元素操作\r\n\r\n为什么我们不直接用 NodeList 呢, 因为 NodeList 也是 arraylike 对象, 不是数组, 要变成数组我们只能 `Array.prototype.slice.call(NodeList)`, 可问题来了, 旧版 IE 不支持 `slice.call(NodeList)` 啊\r\n\r\n\r\n\r\n除了最基本的 `.each .filter .map`, jQuery 封装了更多其他的属性批量操作, 比如 `.text .html .val` 等\r\n\r\n有些现代浏览器的 api 用起来还不如 jQuery\r\n\r\n```js\r\n// 原生 javascript\r\nArray.prototype.forEach.call(document.querySelectorAll('tag'), function(el) {\r\n\tel.classList.toggle('visible')\r\n})\r\n\r\n// jQuery\r\n$('tag').toggleClass('visible')\r\n```\r\n\r\nwinter 老师曾表示 jQuery 重载函数有9种, 基本包罗万象, api 设计的很差\r\n\r\n有意思的是 jQuery 这么多重载, 在我眼里却只有一种\r\n\r\n```js\r\nfunction $(val, box) {\r\n\tif (is.fn(val)) return $(doc).ready(val)\r\n\tif (!(this instanceof $)) return new $(val, box)\r\n\r\n\tthis.length = 0\r\n\r\n\tif (!val) return\r\n\r\n\tif (is.string(val)) {\r\n\t\tif (-1 == val.indexOf('<')) {\r\n\t\t\tval = find(val, box)\r\n\t\t} else {\r\n\t\t\tval = parse.html(val)\r\n\t\t}\r\n\t}\r\n\r\n\tif (!is.arraylike(val)) val = [val]\r\n\r\n\tvar len = val.length\r\n\tfor (var i = 0; i < len; i++) {\r\n\t\tthis[i] = val[i]\r\n\t}\r\n\tthis.length = len\r\n}\r\n```\r\n\r\n一句话描述就是 `$(arraylike) => jQuery arraylike`\r\n\r\n完整代码见<https://github.com/chunpu/min-jquery/blob/gh-pages/index.js>\r\n\r\n> 这里衍生一下, 为什么我们不用 Array 的子类来定义 `$`(`util.inherits($, Array)`), 同样是旧版 IE 的问题, IE6-8 的 数组 length 属性是不可变的\r\n\r\n\r\najax\r\n---\r\n\r\njQuery 的 ajax 有多好用就不谈了, 曾经我是知道怎么手写 ajax 的, 但用了 jQuery 之后我已经不会了\r\n\r\n统一的事件管理\r\n---\r\n\r\n熟悉 jQuery 的朋友知道, jQuery 的事件是自己管理的, 用 jQuery 监听的事件本质上都是在元素上加一个 handler, 最后由 jQuery 内部完成事件的触发\r\n\r\n那统一管理事件有什么好处呢, 抛开 namespace, `return false`, 批量 on 和 off 这些方便的用法, 最重要的是可测试, 比如一个点击操作, 你要做自动化测试, 恐怕要上 webdriver, 但 jQuery 不需要, 因为它可以 `.trigger`, 这样你可以很容易的写出测试\r\n\r\n\r\n即便抛去这上面这些不谈, $ 也比 `element.querySelectorAll` 短太多了\r\n\r\n有人说 jQuery 中 set 和 get 让人迷惑, set 通常是全部都 set, 而 get 只是对第一个元素, 其实这也很好理解, 这些 `.attr .prop .css` 都是由 `$.access` 控制的, 如果是 get 就返回第一个元素的值, 如果不是 get (可能是 set 也可能是判断) 就会对全部元素进行处理, 同时 set 会返回 this 来支持链式操作\r\n\r\nwinter 老师还表示, jQuery 太大了, 压缩后还要 97k, 我就写个 ajax 真的要引入这 97K 嘛, 我们不妨看看 underscore 这个 util 库, 哇! 压缩后竟然 16k 之多, 你只是个小小的 util 库额. 但真的要用 jQuery 却不想搞这 97k 咋办? 请使用 [min-jquery](https://github.com/chunpu/min-jquery), 支持 IE6, 只有20k(广告文本质暴露..)\r\n\r\n你也许会说 现在流行的是 Angular, React, jQuery 已经落伍了, 这就错了, Angular, React 他们都是框架(framework), 而 jQuery 不过是一个库 (Libary), Angular 里面也内置了 jqLite\r\n\r\n未完, 在床上一时兴起瞎写的, 话说你们 star 我私人博客干嘛, 4个 watch, 7个 star 要闹哪样"},"comment":{"url":"https://api.github.com/repos/chunpu/blog/issues/comments/86069351","html_url":"https://github.com/chunpu/blog/issues/81#issuecomment-86069351","issue_url":"https://api.github.com/repos/chunpu/blog/issues/81","id":86069351,"user":{"login":"tcdona","id":352931,"avatar_url":"https://avatars.githubusercontent.com/u/352931?v=3","gravatar_id":"","url":"https://api.github.com/users/tcdona","html_url":"https://github.com/tcdona","followers_url":"https://api.github.com/users/tcdona/followers","following_url":"https://api.github.com/users/tcdona/following{/other_user}","gists_url":"https://api.github.com/users/tcdona/gists{/gist_id}","starred_url":"https://api.github.com/users/tcdona/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tcdona/subscriptions","organizations_url":"https://api.github.com/users/tcdona/orgs","repos_url":"https://api.github.com/users/tcdona/repos","events_url":"https://api.github.com/users/tcdona/events{/privacy}","received_events_url":"https://api.github.com/users/tcdona/received_events","type":"User","site_admin":false},"created_at":"2015-03-25T15:00:12Z","updated_at":"2015-03-25T15:00:12Z","body":"通神的博客必须看啊，我也觉得jQuery依然好用！\r\n自己写一个小小的 dom parser，很容易就可以让jquery 融合上双向绑定、component 等思想。\r\n就是觉得file size有点大了，希望打散成更小的可组合模块 / 函数。"}}