>웹 프론트엔드 >JS 튜토리얼 >JavaScript에서 가장 일반적인 세 ​​가지 문제에 대한 자세한 코드 설명

JavaScript에서 가장 일반적인 세 ​​가지 문제에 대한 자세한 코드 설명

黄舟
黄舟원래의
2017-03-23 14:49:031112검색

JavaScript는 모든 최신 브라우저의 공식 언어입니다. 따라서 JavaScript 문제는 ​​다음에서 발생합니다. 다양한 개발자와의 인터뷰 중 JavaScript에서 가장 자주 묻는 세 가지 인터뷰 질문을 주로 공유합니다.

서문

이 기사는 JavaScript를 논의할 때 흔히 발생하는 것처럼 최신 JavaScript 라이브러리, 일상적인 개발 관행 또는 새로운 ES6 함수에 관한 것이 아닙니다. 나 자신도 이런 질문을 받았고, 내 친구들도 이런 질문을 받았다고 합니다.

물론 JavaScript 인터뷰 전에 이 3가지 질문만 배워서는 안 됩니다. 더 잘 준비할 수 있는 방법은 많습니다. 다가오는 인터뷰를 위해 – 면접관이 JavaScript 언어에 대한 이해와 DOM 숙달을 확인하기 위해 물어볼 수 있는 3가지 질문은 다음과 같습니다.

예제에서는 기본 JavaScript를 사용하겠습니다. 면접관은 일반적으로 jQuery

JavaScript 및 DOM을 이해하는 방법

질문 #1: 이벤트 위임

참고: 이벤트 위임, 시간 프록시 등이라고도 합니다. ;애플리케이션을 구축할 때 가끔 사용자가 요소와 상호작용할 때 특정 작업을 수행하려면 이벤트 리스너를 페이지의 버튼, 텍스트 또는 이미지에 바인딩해야 합니다. >

간단한 할 일 목록을 예로 들면 면접관은 다음과 같이 말할 수 있습니다. 사용자가 목록 항목 중 하나를 클릭하면 어떤 작업이 수행될 것으로 예상한다고 말합니다. HTML 코드가 다음과 같다고 가정합니다.

<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>

다음과 같이 이벤트 리스너를 요소에 바인딩할 수 있습니다.

