A popular line of code on the web, supposedly written by a Google engineer, adds a randomly colored border to all elements of a page.

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

The operation effect is shown as follows:

Although this code is only one line, but contains a lot of knowledge, there are a lot of online analysis. I’ll explain my understanding, and then finally recommend using TreeWalker objects for traversal in practice.

My understanding mainly includes the following four knowledge points:

1. [].forEach.call
2. $$("*")
3. a.style.outline
4. (~~(Math.random()*(1<<24))).toString(16)
Copy the code

1 [].forEach.call

[1.1]. ForEach

ForEach is an array traversal method that takes a function argument to process each traversal element.

let arr = [3.5.8];
arr.forEach((item) = > {
	console.log(item);
})
// Console output:
/ / 3
/ / 5
/ / 8
Copy the code

So here’s how:

[].forEach
Copy the code

This is just to get the forEach method, which is defined on array. prototype. [] represents an empty Array and can be accessed on an Array prototype object.

Once you have the forEach method, you can call it through call.

1.2 the call

The call function is used to call a function. Unlike a normal call, a call can modify the this reference within the function.

The general call to a function posture:

let object1 = {
	id: 1.printId() {
		console.log(this.id)
	}
}
object1.printId();
// Console output:
/ / 1
Copy the code

Because it is a normal call, this in the method points to the object1 object, so the previous example prints 1.

Call printId with call and pass in another object object2:

let object2 = {
	id: 2
}
object1.printId.call(object2);
// Console output:
/ / 2
Copy the code

Used here call call object1. PrintId function, introduced into object2 object, then printId function of this is to point to object2 this object, so the result output 2.

1.3 Comprehensive Analysis

Taken together:

[].forEach.call( $$("*"), function(a){})Copy the code

This line of code traverses the following objects:

$$,"*") 
Copy the code

Then treat each element as follows:

function(a){}
Copy the code

Where a is each of the elements that are iterated over.

then

$$,"*") 
Copy the code

What does it mean? Let’s look back.

2 $$(” * “)

This is used to get all the elements of the page

document.querySelectorAll(The '*')
Copy the code

just

$$,"*") 
Copy the code

It can only be used in the browser development console. This is a predefined API provided by the browser development console. For details, see the reference article at the bottom.

3 a.style.outline

Set the element border, estimated many people know, but set the outer border is relatively few people understand, the effect of the outer border and the border is similar, the only difference is the outer border box model formula, only for decoration use.

<style type="text/css">
	#swiper {
		width: 100px;
		height: 100px;
		outline: 10px solid;
	}
</style>

<div id="swiper"></div>
Copy the code

Operation effect:

The actual width and height of the div element is still 100 * 100. If you change the outline to border, the actual width and height of the div element is 120 * 120 because you want to add the width of border.

The biggest effect of the outer border Settings is:

You can set the border effect without affecting the layout of the page.Copy the code

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

This code gets a hexadecimal color value from the result, but why?

Hexadecimal color value: 81F262Copy the code

4.1 Math. The random ()

This is easy to understand. It’s a random [0, 1] decimal.

4.2 1 < < 24

This represents a shift of 1 to the left by 24 bits, and the binary representation is as follows:

1 0000 0000 0000 0000 0000Copy the code

The decimal notation means:

2 ^ 24Copy the code

then

Math.random() * (1<<24)
Copy the code

You get a random floating point number in the following range:

[0, 2 ^ 24)Copy the code

4.3 Reverse bit twice

Because math.random () results in a decimal, the reverse bit is used twice to filter out the decimal and get an integer.

so

(~~(Math.random()*(1<<24)))
Copy the code

You get a random integer in the following range:

[0, 2 ^ 24)Copy the code

4.4 Converting toString(16)

The last step is to convert the above number to hexadecimal. We know that toString() is used to convert the related object to a string. It can take a base argument and convert it to a different base.

Object. ToString (2); // Convert to base 2Object. ToString (8); // Convert to base 8Object. ToString (10); // Convert to base 10Object. ToString (16); // Convert to hexadecimal
Copy the code

The resulting random integers in binary form are:

0000 0000 0000 0000 0000 to 1111 1111 1111 1111 1111 1111Copy the code

So if you go from base 2 to base 16, is that one for every four digits?

Did I end up with a hexadecimal number of six lengths?

Is this string plus # the hexadecimal color value?

Like:

# ac83CE #b74384 etc...Copy the code

Practical application

While the code above is short and knowledgeable, I wouldn’t recommend this approach in practice if you want to iterate over elements.

There are two main reasons:

1. $$("*") is only available in the development console, not in normal project code. 2. Select all elements and iterate again, but the performance is low.Copy the code

If you are iterating through elements in your practice, the recommendation is to use TreeWalker. QuerySelectorAll fetches all elements at once and iterates through them. TreeWalker is an iterator. TreeWalker is superior in terms of performance, and TreeWalker also supports various filters.

See the following example:

// Instantiate the TreeWalker object
let walker = document.createTreeWalker(
	document.documentElement,
	NodeFilter.SHOW_ELEMENT
);
/ / traverse
let node = walker.nextNode();
while(node ! = =null) {
	node.style.outline = "1px solid #"+ (~ ~ (Math.random() * (1 << 24))).toString(16);
	node = walker.nextNode();
}
Copy the code

More code, better performance at the time, and support for various filters, and more powerful.

If you learn a new pose, please give it a thumbs up. Thank you. Please leave comments and discuss.

The resources

What $$(*) stands for in JavaScript and the origin of the $selector: ourjs.com/detail/54ab…

QuerySelectorAll vs NodeIterator vs TreeWalker:stackoverflow.com/questions/6…