Home >Web Front-end >JS Tutorial >Detailed code explanations of the three most common problems in JavaScript
JavaScript is the official language of all modern browsers. Therefore, JavaScript issues arise in During interviews with various developers. This article mainly shares with you the three most common interview questions in JavaScript. Friends who need it can refer to it. Let’s take a look.
PrefaceThis article is not about the latest JavaScript libraries, daily development practices, or any new ES6 functions
On the contrary, it is often the case when discussing JavaScript. These 3 questions come up in interviews. I have been asked these questions myself, and my friends have told me that they have been asked too. Let's get started! Please note that we will be using native JavaScript in the examples below because your interviewer will usually want to see what you are doing without the help of a third-party library (such asjQuery
). How to understand JavaScript and DOM.##Question #1: Event delegation
Note: Also called event delegation, time proxy, etc. ;
When building an application, sometimes you need to bind event listeners to buttons, text, or images on the page to perform certain actions when the user interacts with the element ##. #If we take a simple to-do list as an example, the interviewer may tell you that they expect certain actions to be performed when the user clicks on one of the list items. They want you to use JavaScript to implement this function. Assume that the HTML code is as follows:
<ul id="todo-app"> <li class="item">Walk the dog</li> <li class="item">Pay bills</li> <li class="item">Make dinner</li> <li class="item">Code for one hour</li> </ul>You may want to bind an event listener to the element as follows:
document.addEventListener('DOMContentLoaded', function() { let app = document.getElementById('todo-app'); let items = app.getElementsByClassName('item'); // 将事件侦听器绑定到每个列表项 for (let item of items) { item.addEventListener('click', function() { alert('you clicked on item: ' + item.innerHTML); }); } });
While this works, the problem is that you're binding event listeners to each list item individually. That's 4 elements, not a big deal, but if someone adds 10,000 to their to-do list. What to do (they may have a lot to do)? Then your function will create 10,000 independent event listeners and bind each event listener to the DOM. This code execution is very inefficient. In interviews, it's a good idea to first ask the interviewer what is the maximum number of items the user can enter. If it never exceeds 10, the above code will work fine. However, if there is no limit to the number of items the user can enter, then you should use a more efficient solution.
If your application may end up with hundreds of event listeners, a more efficient solution would be to actually bind one event listener to the entire container and then have access to each event listener when actually clicked an exact element. This is called event delegation, and it makes it more efficient to bind event handlers individually to each element.Code using event delegation:
document.addEventListener('DOMContentLoaded', function() { let app = document.getElementById('todo-app'); // 事件侦听器绑定到整个容器上 app.addEventListener('click', function(e) { if (e.target && e.target.nodeName === 'LI') { let item = e.target; alert('you clicked on item: ' + item.innerHTML); } }); });Question #2: Using closures inside loops Closures often come up in interviews so that the interviewer can gauge your familiarity with the language and whether you know when to use closures.
The essence of a closure is an internal function
accessing variables outside its scope. Closures can be used to implement things like private variables and creating factory functions. A common interview question about using closures goes like this:Write a function that will loop through a list of integers and print the index of each element after a 3 second delay. The most common (but incorrect) way I see this problem is with an implementation like this:
const arr = [10, 12, 15, 21]; for (var i = 0; i < arr.length; i++) { setTimeout(function() { console.log('The index of this number is: ' + i); }, 3000); }If you run the above code, after a 3 second delay you will See, the printed output is actually 4 each time, instead of the expected 0, 1, 2, 3. The reason is that the setTimeout function creates a function that can access its outer scope (that is, what we often call a closure), and each loop contains the index i.
After 3 seconds, the function is executed and prints out the value of i, which is 4 at the end of the loop because its loop cycle has gone through 0,1,2,3,4, and the loop finally stops at 4 .
There are actually several correct ways to write to solve this problem. Two are listed below:
const arr = [10, 12, 15, 21]; for (var i = 0; i < arr.length; i++) { // 通过传递变量 i // 在每个函数中都可以获取到正确的索引 setTimeout(function(i_local) { return function() { console.log('The index of this number is: ' + i_local); } }(i), 3000); }
const arr = [10, 12, 15, 21]; for (let i = 0; i < arr.length; i++) { // 使用ES6的let语法,它会创建一个新的绑定 // 每个方法都是被单独调用的 // 更多详细信息请阅读: http://exploringjs.com/es6/ch_variables.html#sec_let-const-loop-heads setTimeout(function() { console.log('The index of this number is: ' + i); }, 3000); }
Question #3: Function anti-shake (Debouncing)
有一些浏览器事件可以在很短的时间内快速启动多次,例如调整窗口大小或向下滚动页面。例如,如果将事件侦听器绑定到窗口滚动事件上,并且用户继续非常快速地向下滚动页面,你的事件可能会在3秒的范围内被触发数千次。这可能会导致一些严重的性能问题。
如果你在面试中讨论构建应用程序和事件,如滚动,窗口调整大小,或键盘按下的事件时,请务必提及 函数防抖动(Debouncing) 和/或 函数节流(Throttling)来提升页面速度和性能。一个真实的案例,来自 guest post on css-tricks:
在2011年,一个问题在Twitter上被提出:当你滚动Twitter feed时,它会会变得非常慢甚至未响应。John Resig 就这个问题发布了一篇博文,它解释了直接绑定函数到scroll事件上是多么糟糕的事。
函数防抖动(Debouncing) 是解决这个问题的一种方式,通过限制需要经过的时间,直到再次调用函数。一个正确实现函数防抖的方法是:把多个函数放在一个函数里调用,隔一定时间执行一次。这里有一个使用原生JavaScript实现的例子,用到了作用域、闭包、this和定时事件:
// debounce函数用来包裹我们的事件 function debounce(fn, delay) { // 持久化一个定时器 timer let timer = null; // 闭包函数可以访问 timer return function() { // 通过 'this' 和 'arguments' // 获得函数的作用域和参数 let context = this; let args = arguments; // 如果事件被触发,清除 timer 并重新开始计时 clearTimeout(timer); timer = setTimeout(function() { fn.apply(context, args); }, delay); } }
当这个函数绑定在一个事件上,只有经过一段指定的时间后才会被调用。
你可以像这样去使用这个函数:
// 当用户滚动时函数会被调用 function foo() { console.log('You are scrolling!'); } // 在事件触发的两秒后,我们包裹在debounce中的函数才会被触发 let elem = document.getElementById('container'); elem.addEventListener('scroll', debounce(foo, 2000));
函数节流是另一个类似函数防抖的技巧,除了使用等待一段时间再调用函数的方法,函数节流还限制固定时间内只能调用一次。所以一个事件如果在100毫秒内发生10次,函数节流会每2秒调用一次函数,而不是100毫秒内全部调用。
总结
The above is the detailed content of Detailed code explanations of the three most common problems in JavaScript. For more information, please follow other related articles on the PHP Chinese website!