最短的javascript:地址栏载入脚本代码


Posted in Javascript onOctober 13, 2011

不过脚本比较长的时候,需要复制密密麻麻一大段到地址栏里,显得很不美观,而且脚本修改起来也很不容易。因此一般先把脚本写在单独一个文件里,然后用javascript: 的形式动态载入脚本到页面中。不少网页插件都是用这个方法载入。

平时,我们用最简单的代码实现动态载入:

javascript:var o=document.createElement('script');o.src='...';document.body.appendChild(o);void(0)

当然,这对于载入插件来说足够OK了。但是不久前看到一个稍有修改的方法,让我开始琢磨这段代码究竟可以压缩到多短!

他的代码大致相同,只是更严谨:

javascript:(function(o){o.src='...';document.body.appendChild(o)})(document.createElement('script'));void(0)

虽然代码比先前的还长,但是将变量置于闭包中,避免潜在的冲突。并且将 document.createElement作为闭包的参数,巧妙的节省了一个var单词。

闲来无事,于是考虑起这代码能否精简再精简。顺便复习下js里面的各种特性。
 当然,首先默认了几个地址栏载入脚本要遵循的规则:

1. 不引入全局变量

2. 兼容主流浏览器

3. 载入过程不影响页面

> 不影响全局变量,我们需要使用闭包来隐藏我们的私有变量;

> 兼容主流浏览器,就必须使用标准的方法,兼容性判断只会增加代码长度;

> 如果简单的使用innerHTML添加元素,就有可能导致存在的元素刷新;

于是我们开始逐步分析。

显然,最先想到的就是匿名闭包的调用。

通常我们都是用: (function(){})() 的形式调用一个匿名闭包。注意红色的优先级括号是必不可缺的,否则就是一个错误的语法。

但也可以使用另一种形式:+function(){}() 前面的+号可以换成-!~等等一元操作符。不过这仅仅是1字节之差。

另一个显然的,就是可以把void(0)的参数替换成闭包调用的表达式。void虽然只是个关键字,但有类似函数的功能,对于任何参数都返回undefined。如果没有void,在地址栏执行了javascript:后,页面就变成了脚本表达式返回值,大家应该都见过。


于是经过显而易见的观察,略微减少了3个字符。

javascript:void(+function(o){o.src='...';document.body.appendChild(o)}(document.createElement('script')))

不过上面都是浅层次的观察。现在我们来仔细的分析。


我们为什么要使用闭包,就是为了防止我们的变量和页面里的冲突。那么可以不使用变量吗?想要不出现变量,唯一办法就是使用链式的连等操作:利用上个操作的返回值作为下个操作的参数。这段代码共有3个操作:创建脚本元素/脚本元素src赋值/添加脚本元素。仔细参考下W3C的手册,DOM.appendChild不仅可以添加元素,并且返回值也是此元素。而src赋值和元素添加的顺序可以互换。因此我们可以用链式操作,从而彻底告别闭包和变量:

javascript:void(document.body.appendChild(document.createElement('script')).src='...')

这一步,我们精简了19个字符!

我们继续观察。上面的代码里出现了2个document。我们如果用一个短变量代替的话又可以减少字数。但使用了变量的话又会出现冲突的问题,于是又要用到闭包。。。仔细的回忆下,js里有个我们平时不推荐使用的东西:with。没错,使用他就可以解决这个问题。我是只需with(document){...}即可。因为只有一行代码,所以那对大括号也可以去掉。于是又减少了4个字符:

javascript:with(document)void(body.appendChild(createElement('script')).src='...')

值得注意的是,void不再套在最外层了,因为with和if, for他们一样,不再是表达式,而是语句了。


此时,代码里的每句都是各司其责,连重复的单词都找不到了。我们还能否再精简?如果硬要找,那也只得从void这家伙身上找了。如果去掉它,那地址栏执行后,页面就变成了脚本元素的src字符了。显然删不得。但我们可以尝试换个,比如alert。在对话框过后,页面仍保留着。

先前说了,void的功能仅仅是返回一个undefined,而alert没有返回值。这里就不得不说javascript与其他语言的不同之处了。在其他的语言里,几乎都有函数/过程这么两概念,过程就是没有返回值的函数。不过js可不同,在js里任何函数都有一个返回值,即使“ 没有返回值 ”也是一种返回值,他就是undefined。所以alert和void有着相同的返回值:undefined。只要地址栏执行后结果是它,页面就不会转跳,而其他诸如false,0,null,NaN等等都不行。

于是我们只需让表达式返回的是undefined就可以了,但必须比void()这几个字符短。要产生一个undefined,除了它字面常量外,另外就是调用没有返回值的函数,或者访问一个对象不存在的属性。我们要尽可能简短。如果页面里使用了jQuery的话,我们用$.X就可以得到一个undefined。但没用jq的话,就不能保证是否存在变量$了。既然找不到足够简短的全局变量,我们可以用json创造个匿名的,比如[]或{},然后访问他的不存在属性,比如[].X。于是,我们可以告别void了:

 

javascript:with(document)body.appendChild(createElement('script')).src='...';[].X

