回想了一下 JavaScript 的入门,觉得经历挺神奇的。可以作为实用主义的体现。
起因是这样的。2014年12月的时候,入宅也差不多一年了,这时候通过校内论坛签名的方式找到了 Bangumi。“分集记录”这个想法对我来说还比较新鲜,所以就玩上了。接着发现,看一集点一集,太麻烦了,而且还得设置追番,还要打分。这时候花园还健在,日常看番都是从花园上下载的。我访问花园的频率比 Bangumi 的高到不知哪里去了(毕竟不只是下载,还有讨论吹水什么的),所以为什么不做一个下拉框什么的,看完以后回到花园,一点,就自动完成了一堆事情呢?
嗯对,最终成品就是这玩意儿。
当时我对网页一知半解,理解停留在 FrontPage,HTML(几种元素),和嵌入(inline)的 JavaScript 代码这个阶段。不过也只是“知道”,实际用倒是没用过。开发者工具也是没用过;流量劫持知道原理,不过面向的是专门的嗅探工具(当时用的是 IEInspector HTTP Analyzer)。
反正有了个目标,开工。
然后就发现,逻辑要用 JavaScript 来写,而我根本不会。于是就找了个教程,看到里面各种乱飞的名词:闭包、原型、AJAX……但是几个简单的例子怎么能说明问题呢?就算有个 Try It Yourself,一个完全的新手还是无法理解里面的玄妙。
目标是 Bangumi,略微搜索一下就会发现jabbany的作品(抱歉,当时连 GitHub 都不怎么会用)。但是,代码只能看懂一半,我甚至无法接受 JavaScript 的弱类型性——不知道是什么类型,怎么推测怎么用呢?举个例子:
var xrequest = function (api, post, get, callback) { ... }
等等,几个参数的类型是什么?返回的类型是什么?由于缺乏文档,所以必须要看完才能推测。弱类型不是无类型,而且在调用的时候依然需要保证类型正确,所以看着十分痛苦。
this.authenticate = function(user, pass, callback) { ... }
等等,本来没有 authenticate
这个字段的啊?那别人怎么知道最终给出的 this
是带有 authenticate
,这还是个函数的?
另一个就更让人疑惑了。上面用的是 this.xxx
,好不容易搞清楚了这个 this
指向的是定义其的函数(这里就和我以前所知道的“类”的 this
就有很大区别了),结果在另一个脚本中,又出现了这样的东西:
Object.defineProperties(Function1.prototype, ...)
怎么回事?这又是什么意思?如果这能行,那上面的 this.xxx
和这个又有什么区别呢?对于当时基础等于零的我,根本就是云里雾里。
还有上文函数中的 callback
。要正确使用,必须要理解变量捕获。我只观察到了现象,不过并不知道这个规则。
然后是发送请求。搜索的结果,AJAX 咯。照着骨架用了用 XMLHttpRequest
。在空白页,控制台直接运行代码,能行。然而到花园页面上一用却没有响应,一看调试信息,等着我是一个同源策略错误。这又是什么?搜索了一番,才知道这是个大难题。如果网站不归你管(不能自己添加 Access-Control-Allow-Origin
头),请求发送也不归你管(浏览器禁止修改 Origin
头),那么一般也只能用 JSONP,借用无限制的 GET 了。但是某篇文章里说,<iframe>
不受限制,不过示例是让人在 <iframe>
中交互(点击、登录之类的),和我的需求有差异。哎,添加元素,这个我会,但是如何将信息传递进去呢?(所有操作在 <iframe>
内进行,所以不用考虑传出。)又搜索了一番,得知有一个 postMessage()
,window
和 <iframe>
都有。而且它可以强制忽略 Origin
。不过再一查,已经有人整合了,就是 Dojo 的其中一个模块。
但是使用上就有问题了。由于它依赖 Dojo,而 Dojo 的加载是这个样子的:
require(["dojo/request/iframe"], function (iframe) { ... });
这就要求在 <head>
内引入 Dojo 的代码,否则 require()
是没有定义的——但是在使用这个脚本的时候,不能保证在该页面内引入了 Dojo 的代码。要有鲁棒性,必须保证这段代码在引入了 Dojo 代码之后才能执行。于是又用了动态的 <script>
(等同于懒加载),做了一点点兼容,才最终完成。
后来进一步发现,GreaseMonkey 就有一个 GM_xmlHttpRequest
函数,自带跨域。所以又加了一种实现,仅用于 UserScript 的,不过代码就简单多了。
所以学到了什么呢?
- 回调和闭包
- 原型链
- 异步函数
- AJAX
- CORS
- 懒加载
- 一点点 ES5 (
postMessage
)
后来发到花园上之后(原文转到了博客上),下面有个人回复:等等,这么深,这是你第一次接触 JavaScript?我:只是为了实现一个想要的功能而已……
后来加入了漫版群,原来那是位前端大佬。
不过我真的只是要解决一个问题而已,为此破除路上的障碍,自然而然的啊?