最短的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 相关文章推荐
firefox中用javascript实现鼠标位置的定位
Jun 17 Javascript
js 替换
Feb 19 Javascript
jQuery筛选器children()案例详解(图文)
Feb 17 Javascript
node.js中的fs.readSync方法使用说明
Dec 17 Javascript
asp.net中oracle 存储过程(图文)
Aug 12 Javascript
z-blog SyntaxHighlighter 长代码无法换行解决办法(基于jquery)
Nov 18 Javascript
Bootstrap树形组件jqTree的简单封装
Jan 25 Javascript
EasyUI加载完Html内容样式渲染完成后显示
Jul 25 Javascript
EasyUI折叠表格层次显示detailview详解及实例
Dec 28 Javascript
JS查找字符串中出现最多的字符及个数统计
Feb 04 Javascript
vue2.0中vue-cli实现全选、单选计算总价格的实例代码
Jul 18 Javascript
三步搞定:Vue.js调用Android原生操作
Sep 07 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面向对象的使用教程 简单数据库连接
2006/11/25 PHP
PHP程序开发范例学习之表单 获取文本框的值
2011/08/08 PHP
php 带逗号千位符数字的处理方法
2012/01/10 PHP
php全排列递归算法代码
2012/10/09 PHP
PHP实现路由映射到指定控制器
2016/08/13 PHP
yii2 数据库读写分离配置示例
2017/02/10 PHP
Yii2框架配置文件(Application属性)与调试技巧实例分析
2019/05/27 PHP
redis+php实现微博(三)微博列表功能详解
2019/09/23 PHP
Javascript实现的鼠标经过时播放声音
2010/05/18 Javascript
js中的getAttribute方法使用示例
2014/08/01 Javascript
jquery ajax 如何向jsp提交表单数据
2015/08/23 Javascript
AngularJS仿苹果滑屏删除控件
2016/01/18 Javascript
基于angular中的重要指令详解($eval,$parse和$compile)
2016/10/21 Javascript
AngularJS中的Promise详细介绍及实例代码
2016/12/13 Javascript
angularJs使用$watch和$filter过滤器制作搜索筛选实例
2017/06/01 Javascript
jquery.rotate.js实现可选抽奖次数和中奖内容的转盘抽奖代码
2017/08/23 jQuery
vue 开发一个按钮组件的示例代码
2018/03/27 Javascript
vue实现在一个方法执行完后执行另一个方法的示例
2018/08/25 Javascript
使用Vuex解决Vue中的身份验证问题
2018/09/28 Javascript
js中获取URL参数的共用方法getRequest()方法实例详解
2018/10/24 Javascript
javascript中一些奇葩的日期换算方法总结
2018/11/14 Javascript
js 判断当前时间是否处于某个一个时间段内
2019/09/19 Javascript
vue中添加与删除关键字搜索功能
2019/10/12 Javascript
JS图片预加载三种实现方法解析
2020/05/08 Javascript
Javascript confirm多种使用方法解析
2020/09/25 Javascript
用实例详解Python中的Django框架中prefetch_related()函数对数据库查询的优化
2015/04/01 Python
Python IDE环境之 新版Pycharm安装详细教程
2020/03/05 Python
pytorch  网络参数 weight bias 初始化详解
2020/06/24 Python
解决Pycharm 中遇到Unresolved reference 'sklearn'的问题
2020/07/13 Python
Python利用imshow制作自定义渐变填充柱状图(colorbar)
2020/12/10 Python
室内设计专业个人的自我评价
2013/12/18 职场文书
劳动工资科岗位职责范本
2014/03/02 职场文书
2015年试用期工作总结范文
2015/05/28 职场文书
2019年员工晋升管理制度范本!
2019/07/08 职场文书
Linux安装Nginx步骤详解
2021/03/31 Servers
如何用JS实现网页瀑布流布局
2021/04/24 Javascript