这样就减少了1个字节。我们还可以合并下代码,用表达式替换X:

javascript:with(document)[][body.appendChild(createElement('script')).src='...']

这样又减少了1个字节。


事实上,js里的任何一个变量都是继承于Object的,即使数字也不例外。所以,我们完全可以用一个数字替换[],这样更进一步减少1个字符:

javascript:with(document)0[body.appendChild(createElement('script')).src='...']

到此,代码里除了src字符外,缩短到76字节。


当然,最终的极限仍在探索中。。。


配合Google的短域名服务Google URL Shortener,我们可以缩短脚本的URL,例如:

javascript:with(document)0[body.appendChild(createElement('script')).src='http://goo.gl/QPp29']
Javascript 相关文章推荐
关于jquery css的使用介绍
Apr 18 Javascript
使用js在页面中绘制表格核心代码
Sep 16 Javascript
浅析Node.js查找字符串功能
Sep 03 Javascript
jQuery提示效果代码分享
Nov 20 Javascript
jQuery幻灯片特效代码分享--鼠标滑过按钮时切换(2)
Nov 18 Javascript
jquery实现可自动判断位置的弹出层效果代码
Oct 12 Javascript
jQuery Select下拉框操作小结(推荐)
Jul 22 Javascript
微信小程序 loading 详解及实例代码
Nov 09 Javascript
jQuery Migrate 插件用法实例详解
May 22 jQuery
vue router动态路由设置参数可选问题
Aug 21 Javascript
在Angular中实现一个级联效果的下拉框的示例代码
May 20 Javascript
JavaScript 判断浏览器是否是IE
Feb 19 Javascript
jQuery EasyUI API 中文文档 - ComboGrid 组合表格
Oct 13 #Javascript
Javascript insertAfter() 实现函数代码
Oct 12 #Javascript
Tab页界面 用jQuery及Ajax技术实现(php后台)
Oct 12 #Javascript
Jquery中的CheckBox、RadioButton、DropDownList的取值赋值实现代码
Oct 12 #Javascript
jQuery EasyUI API 中文文档 - ComboTree组合树
Oct 11 #Javascript
推荐10个超棒的jQuery工具提示插件
Oct 11 #Javascript
namespace.js Javascript的命名空间库
Oct 11 #Javascript
You might like
JAVA/JSP学习系列之二
2006/10/09 PHP
PHP实现对文本数据库的常用操作方法实例演示
2014/07/04 PHP
PHP使用file_get_content设置头信息的方法
2016/02/14 PHP
PHP入门教程之自定义函数用法详解(创建,调用,变量,参数,返回值等)
2016/09/11 PHP
PHP基于MySQLI函数封装的数据库连接工具类【定义与用法】
2017/08/11 PHP
PHP时间戳和日期相互转换操作实例小结
2018/12/18 PHP
Laravel 微信小程序后端搭建步骤详解
2019/11/26 PHP
javascript实现div浮动在网页最顶上并带关闭按钮效果实例
2013/08/13 Javascript
在firefox和Chrome下关闭浏览器窗口无效的解决方法
2014/01/16 Javascript
jquery+CSS3实现淘宝移动网页菜单效果
2015/08/31 Javascript
JavaScript_object基础入门(必看篇)
2016/06/13 Javascript
Bootstrap字体图标无法正常显示的解决方法
2016/10/08 Javascript
Javascript中字符串相关常用的使用方法总结
2017/03/13 Javascript
详解Vue 中 extend 、component 、mixins 、extends 的区别
2017/12/20 Javascript
解决VUE项目localhost端口服务器拒绝连接,只能用127.0.0.1的问题
2020/08/14 Javascript
three.js如何实现3D动态文字效果
2021/03/03 Javascript
[02:57]DOTA2亚洲邀请赛 SECRET战队出场宣传片
2015/02/07 DOTA
Python实现字典按照value进行排序的方法分析
2017/12/23 Python
python的scikit-learn将特征转成one-hot特征的方法
2018/07/10 Python
python 实现兔子生兔子示例
2019/11/21 Python
使用Python判断一个文件是否被占用的方法教程
2020/12/16 Python
matplotlib事件处理基础(事件绑定、事件属性)
2021/02/03 Python
基于CSS3实现的黑色个性导航菜单效果
2015/09/14 HTML / CSS
怀旧香味蜡烛:Homesick
2019/11/02 全球购物
struct和class的区别
2015/11/20 面试题
商场中秋节广播稿
2014/01/17 职场文书
预备党员的自我评价
2014/03/12 职场文书
机械专业求职信范文
2014/07/15 职场文书
一般基层干部群众路线教育实践活动个人对照检查材料
2014/11/04 职场文书
全国爱牙日活动总结
2015/02/05 职场文书
房地产销售助理岗位职责
2015/04/14 职场文书
2016新党章学习心得体会
2016/01/15 职场文书
微信小程序用户授权最佳实践指南
2021/05/08 Javascript
解决pytorch-gpu 安装失败的记录
2021/05/24 Python
浅谈如何提高PHP代码质量之端到端集成测试
2021/05/28 PHP
CSS实现单选折叠菜单功能
2021/11/01 HTML / CSS