document.addEventListener(&#39;DOMContentLoaded&#39;, function() {
 
 let app = document.getElementById(&#39;todo-app&#39;);
 let items = app.getElementsByClassName(&#39;item&#39;);
 
 // 将事件侦听器绑定到每个列表项
 for (let item of items) {
 item.addEventListener(&#39;click&#39;, function() {
 alert(&#39;you clicked on item: &#39; + item.innerHTML);
 });
 }
 
});

이 방법은 작동하지만 문제는 이벤트 리스너를 각 목록 항목에 개별적으로 바인딩한다는 것입니다. 큰 문제는 아니지만 누군가가 할 일 목록에 10,000개를 추가한다면(할 일이 많을 수 있습니다) 그러면 함수는 10,000개의 독립적인 이벤트 리스너를 생성하고 각 이벤트 리스너를 DOM에 바인딩합니다.

면접에서는 먼저 면접관에게 사용자가 입력할 수 있는 최대 항목 수를 물어보는 것이 좋습니다. 10개를 초과하지 않으면 위의 코드가 제대로 작동합니다. 그러나 사용자가 입력할 수 있는 항목 수에 제한이 없다면 보다 효율적인 솔루션을 사용해야 합니다.

응용 프로그램이 수백 개의 이벤트 리스너로 끝날 수 있는 경우, 더 효율적인 솔루션은 실제로 하나의 이벤트 리스너를 전체 컨테이너에 바인딩한 다음 실제로 정확한 요소를 클릭할 때 각 이벤트 리스너에 액세스할 수 있도록 하는 것입니다. 이를 이벤트 위임이라고 하며 각 요소에 대해 이벤트 핸들러를 개별적으로 바인딩하는 것이 더 효율적입니다.

이벤트 위임을 사용하는 코드:

document.addEventListener(&#39;DOMContentLoaded&#39;, function() {
 
 let app = document.getElementById(&#39;todo-app&#39;);
 
 // 事件侦听器绑定到整个容器上
 app.addEventListener(&#39;click&#39;, function(e) {
 if (e.target && e.target.nodeName === &#39;LI&#39;) {
 let item = e.target;
 alert(&#39;you clicked on item: &#39; + item.innerHTML);
 }
 });
 
});

문제 #2: 루프 내부에서 클로저 사용

면접관이 언어에 대한 친숙도와 클로저 사용 시기를 알고 있는지 여부를 측정할 수 있도록 인터뷰에서 클로저가 자주 등장합니다.

클로저의 핵심은

내부 함수가 범위 밖의 변수에 액세스한다는 것입니다. 클로저는 개인 변수 및 팩토리 함수 생성과 같은 기능을 구현하는 데 사용할 수 있습니다. 클로저 사용에 대한 일반적인 인터뷰 질문은 다음과 같습니다.

정수 목록을 반복하고 3초 지연 후 각 요소의 인덱스를 인쇄하는 함수를 작성합니다.

이 문제를 확인하는 가장 일반적이지만 잘못된 방법은 다음과 같은 구현을 사용하는 것입니다.

const arr = [10, 12, 15, 21];
for (var i = 0; i < arr.length; i++) {
 setTimeout(function() {
 console.log(&#39;The index of this number is: &#39; + i);
 }, 3000);
}

위 코드를 실행하면 3초 지연 후 인쇄된 출력은 예상되는 0, 1, 2, 3 대신 실제로 매번 4입니다.

왜 이런 일이 일어나는지 제대로 이해하기 위해서는 면접관이 실제로 의도한 자바스크립트를 사용하는 것이 유용합니다.

이유는 setTimeout 함수가 외부 범위(즉, 흔히 클로저라고 부르는 함수)에 액세스할 수 있는 함수를 생성하고 각 루프에 인덱스 i가 포함되어 있기 때문입니다. 3초 후 함수가 실행되고 i의 값이 출력됩니다. 루프 주기는 0,1,2,3,4를 거치고 루프는 최종적으로 4에서 멈춥니다. 4 .

실제로 이 문제를 작성하는 올바른 방법은 여러 가지가 있습니다. 다음은 두 가지입니다.

const arr = [10, 12, 15, 21];
for (var i = 0; i < arr.length; i++) {
 // 通过传递变量 i
 // 在每个函数中都可以获取到正确的索引
 setTimeout(function(i_local) {
 return function() {
 console.log(&#39;The index of this number is: &#39; + 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(&#39;The index of this number is: &#39; + i);
 }, 3000);
}

문제 #3: 흔들림 방지 기능(디바운싱 )

有一些浏览器事件可以在很短的时间内快速启动多次,例如调整窗口大小或向下滚动页面。例如,如果将事件侦听器绑定到窗口滚动事件上,并且用户继续非常快速地向下滚动页面,你的事件可能会在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() {
 // 通过 &#39;this&#39; 和 &#39;arguments&#39;
 // 获得函数的作用域和参数
 let context = this;
 let args = arguments;
 // 如果事件被触发,清除 timer 并重新开始计时
 clearTimeout(timer);
 timer = setTimeout(function() {
 fn.apply(context, args);
 }, delay);
 }
}

当这个函数绑定在一个事件上,只有经过一段指定的时间后才会被调用。

你可以像这样去使用这个函数:

// 当用户滚动时函数会被调用
function foo() {
 console.log(&#39;You are scrolling!&#39;);
}
 
// 在事件触发的两秒后,我们包裹在debounce中的函数才会被触发
let elem = document.getElementById(&#39;container&#39;);
elem.addEventListener(&#39;scroll&#39;, debounce(foo, 2000));

函数节流是另一个类似函数防抖的技巧,除了使用等待一段时间再调用函数的方法,函数节流还限制固定时间内只能调用一次。所以一个事件如果在100毫秒内发生10次,函数节流会每2秒调用一次函数,而不是100毫秒内全部调用。

总结

위 내용은 JavaScript에서 가장 일반적인 세 ​​가지 문제에 대한 자세한 코드 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.