-
Notifications
You must be signed in to change notification settings - Fork 731
/
dom.html
801 lines (768 loc) · 48.8 KB
/
dom.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="that js dude" content="">
<title>JS: DOM related Questions</title>
<link rel="shortcut icon" href="images/favicon.jpg">
<link rel="stylesheet" href="css/bootstrap.min.css" >
<link rel="stylesheet" href="css/zenburn.css">
<!-- Custom styles for this template -->
<style>
/* Move down content because we have a fixed navbar that is 50px tall */
body {
padding-bottom: 20px;
}
.purpleBold{
color:purple;
font-weight: bold;
}
.gray{
color: gray;
}
.blueish{
color: rgba(151, 182, 209, 0.98);
}
.singInStuff{
margin-top: 9px;
}
#uName{
margin-top: -7px;
}
.skipListItem{
list-style-type: none;
}
.skipListItem a{
color: inherit;
}
a:visited
{
color: rgba(218, 209, 149, 0.98);
}
.padding10Px{
padding: 10px;
}
.item{
margin-left: 2em;
}
/*style for demo*/
</style>
<!-- Just for debugging purposes. Don't actually copy this line! -->
<!--[if lt IE 9]><script src="docs-assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
<div class="container">
<h1>JS: DOM related Interview Questions</h1>
<h4>21+ DOM related interview questions for intermediate JavaScript developers</h4>
<h2>part-3: intermediate</h2>
<p>May 29, 2014</p>
<div id="fb-root"></div><div class="fb-like" data-href="http://www.thatjsdude.com/interview/dom.html" data-layout="button_count" data-action="like" data-show-faces="false" data-share="false"></div><div class="g-plusone"></div>
</div>
</div>
<div class="container container-fluid">
<!-- Example row of columns -->
<div class="row center">
<!-- <iframe width="853" height="480" src="//www.youtube.com/embed/Rx_JFOSxgpY" frameborder="0" allowfullscreen></iframe> -->
</div>
<!-- <p class="gray">if you are little more comfortable or claim to be comfortable with javascript, these questions would not be enough for you. more coming</p>
<p class="gray"> <span class="purpleBold">More Questions</span> <a href="css.html">css interview questions</a>, <a href="html.html">html interview questions</a> </p> -->
<div id="questionList">
<ol>
<li><a href="#windwoVsDocument">Is there any difference between window and document?</a></li>
<li><a href="#compareTwoOnload">Does document.onload and window.onload fire at the same time?</a></li>
<li><a href="#attrVSProperty">Is attribute similar to property?</a></li>
<li><a href="#queryDOM">What are the different ways to get an element from DOM?</a></li>
<li><a href="#fastestDOMQuery">What is the fastest way to select elements by using css selectors?</a></li>
<li><a href="#nodeListVsArray">How come, I can't use forEach or similar array methods on a NodeList?</a></li>
<li><a href="#getElementByallAttribute">If you need to implement getElementByAttribute, how would you implement it?</a></li>
<li><a href="#addClass">How would you add a class to an element by query selector?</a></li>
<li><a href="#isDescendant">How could I verify whether one element is child of another?</a></li>
<li><a href="#innerHTMLVsAppendChild">What is the best way to create a DOM element? Set innherHTML or use createElement?</a></li>
<li><a href="#createDocumentFragment">What is createDocumentFragment and why you might use it?</a></li>
<li><a href="#reflow">What is reflow? What causes reflow? How could you reduce reflow?</a></li>
<li><a href="#repaint">What is repaint and when does this happen?</a></li>
<li><a href="#domReady">How could you make sure to run some JavaScript when DOM is ready like <code>$(document).ready</code>?</a></li>
<li><a href="#eventBubble">What is event bubble? How does event flows in DOM?</a></li>
<li><a href="#eventDelegate">How would you destroy multiple list items with one click handler?</a></li>
<li><a href="#unintendedClosure">If you are looping through a collection of dom and adding a click handler like the example below. What will happen if you click on the item?</a></li>
<li><a href="#mythicalHydra">Create a button that is destroyed by clicking in it but two new buttons are created in it's place.</a></li>
<li><a href="#captureAllClick">How could you capture all clicks in a page?</a></li>
<li><a href="#allTextInAPage">How can you get all the texts in a web page?</a></li>
<li><a href="#deferAsync">What is defer and async keyword does in a script tag?</a></li>
<li><a href="#domRapidFire">10 rapid fire questions</a></li>
</ol>
</div>
<div class="bg-success text-warning padding10Px">
<h5>DOM provides an API to access and modify structure, style and content of a web page through objects (nodes or elements), properties and methods. <a href="https://developer.mozilla.org/en-US/docs/DOM/DOM_Reference/Introduction">learn more...</a></h5>
</div>
<div id="windwoVsDocument">
<h2>1. window vs document</h2>
<p><strong>Question: </strong> Is there any difference between window and document?</p>
<p><strong>Answer: </strong> Yes. JavaScript has a global object and everything runs under it. window is that global object that holds global variables, global functions, location, history everything is under it. Besides, setTimeout, ajax call (XMLHttpRequest), console or localStorage are part of window. </p>
<p> document is also under window. document is a property of the window object. document represents the DOM and DOM is the object oriented representation of the html markup you have written. All the nodes are part of document. Hence you can use getElementById or addEventListener on document. These methods are not present in the window object.</p>
<pre><code>
window.document === document; //true
window.getElementById; //undefined
document.getElementById; //function getElementById() { [native code] }
</code></pre>
<p>ref: <a href="http://eligeske.com/jquery/what-is-the-difference-between-document-and-window-objects-2/">document and window</a></p>
</div>
<div id="compareTwoOnload">
<h2>2. window.onload vs document.onload</h2>
<p><strong>Question:</strong> Does document.onload and window.onload fire at the same time?</p>
<p><strong>Answer:</strong> <code>window.onload</code> is fired when DOM is ready and all the contents including images, css, scripts, sub-frames, etc. finished loaded. This means everything is loaded.</p>
<p><code>document.onload</code> is fired when DOM (DOM tree built from markup code within the document)is ready which can be prior to images and other external content is loaded.</p>
<p>Think about the differences between <code>window</code> and <code>document</code>, this would be easier for you.</p>
<p><strong>Bonus:</strong><code>document.readyState</code> Returns "loading" while the Document is loading, "interactive" once it is finished parsing but still loading sub-resources, and "complete" once it has loaded. The <code>readystatechange</code> event fires on the Document object when this value changes.</p>
<p>ref: <a href="https://developer.mozilla.org/en-US/docs/Web/API/document.readyState">MDN: readyState</a></p>
</div>
<div id="attrVSProperty">
<h2>3. attribute vs property</h2>
<p><strong>Question: </strong> Is attribute similar to property?</p>
<p><strong>Answer: </strong> attributes are just like attribute in your html tag (XML style attribute) inside the starting tag. html attributes are exposed to the DOM via property. Hence, a property is created when DOM is parsed for each attribute in the html tag. If you change an attribute only the value of the property will change. However, the value of attribute will remain same.<p>
<div>
<button id = "attrVsProp" type="button" class="toggleExample btn btn-primary">Show more</button>
<div id="attrVsPropExample" class="hide bg-success padding10Px">
<p>For example, if you have a input with three attribute- id, type, value.</p>
<pre><code>
<input id="my-input" type="text" value="Name:">
</code></pre>
<p>If you type "my dude" in the text box. The value property will be changed but value attribute will remain unchanged.</p>
<pre><code>
var myInput = document.getElementById('my-input');
myInput.getAttribute('value'); //"Name:"
myInput.value; //'my dude'
</code></pre>
<p>However, if you change the value of an attribute by using <code>myInput.setAttribute('value', 'that dude')</code> or <code>myInput.removeAttribute()</code>, then value of attribute will be changed.</p>
<p>ref: <a href="http://jquery-howto.blogspot.com/2011/06/html-difference-between-attribute-and.html">attr vs property</a></p>
</div>
</div>
</div>
<div id="queryDOM">
<h2>4. DOM Query</h2>
<p><strong>Question: </strong> What are the different ways to get an element from DOM?</p>
<p><strong>Answer: </strong> You can use the following methods in <code>document</code></p>
<ul>
<li><code>getElementById</code> to get a element that has the provided Id.</li>
<li><code>getElementsByClassName</code> to get a nodelist (nodelist is not an array, rather it is array-like object) by providing a class name.</li>
<li><code>getElementsByTagName</code> to get a nodelist by the provided tag name.</li>
<li><code>querySelector</code> you will pass css style selector (jquery style) and this will retrurn first matched element in the DOM.</li>
<li><code>querySelectorAll</code> will return a non-live nodelist by using depth-first pre order traversal of all the matched elements. Non-live means, any changes after selecting the elements will not be reflected.</li>
</ul>
<p>There are two more options but I dont use them frequently-</p>
<ul>
<li><code>getElementsByName</code> returns the list of elements by the provided name of the html tag</li>
<li><code>getElementsByTagNameNS</code> returns elements with particular tag name within the provided namespace</li>
</ul>
</div>
<div id="fastestDOMQuery">
<h2>5. Fastest way to Query DOM</h2>
<p><strong>Question:</strong> What is the fastest way to select elements by using css selectors?</p>
<p><strong>Answer:</strong> It depends on what you are selecting. If you have an ID of an element <code>getElmentById</code> is the fastest way to select an element. However, you should not have so many ID in you document to avoid style repetition. css class <code>getElementsByClassName</code> is the second quickest way to select an element</p>
<p>Here is the list. As we go downwards through the list, it takes more time to select elements. </p>
<ul>
<li>ID (#myID)</li>
<li>Class (.myClass)</li>
<li>Tag (div, p)</li>
<li>Sibling (div+p, div~p)</li>
<li>child (div>p)</li>
<li>Descendant (div p)</li>
<li>Universal (*)</li>
<li>Attribute (input[type="checkbox"])</li>
<li>Pseudo (p:first-child)</li>
</ul>
<p>If you have crazy long selectors to select element, think about your selectors and check whether you can use a class instead.</p>
<div>
<button id = "byClassVsSelectorAll" type="button" class="toggleExample btn btn-primary">Show deeper question</button>
<div id="byClassVsSelectorAllExample" class="hide bg-success padding10Px">
<p><strong>Question: </strong> Why <code>querySelectorAll('.my-class')</code> is slower than <code>getElementsByClassName('my-class')</code>?</p>
<p><strong>Answer: </strong> querySlectorAll is a generic purpose method. It is optimized for different kinds of selectors. Hence it has to check whether you put a "#" or "." in front of the parameter you are passing. If you are just passing a class name with ".", under the hood it uses <code>getElementsByClassName</code> (could vary based on browser implements). Whereas if you directly uses <code>getElementsByClassName</code> it directly uses this method and doesn't have to go through all the initial processing of <code>querySelectorAll</code>. Hence to search elements with a particular class name, getElementsByClassName is faster than querySelectorAll.</p>
</div>
</div>
</div>
<div id="nodeListVsArray">
<h2>6. Use forEach on NodeList</h2>
<p><strong>Question: </strong>How come, I can't use forEach or similar array methods on a NodeList?</p>
<p><strong>Answer: </strong> Yeah. Both array and nodeList have length and you can loop through elements but they are not same object.</p>
<p>Both are inherited from Object. However array has different prototype object than nodeList. forEach, map, etc are on array.prototype which doesn't exist in the NodeList.prototype object. Hence, you don't have forEach on a nodeList</p>
<pre><code>
myArray --> Array.prototype --> Object.prototype --> null
myNodeList --> NodeList.prototype --> Object.prototype --> null
</code></pre>
<p><strong>Question: </strong> How could you solve this problem? </p>
<p><strong>Answer: </strong> To solve this problem, you can simply loop through a nodeList and do whatever you wanted to inside forEach or you can call method on array to convert nodelist to an array. After that you will have access to all array.prototype methods</p>
<pre><code>
var myNodeList = document.querySelectorAll('.my-class');
var nodesArray = Array.prototype.slice.call(myNodeList);
//use array method on nodeList
nodesArray.forEach(function(el, idx){
console.log(idx, el);
});
</code></pre>
<p>ref: <a href="https://developer.mozilla.org/en-US/docs/Web/API/NodeList">MDN: nodelist</a></p>
</div>
<div id="getElementByallAttribute">
<h2>7. getElementsByAttribute</h2>
<p><strong>Question:</strong> If you need to implement getElementByAttribute, how would you implement it?</p>
<p><strong>Answer: </strong> First, get all the elements in the DOM. You can either get it by Tag Name '*' and then check whether they have the particular attribute. In this case, even if attribute is null that will be captured. If you need to check the value, you should be able to do it by passing one extra parameter and comparing it in the if block.</p>
<pre><code>
function getElementsByAttribute(attribute){
var allElements = document.getElementsByTagName('*'),
elm,
found=[];
for (var i = 0; i < allElements.length; i++)
{
elm = allElements[i];
if (elm.getAttribute(attribute))
{
found.push(elm);
}
}
return found;
}
</code></pre>
<div>
<button id = "betterByAttribute" type="button" class="toggleExample btn btn-primary">Show better algorithm</button>
<div id="betterByAttributeExample" class="hide bg-success padding10Px">
<p><strong>Question: </strong> Can you make it better?</p>
<p><strong>Answer: </strong> Yes. The example above, I am getting all the elements and then comparing the attribute. I can check the attribute while getting the elements.</p>
<pre><code>
// todo: prettify this ugly code
function getElementsByAttribute2(attr){
var found = [],
child;
function getNodeText(node){
if(node && node.childNodes && node.childNodes.length){
for(var i = 0, len = node.childNodes.length; i<len; i++){
child = node.childNodes[i];
if(child && child.getAttribute && child.getAttribute(attr)){
found.push(child);
}
getNodeText(child);
}
}
else{
if(node.getAttribute && node.getAttribute(attr)){
found.push(node);
}
}
}
getNodeText(document.body);
return found;
}
</code></pre>
<p>If you want to make it even faster, you could try DOM traverse by using <a href="https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker">TreeWalker</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/NodeIterator">NodeIterator</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/NodeFilter">NodeFilter</a> or <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/traversal.html#Traversal-TreeWalker">find them in spec</a> . Unfortunately, I have no idea what I am talking about.</li></p>
</div>
</div>
<p><strong>Question: </strong> Can I add this <code>getElementsByAttribute</code> to <code>document</code>?</p>
<p><strong>Answer: </strong> Mr. Interviewer, please read this article: <a href="http://perfectionkills.com/whats-wrong-with-extending-the-dom/">whats wrong with extending the dom</a></p>
</div>
<div id="addClass">
<h2>8. add class</h2>
<p><strong>Question:</strong> How would you add a class to an element by query selector?</p>
<p><strong>Answer: </strong> Very simple. Just get the element and add the classname to the classlist.</p>
<pre><code>
function addClass(selector, className){
var elm = document.querySelector(selector);
if (elm){
elm.classList.add(className);
}
}
</code></pre>
<p>Similarly, you can implement removeClass, toggleClass and hasClass</p>
<pre><code>
//IE9+
el.classList.remove('my-class'); //removing a class
el.classList.toggle('my-class'); // toggling a class
el.classList.contains('my-class'); // checking whether class exists
</code></pre>
<p>ref: <a href="http://youmightnotneedjquery.com/">you might not need jquery</a>.</p>
</div>
<div id="isDescendant">
<h2>9. Check Descendant</h2>
<p><strong>Question:</strong> How could I verify whether one element is child of another?</p>
<p><strong>Answer:</strong> First check whether the passed parent is the direct parent of the child. If not, keep moving upward to the root of the tree.</p>
<pre><code>
function isDescendant(parent, child){
while(child.parentNode ){
if(child.parentNode == parent)
return true;
else
child = child.parentNode;
}
return false;
}
</code></pre>
</div>
<div id="innerHTMLVsAppendChild">
<h2>10. innerHTML vs appendChild </h2>
<p><strong>Question: </strong> What is the best way to create a DOM element? Set innherHTML or use createElement?</p>
<p><strong>Answer: </strong> When you set innerHTML property, browser removes all the current children of the elements. Parse the string and assign the parsed string to the element as children.</p>
<p>For example, if you want to add a list item to an unorderedList. You can get the element and set the innerHTML of the element like</p>
<pre><code>
var ul = document.getElementById('myList');
el.innerHTML = '<li>Only one item</li>';
</code></pre>
<p><strong>Extra Credit: </strong> innerHTML could be slow while parsing a string. Browser has to deal with the string and if you have crappy html (invalid html).</p>
<h4>appendChild</h4>
<p>On the other hand, while using appendChild, you create a new Element. Since you are creating it, browser doesnt have to parse string and there is no invalid html. And you can pass the child to the parent and child will be appended to the parent.</p>
<pre><code>
var li = document.createElement("li");
var text = document.createTextNode('Only one Item');
li.appendChild(text);
ul.appendChild(li);
</code></pre>
<p><strong>Extra Credit: </strong> If you pass a reference to be appended as child other than creating a new element. The reference you are passing will be removed from the current parent and will be added to the new parent you are appending to.</p>
<p>Though you would be writing couple more lines of JavaScript, it makes browsers life easier and your page faster.</p>
</div>
<div id="createDocumentFragment">
<h2>11. CrateDocumentFragment</h2>
<p><strong>Question: </strong> What is createDocumentFragment and why you might use it?</p>
<p><strong>Answer: </strong> <code>documentFragment</code> a very lightweight or minimal part of a DOM or a subtree of a DOM tree. It is very helpful when you are manipulating a part of DOM for multiple times. It becomes expensive to hit a certain portion of DOM for hundreds time. You might cause reflow for hundred times. Stay tuned for reflow.</p>
<p>If you are changing dom that cause expensive reflow, you can avoid it by using <code>documentFragment</code> as it is managed in the memory.</p>
<pre><code>
//bad practice. you are hitting the DOM every single time
var list = ['foo', 'bar', 'baz', ... ],
el, text;
for (var i = 0; i < list.length; i++) {
el = document.createElement('li');
text = document.createTextNode(list[i]);
el.appendChild(text);
document.body.appendChild(el);
}
</code></pre>
<pre><code>
//good practice. you causing reflow one time
var fragment = document.createDocumentFragment(),
list = ['foo', 'bar', 'baz', ...],
el, text;
for (var i = 0; i < list.length; i++) {
el = document.createElement('li');
text = document.createTextNode(list[i]);
el.appendChild(text);
fragment.appendChild(el);
}
document.body.appendChild(fragment);
</code></pre>
<p>ref: <a href="http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-B63ED1A3">W3: spec</a></p>
</div>
<div id="reflow">
<h2>12. reflow</h2>
<p><strong>Question: </strong> What is reflow? What causes reflow? How could you reduce reflow?</p>
<p><strong>Answer: </strong> Aha... so many questions at the same time. Take a breathe Mr. Interviewer.</p>
<p><strong>reflow: </strong> When you change size or position of an element in the page, all the elements after it has to change their position according to the changes you made. For example, if you change height on an element, all the elements under it has to move down in the page to accomodate a change in height. Hence, flow of the elements in the page is changed and this is called reflow.</p>
<p><strong>Why reflow is bad: </strong> Reflows could be very expensive and it might have a performance hit specially in the smaller devices like phone. As it might causes changes in the portion (or whole) layout of the page.</p>
<div>
<button id = "reflowExplanation" type="button" class="toggleExample btn btn-primary">Show more explanation</button>
<div id="reflowExplanationExample" class="hide bg-success padding10Px">
<p>In the images below, effect of reflow is shown in a yellow box. Reflow causes changes in the render tree which changes the layout of the page. Eventually browser has to paint the changes so that you can see your awesome changes.</p>
<img src="images/reFlow.png" alt="">
<p>Image source: original image is taken from W3 site but I added the yellow box (my contribution).</p>
</div>
</div>
<p><strong>Reasons to reflow:</strong> The following cases causes reflow</p>
<ul>
<li>change layout (geometry of the page)</li>
<li>resize the window</li>
<li>change height/width of any element</li>
<li>changing font</li>
<li>change font size</li>
<li>move DOM element (animation)</li>
<li>adding or removing stylesheet</li>
<li>calculating offset height or offset width</li>
<li><code>display: none;</code></li>
</ul>
<p><strong>How to avoid:</strong> To avoid reflow, try to avoid doing things in the above list and some more in the below</p>
<ul>
<li>avoid setting multiple inline style</li>
<li>apply animation to the elements that are positioned fixed or absolute</li>
<li>avoid tables for layout</li>
</ul>
<p>ref: <a href="http://www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performance-making-your-javascript-slow/">reflow and repaint: css performance makes your JS slow</a></p>
</div>
<div id="repaint">
<h2>13. repaint</h2>
<p><strong>Question: </strong> What is repaint and when does this happen?</p>
<p><strong>Answer: </strong> repaint happens when you change the look of an element without changing the size and shape. This doesn't cause reflow as geometry of the element didn't changed. </p>
<p><strong>How it happens: </strong></p>
<ul>
<li>change background color</li>
<li>change text color</li>
<li>visibility hidden</li>
</ul>
<div>
<button id = "repaintExplanation" type="button" class="toggleExample btn btn-primary">Show more explanation</button>
<div id="repaintExplanationExample" class="hide bg-success padding10Px">
<p>In the image below, only the painting and display part is changes due to repaint. Browser doesn't have to change the render tree or layout of the page. Hence, this is less expensive than reflow.</p>
<img src="images/repaint.png" alt="">
<p>image source: original image is taken from W3 site but i added the yellow box (my contribution).</p>
</div>
<p>If possible, prefer repaint over reflow.</p>
</div>
</div>
<div id="domReady">
<h2>14. DOM ready</h2>
<p><strong>Question: </strong> How could you make sure to run some javaScript when DOM is ready like <code>$(document).ready</code>?</p>
<p><strong>Answer: </strong> There are four different ways-</p>
<p><strong>option-1: </strong> Put your script in the last tag of html body element. DOM would be ready by the time browser hits the script tag.</p>
<p><strong>option-2: </strong> Place your code inside a <code>DOMContentLoaded</code> handler. This event will be fired when DOM is completely loaded.</p>
<pre><code>
document.addEventListener('DOMContentLoaded', function(){
//put your script here
});
</code></pre>
<p><strong>option-3: </strong> Watch changes in the readyState of the document. And the last state is "complete" state, you can put your code there.</p>
<pre><code>
document.onreadystatechange = function () {
if (document.readyState == "complete") {
//put your script here
}
}
</code></pre>
<p><strong>option-4: </strong> Search jquery source code and copy dom ready function. In that case you have a ready function that works in the older browsers as well without loading the whole jquery library.</p>
</div>
<div id="eventBubble">
<h2>15. Event bubble</h2>
<p><strong>Question:</strong> What is event bubble? How does event flows?</p>
<p><strong>Answer:</strong> To understand event bubble, you have to understand what happen when you click on anything on a page.</p>
<p><strong>Where you clicked:</strong> If you have a table with multiple rows and multiple columns and you click in one of the cell</p>
<ul>
<li>You will think that you have clicked on the cell and browser will know that you have a click handler with the cell that will be fired immediately.</li>
<li>You are completely wrong. Right away, browser doesn't know where you have clicked.</li>
</ul>
<p>The way browser find out where you have clicked are as follows-</p>
<ol>
<li><strong>Capture: </strong>When you clicked, browser knows a click event occurred. It starts from the window (lowest level/root of your website), then goes to document, then html root tag, then body, then table... its trying to reach the the as lowest level of element as possible. This is called capture phase (phase -1).</li>
<li><strong>Target:</strong> When browser reach the lowest level of element. In this case, you have clicked on a table cell (table data) hence target would be "td" tag. Then browser checks whether you have any click handler attached to this element. If there is any, browser executes that click hander. This is called target phase (phase -2).</li>
<li><strong>Bubbling: </strong>After firing click hander attached to "td", browser walks toward root. One level upward and check whether there is any click handler attached with table row ("tr" element). If there is any it will execute that. Then it goes to tbody, table, body, html, document, window. In this stage its moving upward and this is called event bubbling or bubbling phase (phase-3). Please note that, you clicked on cell but all the event handler with parent elements will be fired. This is actually very powerful (check event delegation)</li>
</ol>
<p></p>
<br>
<div>
<button id = "eventBubble" type="button" class="toggleExample btn btn-primary">Show a picture of bubble</button>
<div id="eventBubbleExample" class="hide bg-success padding10Px">
<p>Stare at the image for 5 min. Have a look at the left hand side where red arrows starts that is phase 1. The capture phase goes downward and found the target. This is target phase (phase-2), blue color. After that the bubbling phase starts (phase-3) in green arrows. Bubble stage goes all the way up to the root (window).</p>
<img src="images/eventBubble.png" alt="">
<p>Image source: <a href="https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#event-order-and-loops">event order and loop</a>.</p>
<p>If you want to stop the bubbling you have to explicitly call stopPropagation or stopImmediatePropagation</p>
</div>
</div>
<p><strong>Show live demo:</strong> <a href="http://www.thatjsdude.com/jsConcepts/concepts/eventPropagation.html">Go to this link</a> and click any layer to see event propagation.</p>
</div>
<div id="eventDelegate">
<h2>16. Event Delegate</h2>
<p><strong>Question:</strong> How would you destroy multiple list items with one click handler? </p>
<p><strong>Easy Solution:</strong> If you have one hundred list items that have similar event to handle. You can write one hundred event handler (actually copy paste) same code in 99 places. This works but if something changes in the event handler, you have to change in one hundred places. This doesn't call job security. This is called screwed up.</p>
<p>Second problem is if you want to dynamically add a new element, you have to make sure event handler is attached with the new element. More JavaScript code!</p>
<p><strong>Answer:</strong> We can actually leverage event bubbling. You can have only one event handler attached to the parent element of one hundred list items. In this case, you can attach the event handler to the "ul" tag. After you click on a list item (list item does not have an event), event will bubble and "ul" has a handler. That handler will be fired.</p>
<pre><code>
<ul id="listToDestroy">
<li><a href="#">first item</a></li>
<li><a href="#">second item</a></li>
<li><a href="#">third item</a></li>
<li><a href="#">forth item</a></li>
<li><a href="#">Fifth item</a></li>
</ul>
</code></pre>
<pre><code>
document.getElementById('listToDestroy').addEventListener('click', function (e) {
var elm = e.target.parentNode;
elm.parentNode.removeChild(elm);
e.preventDefault();
});
</code></pre>
<div>
<button id = "destroyLst" type="button" class="toggleExample btn btn-primary">Show demo</button>
<div id="destroyLstExample" class="hide bg-success padding10Px">
<ul id="listToDestroy">
<li><a href="#">first item</a></li>
<li><a href="#">second item</a></li>
<li><a href="#">third item</a></li>
<li><a href="#">forth item</a></li>
<li><a href="#">Fifth item</a></li>
</ul>
</div>
</div>
</div>
<div id="mythicalHydra">
<h2>17. destroy button</h2>
<p><strong>Question:</strong> Create a button that is destroyed by clicking on it but two new buttons are created in it's place.</p>
<p><strong>Answer:</strong> One way of solving is to attach a event handler with the button to destroy itself and append two. However, we can leverage event delegate. If we attach the event hander to the parent div instead of the button itself. We don't have to add the event handler to each button we create. So, we will take advantage of event bubbling.</p>
<p><strong>Try to be Smart:</strong> If both the newly created button is identical to one we are destroying, why interviewer wants to destroy exactly similar one and then create one. Why not just add one. And end result would be same, you will have two two buttons.</p>
<p><strong>Interviewer:</strong> I just want to see whether you can destroy any element. Make sure when you are destroying, there is no reference to the element, otherwise, you will have memory leak. If interviewer, says ok, just create one more button on click, then use your brain to change the following code.</p>
<pre><code>
<div id="doubleHolder">
<button class="double">double</button>
</div>
</code></pre>
<pre><code>
document.getElementById('doubleHolder').addEventListener('click', function (e) {
if(e.target.classList.contains('double')){
var btn = document.createElement('button');
btn.setAttribute('class', 'double');
btn.innerHTML = 'double';
var btn2 = document.createElement('button');
btn2.setAttribute('class', 'double');
btn2.innerHTML = 'double';
this.appendChild(btn);
this.appendChild(btn2);
this.removeChild(e.target);
}
});
</code></pre>
<div>
<button id = "destroyBtn" type="button" class="toggleExample btn btn-primary">Show clickable demo</button>
<div id="destroyBtnExample" class="hide bg-success padding10Px">
<div id="doubleHolder">
<button class="double">double</button>
</div>
</div>
</div>
<p>ref: <a href="http://www.careercup.com/question?id=17328675">destroy button</a></p>
</div>
<div id="unintendedClosure">
<h2>18. Unintended Closure</h2>
<p><strong>Question:</strong> If you are looping through a collection of dom and adding a click handler like the example below. What will happen if you click on the item?</p>
<pre><code>
<div class="item">Item1</div>
<div class="item">Item2</div>
<div class="item">Item3</div>
<div class="item">Item4</div>
</code></pre>
<pre><code>
var elems = document.getElementsByClassName("item"), i;
for (i = 0; elems.length > i; i++) {
elems[i].addEventListener("click", function () {
this.innerHTML = "Item" + i + " Clicked";
});
}
</code></pre>
<div>
<button id = "clickClosure" type="button" class="toggleExample btn btn-primary">Show Demo to Click</button>
<div id="clickClosureExample" class="hide bg-success toggleContent">
<div>
<div class="item">Item1</div>
<div class="item">Item2</div>
<div class="item">Item3</div>
<div class="item">Item4</div>
</div>
<p>is that what you have expected?</p>
<p><strong>how could you fix it?</strong></p>
</div>
</div>
<p><strong>Answer:</strong> there could be two different ways to solve it. first one is to execute it immediatey</p>
<p><strong>explanation:</strong> as you are looping through a closure is created for the event handler. look <code>i</code> is encapsulated. Now, after loop is over, value of i = 4. and whenever you are clicking on the element it uses the value of i. which is currently 4. Hence doesnt matter which one you are clicking, you will see item4 clicked</p>
<pre><code>
var elems = document.getElementsByClassName("item"), i;
for (i = 0; elems.length > i; i++) {
var el= elems[i];
(function(elem, idx){
elem.addEventListener("click", function () {
elem.innerHTML = "Item" + idx + " Clicked";
});
})(el, i+1);
}
</code></pre>
<p><strong>Solution: </strong> to solve this problem, you can use IIFe (immediate invoking functios expression) this will exectute the function immediately in the loop before going to the next step. Hence current value of <code>i</code> will be used. and in the next one the new value of <code>i</code> would be used.</p>
<div>
<button id = "clickClosureFixed" type="button" class="toggleExample btn btn-primary">Show Fixed Demo to Click</button>
<div id="clickClosureFixedExample" class="hide bg-success toggleContent">
<div>
<div class="itemFixed">Item1</div>
<div class="itemFixed">Item2</div>
<div class="itemFixed">Item3</div>
<div class="itemFixed">Item4</div>
</div>
<p><strong>Good job</strong></p>
</div>
</div>
<p><strong>question:</strong> how could you solve this by using event delegate</p>
<p><strong>Answer:</strong> Use your brain to extract answer from <a href="http://www.thatjsdude.com/interview/dom.html#eventDelegate">this answer</a></p>
</div>
<div id="captureAllClick">
<h2>19. Capture all click</h2>
<p><strong>Question:</strong> How could you capture all clicks in a page?</p>
<p><strong>Answer:</strong> You can leverage, event bubble to capture all the clicks. As all the clicks will be bubbled up to the body.</p>
<pre><code>
document.querySelector('body').addEventListener('click', function(e){
console.log('body clicked', e.target);
});
//or
window.onclick =function(e){
console.log('someone clicked', e.target)
}
</code></pre>
<p>However, if event bubbling is canceled by <code>stopPropagation()</code> your code will not work. Think about it.</p>
</div>
<div id="allTextInAPage">
<h2>20. All text in a page</h2>
<p><strong>Question:</strong> How can you get all the texts in a web page?</p>
<p><strong>Answer:</strong> The easiest way to get all the text is to get the innerText of body tag.</p>
<pre><code>
document.body.innerText;
</code></pre>
<p><strong>Question:</strong> Can you do by accessing DOM?</p>
<p><strong>Answer:</strong> Make it recursive. I used closure. There could be many other ways to implement.</p>
<pre><code>
function getAllText(node){
var allText = [];
function getNodeText(node){
if(node && node.childNodes && node.childNodes.length){
for(var i = 0, len = node.childNodes.length; i<len; i++){
getNodeText(node.childNodes[i]);
}
}
else{
allText.push(node.nodeValue);
}
}
getNodeText(node);
return allText.join('');
}
</code></pre>
<p><strong>disclaimer:</strong> I didn't explicitly tested these two methods.</p>
</div>
<div id="deferAsync">
<h2>21. defer vs async</h2>
<p><strong>Question:</strong> What is defer and async keyword does in a script tag?</p>
<p><strong>Answer:</strong> HTML parser will ignore defer and async keyword for inline script (script that does not have a src attribute). </p>
<p><strong>normal:</strong> When you have a plain script tag (no defer or async keyword), parser will pause parsing, script would be downloaded and exectuted. After that parsing resume.</p>
<p><strong>defer:</strong> defer keyword in the script tag will defer the execution of the script. Hence script will be executed when DOM is available. Important point is, defer is not supported by all major major browsers.</p>
<p><strong>async:</strong> If possible, set the execution of the script, asynchronously. <code>async</code> keyword has no effect on inline script.</p>
<img src="images/asyncVsDefer.jpg" alt="">
<p> Image copied from <a href="http://peter.sh/experiments/asynchronous-and-deferred-javascript-execution-explained/">JS script execution</a></p>
<p><strong>Extra: </strong><a href="https://www.igvita.com/2014/05/20/script-injected-async-scripts-considered-harmful/"><del>async injected scripts</del> script injected async scripts are considered harmful</a></p>
</div>
<div id="domRapidFire">
<h2>22. Rapid fire</h2>
<p><strong>Question: </strong> How could you prevent a click on an anchor from going to the link?</p>
<p><strong>Answer: </strong><code>preventDefault()</code> inside event handler. However, this doesnt stop further propagation.</p>
<p><strong>Question: </strong> How could you stop further propagation of an event?</p>
<p><strong>Answer: </strong> Call <code>event.stopPropagation();</code></p>
<p><strong>Question: </strong> Can you remove an event handler from an element?</p>
<p><strong>Answer: </strong>Yes. <code>target.removeEventListener('click', handler)</code></p>
<p><strong>Question: </strong> How could you run event handler in the capturing phase not in bubble phase?</p>
<p><strong>Answer: </strong> There is a third (optional) parameter in addEventListener and removeEventLister. You can pass true or false to useCapture phase.</p>
<p><strong>Question: </strong> How could you prevent multiple event handler to be fired for an event?</p>
<p><strong>Answer: </strong>If event listeners are attached for the same type event (click, keydown, etc.) of an element for the same event type, you can call <code>event.stopImmediatePropagation()</code> in the first event handler. No other event handler will be executed.</p>
<p><strong>Question: </strong> What are the cancelable events?</p>
<p><strong>Answer: </strong> Go to <a href="http://en.wikipedia.org/wiki/DOM_events#HTML_events">wiki</a> find the right most column cancelable.</p>
<p><strong>Question: </strong> How could I check whether an event is cancelable or not?</p>
<p><strong>Answer: </strong> Use <code>event.cancelable</code> to get true or false return. However, you have to <code>preventDefault()</code> to prevent the event.</p>
<p><strong>Question: </strong> Is there anything you have to be careful when using <code>node.cloneNode()</code>?</p>
<p><strong>Answer: </strong> While cloning, make sure you didnt duplicate ID.</p>
<p><strong>Question: </strong>What are different nodeTypes?</p>
<p><strong>Answer: </strong> ELEMENT_NODE (1), TEXT_NODE (3), COMMENT_NODE(8), DOCUMENT_NODE(9), DOCUMENT_TYPE_NODE(10), DOCUMENT_FRAGMENT_NODE(11), etc.</p>
<p><strong>Question: </strong>What are the differences between node and element?</p>
<p><strong>Answer: </strong> read <a href="http://stackoverflow.com/a/9979779/1535443">here</a>.</p>
</div>
<div>
<h2>Deleted questions</h2>
<p>Following are the questions that weren't picked in my final list.</p>
<ul>
<li>Explain Event loop. <a href="http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/">event loop explained</a> or <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/EventLoop">concurrency model and event loop</a></li>
<li>asynchronous vs synchronous events: <a href="http://javascript.info/tutorial/events-and-timing-depth#asynchronous-events">events and timing</a></li>
<li>When you click on an element, what is the value of "this" inside the click handler?</li>
<li>How could you create Custom events? <a href="http://davidwalsh.name/customevent">customEvents</a></li>
<li>Write a function to find the nearest link on a webpage given the mouse x,y coordinates. <a href="http://www.careercup.com/question?id=3538036">career cup</a></li>
</ul>
</div>
<div>
<h2>Need more:</h2>
<p>JavaScript part -1: <a href="js1.html">JS basic algorithm</a></p>
<p>CSS: <a href="css.html">css related questions</a></p>
<p>HTML: <a href="html.html">html related questions</a></p>
<p><strong>Full list of interview questions are </strong><a href="https://github.com/khan4019/front-end-Interview-Questions">https://github.com/khan4019/front-end-Interview-Questions</a></p>
<p>A lot of data structure, tree, graphs related interview questions are on the pipe line. Stay tuned</p>
</div>
<div>
<h3 class="purpleBold">Express anger!</h3>
<p class="gray">Feel free to express your anger (sorry folks, you have to use g+.). Also point out my mistakes ( technical, wrong answer, spelling, grammar, sentence..., whatever), let your dude learn and grow.</p>
<script src="https://apis.google.com/js/plusone.js"></script>
<div class="g-comments"
data-href="http://www.thatjsdude.com/interview/dom.html"
data-width="642"
data-first_party_property="BLOGGER"
data-view_type="FILTERED_POSTMOD">
</div>
</div>
<hr>
<footer>
<p>©thatJSDude 2014</p>
</footer>
</div> <!-- /container -->
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="js/jquery-2.0.3.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="js/toggleExample.js"></script>
<script type="text/javascript">
//social plugins
//g+
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/platform.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
//fb
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>
<script type="text/javascript">
document.getElementById('listToDestroy').addEventListener('click', function (e) {
var elm = e.target.parentNode;
elm.parentNode.removeChild(elm);
e.preventDefault();
});
document.getElementById('doubleHolder').addEventListener('click', function (e) {
if(e.target.classList.contains('double')){
var btn = document.createElement('button');
btn.setAttribute('class', 'double');
btn.innerHTML = 'double';
var btn2 = document.createElement('button');
btn2.setAttribute('class', 'double');
btn2.innerHTML = 'double';
this.appendChild(btn);
this.appendChild(btn2);
this.removeChild(e.target);
}
});
//for item click that doesn't work
var elems = document.getElementsByClassName("item"), i;
console.log(elems);
for (i = 0; elems.length > i; i++) {
elems[i].addEventListener("click", function () {
this.innerHTML = "Item" + i + " Clicked";
});
}
//for item click that works
var elemsFixed = document.getElementsByClassName("itemFixed"), i;
for (i = 0; elemsFixed.length > i; i++) {
var el= elemsFixed[i];
(function(elem, idx){
elem.addEventListener("click", function () {
elem.innerHTML = "Item" + idx + " Clicked";
});
})(el, i+1);
}
</script>
</body>
</html>