`
2008winstar
  • 浏览: 57051 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
  • chenke: 写的很好,也可以看看那这个文章,我感觉学的还可以。http:/ ...
    HTML

通过一行代码学JavaScript

 
阅读更多

本文内容源于这里

 

首先来看下面这行代码:

[].forEach.call($$("*"),function(a){
  a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)
})

 

你可以在浏览器的控制台执行这段代码,你会看到页面中不同的HTML结构被不同颜色的框圈着。是不是很神奇呢?

 

其实,它只是进行了如下的操作:获取页面的所有元素,然后给这些元素加上1px的外框(outline),并且使用了随见的颜色。

 

想法虽然简单,但是要想写出这样的代码,必须对web开发非常熟练。下面通过具体地分析这段代码,来学习相关的知识。

 

(1)选择页面中的所有元素

在浏览器的控制台中可以使用$$()方法来获取页面中相应的元素,如在浏览器的JavaScript控制台中输入$$('a')并执行,可以得到由当前页面所有<a>标签元素组成的一个列表。

 

$$函数是现代浏览器提供的一个命令行API,它相当于document.querySelectorAll,可以将当前页面中的CSS选择器作为参数传给该方法,然后它会返回匹配的所有元素。

 

所以,如果想在浏览器控制台外使用上面这段代码,可以将$$('*')替换为document.querySelectorAll('*')。

 

(2)遍历元素

通过$$('*')的方式,我们得到了由页面中所有元素组成的一个NodeList节点列表,我们希望为这些节点加上不同颜色的外框。

 

注意上段代码中的以下部分:

[].forEach.call( $$('*'), function( a ) { /* 具体的操作 */ });

 

NodeLists有点类似数组,可以通过中括号的方式获取列表中的节点,也可以通过length属性获得列表的长度,但是它不具备数组所具有的方法,因此,无法直接使用$$('*').forEach()。

 

在JavaScript中,有好几个对象表现得与数组类似,但是它们都不是数组,比如函数内部的arguments变量。

 

虽然无法直接调用数组方法,但是我们可以通过一个实用的模式来解决它:通过使用函数的call和apply方法,可以实现在类似NodeLists这样的非数组对象上调用数组方法。

 

函数的call方法使用示例:

function say(name) {
 console.log( this + ' ' + name );
}
 
say.call( 'hola', 'Mike' ); // Prints out 'hola Mike' in the console
 
// Also you can use it on the arguments object
function example( arg1, arg2, arg3 ) {
 return Array.prototype.slice.call(arguments, 1); // Returns [arg2, arg3]
}

 

在我们之前的那段代码中使用[].forEach.call而没有用Array.prototype.forEach.call简洁了许多。

 

(3)为元素添加颜色

代码中使用outline的CSS属性给元素添加一个边框。由于渲染的outline是不在CSS盒模型中的,所以为元素添加outline并不会影响元素的大小和页面的布局。但outline的语法与border属性类似,所以也不难理解。

a.style.outline="1px solid #" + color

 

关键是颜色的定义:

~~(Math.random()*(1<<24))).toString(16)

 

这里使用了位操作符。

我们希望得到是一个十六机制的颜色值如白色(FFFFFF)或者蓝色(0000FF)或者其它颜色(37f9ac)。

在上面这段代码中,首先我们学到的是使用toString()方法将一个小数转成十六进整数。toString()方法将数值转换成字符串时,接收一个参数用以指明数值的进制。如果省略了该参数,则默认采用十进制,但你可以指定为其他的进制,如下所示。

(30).toString(); // "30"
(30).toString(10); // "30"
(30).toString(16); // "1e" Hexadecimal
(30).toString(2); // "11110" Binary
(30).toString(36); // "u" 36 is the maximum base allowed

 

与之对应,你也可以使用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(可以在控制台试一下)。

 

接下来,通过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
Again, if you go to the gist and have a look

 

这样最终我们得到了0至16777216之间的随机数,可以用于产生一个随机颜色。得到相应的颜色,我们只需将对应的随机数通过使用toString(16)方法将其转化为十六进制表示的字符串即可。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics