从一行代码里面学点JavaScript
从一行代码里面学点JavaScript
现如今,JavaScript无处不在,因此关于JavaScript的新知识也是层出不穷。JavaScript的特点在于,要学习它的语法入门简简单,但是要精通使用它的方式却是一件不容易的事。
来看看下面的这段代码,它来自于谷歌“名猿”Addy Osmani在几天前贴出的一段代码,它的作用是用来调试你的CSS层。全部代码只有三行,但是你绝对可以把它放在一行里面完成:
[].forEach.call($$("*"),function(a){
a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)
})
现在,在你的Chrome浏览器的控制台中输入这段代码,你会发现不同HTML层都被使用不同的颜色添加了一个高亮的边框。是不是非常酷?但是,简单来说,这段代码只是首先获取了所有的页面元素,然后使用一个不同的颜色为它们添加了一个1ps的边框。想法很简单,但是真要实现起来却不是那么容易的一件事。在下面的内容中,我们将一起一步一步学习如何理解上面的这段代码。
选择页面中所有的元素
我们需要做的第一件事情是获取页面中所有的元素,在上面的代码中,Addy使用了一个Chrome浏览器中特有的函数$$。你可以在你的Chrome浏览器控制台中输入$$('a'),然后你就能得到一个当前页面中所有锚元素的列表。
$$函数是许多现代浏览器命令行API中的一个部分,它等价于document.querySelectorAll,你可以将一个CSS选择器作为这个函数的参数,然后你就能够获得当前页面中所有匹配这个CSS选择器的元素列表。如果你在浏览器控制台以外的地方,你可以使用document.querySelectorAll('*')来代替$$('*')。更多关于$$函数的详细内容可以查看Chrome开发者工具的文档。
当然,除了使用$$函数之外,我们还有一种更简单的方法,document.all,虽然这并不是一种很规范的使用方法,但是它几乎在每一个浏览器中都能运行成功。
迭代所有的元素
经过第一步,我们已经获得了页面内所有的元素,现在我们想做的事情是遍历每一个元素,然后为它们添加一个彩色边边框。但是上面的代码究竟是怎么一回事呢?
[].forEach.call( $$('*'), function( element ) { /* 在这里修改颜色 */ });
首先,我们通过选择器获得的列表是一个NodeLists对象,它和JavaScript中的数组有点像,你可以使用方括号来获取其中的节点,你也可以检查它其中包含多少个元素,但是它并没有实现数组包含的所有方法,因此我们并不能使用$$('*').forEach()来进行迭代。在JavaScript中,有好几个类似于数组但是并不是数组的对象,除了前面的NodeLists,还有函数的参数集合arguments,在这里我们可以使用call或apply函数将函数的方法运用到这些对象上。例如下面的例子:
function say(name) {
console.log( this + ' ' + name );
}
say.call( 'hola', 'Mike' ); // 打印 'hola Mike'
// 你也可以将这种方法有用在arguments对象上 function example( arg1, arg2, arg3 ) { return Array.prototype.slice.call(arguments, 1); // Returns [arg2, arg3] }
在Addy的代码中,使用了[].forEach.call而不是Array.prototype.forEach.call,二者等价,但是前者可以节省几个字节。
为元素添加颜色
为了让元素都有一个漂亮的边框,我们在上面的代码中使用了CSS属性outline。outline属性位于CSS盒模型之外,因此它并不影响元素的属性或者元素在布局中的位置,这对于我们来说非常有用。这个属性和修改border属性非常类似,因此下面的代码应该不会很难理解:
a.style.outline="1px solid #" + color
真正有趣的地方在于定义颜色部分:
~~(Math.random()*(1<<24))).toString(16)
天呐,上面的代码是什么意思?在JavaScript中,比特操作符并不是经常被使用,因此这里可能会让很多程序员感到很疑惑。
我们想达到的目的是活的一个十六进制格式的颜色例如白色对应的是FFFFFF,蓝色对应的是0000FF,或者随便一个颜色37f9ac。虽然我们人类喜欢十进制,但是我们的代码常常会需要十六进制的东西。
我们首先要学会如何使用toString函数将一个十进制的数组转换为一个十六进制整数。这个函数可以接受一个参数,如果参数缺省,默认为十进制,但是你完全可以使用别的数组:
(30).toString(); // "30"
(30).toString(10); // "30"
(30).toString(16); // "1e" 十六进制
(30).toString(2); // "11110" 二进制
(30).toString(36); // "u" 36是允许的最大参数值
除此之外,你可以使用parseInt函数将十六进制数字转换为十进制。
parseInt("30"); // "30"
parseInt("30", 10); // "30"
parseInt("1e", 16); // "30"
parseInt("11110", 2); // "30"
parseInt("u", 36); // "30"
因此,我们现在只需要一个位于0和ffffff之间的十六进制数,由于:
parseInt("ffffff", 16) == 16777215
而这里的16777215实际上是2^24-1。
如果你对二进制数学熟悉的话,你可能会知道1<<24 == 16777216。
再进一步,你每在1后面添加一个0,你就相当于多做了一次2的乘方:
1 // 1 == 2^0
100 // 4 == 2^2
10000 // 16 == 2^4
1000000000000000000000000 // 16777216 == 2^24
因此,在这里我们可以知道Math.random()*(1<<24)表示一个位于0和16777216之间的数。
但是这里并没有结束,因为Math.random返回的是一个浮点数,但是我们只想要整数部分。我们的代码中使用波浪号操作符来完成这件事。波浪操作符在JavaScript中被用来对一个变量进行取反。
但是我们在这里并不关心取反,我们指向获取整数部分。因此我们还可以知道两次取反可以去掉一个浮点数的小数部分,因此~~的作用相当于parseInt:
var a = 12.34, // ~~a = 12
b = -1231.8754, // ~~b = -1231
c = 3213.000001 // ~~c = 3213; ~~a == parseInt(a, 10); // true
~~b == parseInt(b, 10); // true
~~c == parseInt(c, 10); // true
当然,我们还有一种更加简洁的方法,使用OR操作符:
~~a == 0|a == parseInt(a, 10)
~~b == 0|b == parseInt(b, 10)
~~c == 0|c == parseInt(c, 10)
最终,我们获得了一个位于0和16777216之间的随机整数,也就是我们想要的随机颜色。此时我们只需要使用toString(16)将它转化为十六进制数即可。
总结
现在,你已经完全理解了前面的这一行代码中的各个部分。作为一个程序员,我们应该在完成工作之后多问自己几遍为什么,还有没有更好更简洁的方法。当然,最应该做的事情当然是多阅读程序代码,也许你就能从某一行代码中学到很多新东西。
本文参考自Learning much javascript from one line of code,原文地址http://arqex.com/939/learning-much-javascript-one-line-code
从一行代码里面学点JavaScript的更多相关文章
- [转]从一行代码里面学点JavaScript
现如今,JavaScript无处不在,因此关于JavaScript的新知识也是层出不穷.JavaScript的特点在于,要学习它的语法入门简简单,但是要精通使用它的方式却是一件不容易的事. 来看看下面 ...
- 前端读者 | 从一行代码里面学点JavaScript
本文来自 @张小俊128:链接:http://www.html-js.com/article/A-day-to-learn-from-a-line-of-code-inside-the-JavaScr ...
- NodeJS服务器:一行代码 = 一个的HTTP服务器
从这一篇开始,我们进入技术讲解的话题,逐步实现用NodeJS实现文件的传送共享服务. 前文我们讲过,NodeJS是最擅长做网络服务器的,今天我们就来用NodeJS做一个最简单的服务器. 先看一幅图: ...
- 一行能装逼的JavaScript代码
一行能装逼的JavaScript代码 2016-06-28 野狗 一行神奇的JS代码,当时我就震 惊了,这不就是传说中的ZB神奇么… … 哈哈. 写本篇文章的缘由是之前看到了一段js代码,如下: (! ...
- Asp.Net Core 轻松学-一行代码搞定文件上传 JSONHelper
Asp.Net Core 轻松学-一行代码搞定文件上传 前言 在 Web 应用程序开发过程中,总是无法避免涉及到文件上传,这次我们来聊一聊怎么去实现一个简单方便可复用文件上传功能:通过创建 ...
- 一行能装逼的JavaScript代码的延伸
前段就是坑,入坑水真深. 先看看一个黑科技, 纳尼,这是什么东西. (!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]]+({}+[])[[~!+ ...
- 33个非常实用的JavaScript一行代码
33个非常实用的JavaScript一行代码 一.日期处理 1. 检察日期是否有效 该方法用于检测给出的日期是否有效: const isDateValid = (...val) => !Numb ...
- 微软出品自动化神器Playwright,不用写一行代码(Playwright+Java)系列(一) 之 环境搭建及脚本录制
一.前言 半年前,偶然在视频号刷到某机构正在直播讲解Playwright框架的使用,就看了一会,感觉还不错,便被种草,就想着自己有时间也可以自己学一下,这一想着就半年多过去了. 读到这,你可能就去百度 ...
- 一行代码解决各种IE兼容问题,IE6,IE7,IE8,IE9,IE10
行代码解决各种IE兼容问题,IE6,IE7,IE8,IE9,IE10 2012-04-25 16:29:04| 分类: 学习 |字号 订阅 在网站开发中不免因为各种兼容问题苦恼,针对兼容问题,其实IE ...
随机推荐
- LoadRunner检查点实战
码农博客 即将到期,现将博客中部分文章转载到博客园.转载时略有删减. 一.为什么要使用检查点 为什么要使用检查点,那就要说明一下LR如何判断脚本是否执行成功. LR判断脚本是否执行成功是根据服务器返回 ...
- 【Linux学习】 写一个简单的Makefile编译源码获取当前系统时间
打算学习一下Linux,这两天先看了一下gcc的简单用法以及makefile的写法,今天是周末,天气闷热超市,早晨突然发现住处的冰箱可以用了,于是先出去吃了点东西,然后去超市买了一坨冰棍,老冰棍居多, ...
- <转>详解DNS的常用记录(上):DNS系列之二
详解DNS的常用记录(上) 在上篇博文中,我们介绍了DNS服务器的体系结构,从中我们了解到如果我们希望注册一个域名,那么必须经过顶级域名服务器或其下级的域名服务器为我们申请的域名进行委派,把解析权委派 ...
- (一)使用Blender导出GameMaker支持的模型脚本
源于YOYO论坛帖子:http://gmc.yoyogames.com/index.php?showtopic=603723 既然想做3D,那就先从模型的导入开始,具体的源文件,可以在“(二)使用等高 ...
- ckeditor+jsp+spring配置图片上传
CKEditor用于富文本输入是极好的,它还有一些插件支持扩展功能,其中图片上传就是比较常用到的.本文简单记录我的实现步骤. 1.CKEditor除了提供三种标准版压缩包下载,还可根据自己的需求进行个 ...
- android Loger日志类(获取内置sd卡)
Android手机自带内部存储路径的获取 原文地址:http://my.oschina.net/liucundong/blog/288183 直接贴代码: public static String g ...
- Blogilo:Ubuntu下“wlw”
原文首发:http://www.ido321.com/1274.html 这一篇博客是在Ubuntu的博客客户端blogilo下发布的,感觉有点高大上,特此发布一篇博文记录一下. 博客发布在 ...
- 微软Azure已开始支持hadoop--大数据云计算
微软Azure已开始支持hadoop,对于有需要弹性大数据运算的公司可能是个好消息.据悉,近期微软已提供一个预览版的Azure HDInsight(Hadoop on Azure)服务,运行在Linu ...
- Azure支持docker简介以及使用指南
Docker 是一个开源的项目,主要的特点是能将应用程序包装在一个 LXC (Linux Container) 容器中,当这些应用被包装进容器后,部署.迁移都变得更为简单.与传统的虚拟化技术相比,虚拟 ...
- VS20xx下项目开发目录管理方法
在VS20XX之后项目管理使用解决方案(solution)管理一个大的开发工程中多个项目(Project). 以下目录配置与工程名称无关,适用于一般的工程组织过程. 对于一般的生成可执行程序的工程,使 ...