最短的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 相关文章推荐
一个高效的JavaScript压缩工具下载集合
Mar 06 Javascript
javascript 一个自定义长度的文本自动换行的函数
Aug 19 Javascript
google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)
Apr 24 Javascript
javascript实现tabs选项卡切换效果(扩展版)
Mar 19 Javascript
jquery 触发a链接点击事件解决方案
May 02 Javascript
浅析$.getJSON异步请求和同步请求
Jun 06 Javascript
针对BootStrap中tabs控件的美化和完善(推荐)
Jul 06 Javascript
谈谈JavaScript中的几种借用方法
Aug 09 Javascript
Vuex之理解Mutations的用法实例
Apr 19 Javascript
详解vue-cli 构建Vue项目遇到的坑
Aug 30 Javascript
浅谈angularJS2中的界面跳转方法
Aug 31 Javascript
JS实现随机抽取三人
Nov 06 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
php的一些小问题
2010/07/03 PHP
基于php权限分配的实现代码
2013/04/28 PHP
shell脚本作为保证PHP脚本不挂掉的守护进程实例分享
2013/07/15 PHP
php面向对象编程self和static的区别
2016/05/08 PHP
解析PHP之提取多维数组指定列的方法
2017/01/03 PHP
PHP命令Command模式用法实例分析
2018/08/08 PHP
Laravel项目中timeAgo字段语言转换的改善方法示例
2019/09/16 PHP
超级24小时弹窗代码 24小时退出弹窗代码 100%弹窗代码(IE only)
2010/06/11 Javascript
JS代码判断IE6,IE7,IE8,IE9的函数代码
2013/08/02 Javascript
一个Action如何调用两个不同的方法
2014/05/22 Javascript
JQuery 控制内容长度超出规定长度显示省略号
2014/05/23 Javascript
jquery实现保存已选用户
2014/07/21 Javascript
如何使用jquery easyui创建标签组件
2015/11/18 Javascript
详解Angular开发中的登陆与身份验证
2016/07/27 Javascript
JS中parseInt()和map()用法分析
2016/12/16 Javascript
vue 避免变量赋值后双向绑定的操作
2020/11/07 Javascript
Python多线程实例教程
2014/09/06 Python
使用Python编写类UNIX系统的命令行工具的教程
2015/04/15 Python
简单介绍Python中的readline()方法的使用
2015/05/24 Python
python多进程和多线程究竟谁更快(详解)
2017/05/29 Python
Python将多个excel文件合并为一个文件
2018/01/03 Python
python实现简单加密解密机制
2019/03/19 Python
python sort、sort_index方法代码实例
2019/03/28 Python
用django设置session过期时间的方法解析
2019/08/05 Python
python图的深度优先和广度优先算法实例分析
2019/10/26 Python
CSS3 icon font完全指南(CSS3 font 会取代icon图标)
2013/01/06 HTML / CSS
css3 按钮样式简单可扩展创建
2013/03/18 HTML / CSS
为什么在使用动态 SQL 语句时必须为低层数据库对象授予权限
2012/12/13 面试题
办理生育手续介绍信
2014/01/14 职场文书
信息技术专业大学生职业生涯规划书
2014/01/24 职场文书
小学语文课后反思精选
2014/04/25 职场文书
授权委托书怎么写
2014/09/25 职场文书
机关作风建设整改方案
2014/10/27 职场文书
初中毕业生自我评价
2015/03/02 职场文书
医务人员岗前培训心得体会
2016/01/08 职场文书
html form表单基础入门案例讲解
2021/07/15 HTML / CSS