Javascript 口试中经常被问到的三个题目!

《Javascript 口试中经常被问到的三个题目!》

想浏览更多优良文章请猛戳GitHub博客,一年百来篇优良文章等着你!

本文不是议论最新的 JavaScript 库、罕见的开辟实践或任何新的 ES6 函数。相反,在议论 JavaScript 时,口试中一般会提到三件事。我本身也被问到这些题目,我的朋友们通知我他们也被问到这些题目。

然,这些并非你在口试之前应当进修的唯一三件事 – 你可以经由过程多种体式格局更好地为行将到来的口试做准备 – 但口试官可以会问到下面是三个题目,来推断你对 JavaScript 言语的明白和 DOM 的掌握水平。

让我们最先吧!注重,我们将在下面的示例中运用原生的 JavaScript,由于口试官一般愿望相识你在没有 jQuery 等库的协助下对JavaScript 和 DOM 的明白水平。

题目 1: 事宜托付代办

在构建运用顺序时,偶然须要将事宜绑定到页面上的按钮、文本或图象,以便在用户与元素交互时实行某些操纵。

假如我们以一个简朴的待办事项列表为例,口试官可以会通知你,当用户点击列表中的一个列表项时实行某些操纵。他们愿望你用 JavaScript 完成这个功用,假设有以下 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('DOMContentLoaded', function() {
  let app = document.getElementById('todo-app');
  let itimes = app.getElementsByClassName('item');

  for (let item of items) {
    item.addEventListener('click', function(){
      alert('you clicked on item: ' + item.innerHTML);
    })
  }
})

虽然这在手艺上是可行的,但题目是要将事宜离别绑定到每一个项。这关于如今 4 个元素来讲,没什么大题目,然则假如在待办事项列表中添加了 10,000 项(他们可以有许多事变要做)怎么办?然后,函数将建立 10,000 个自力的事宜侦听器,并将每一个事宜监听器绑定到 DOM ,如许代码实行的效力异常低下。

在口试中,最好先问口试官用户可以输入的最大元素数目是若干。比方,假如它不凌驾 10,那末上面的代码就可以很好地事情。然则假如用户可以输入的条目数目没有限定,那末你应当运用一个更高效的解决方案。

假如你的运用顺序终究可以有数百个事宜侦听器,那末更有效的解决方案是将一个事宜侦听器现实绑定到全部容器,然后在单击它时可以接见每一个列表项, 这称为 事宜托付,它比附加零丁的事宜处置惩罚顺序更有效。

下面是事宜托付的代码:

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

题目 2: 在轮回中运用闭包

闭包常常涌如今口试中,以便口试官权衡你对 JS 的熟习水平,以及你是不是晓得什么时刻运用闭包。

闭包基本上是内部函数可以接见其局限以外的变量。 闭包可用于完成隐私和建立函数工场, 闭包罕见的口试题以下:

编写一个函数,该函数将遍历整数列表,并在耽误3秒后打印每一个元素的索引。

常常不准确的写法是如许的:

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);
}

假如运转上面代码,3 秒耽误后你会看到,现实上每次打印输出是 4,而不是希冀的 0,1,2,3

为了准确明白为何会发作这类状况,相识为何会在 JavaScript 中发作这类状况将异常有效,这正是口试官试图测试的内容。

缘由是由于 setTimeout 函数建立了一个可以接见其外部作用域的函数(闭包),该作用域是包括索引 i 的轮回。 经由 3 秒后,实行该函数并打印出 i 的值,该值在轮回完毕时为 4,由于它轮回经由0,1,2,3,4而且轮回终究住手在 4

现实上有多处方法来准确的解这道题:

const arr = [10, 12, 15, 21];

for (var i = 0; i < arr.length; 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++) {
  setTimeout(function() {
    console.log('The index of this number is: ' + i);
  }, 3000);
}


题目 3:事宜的撙节(throttle)与防抖(debounce)

有些浏览器事宜可以在短时刻内疾速触发屡次,比方调解窗口大小或向下转动页面。比方,监听页面窗口转动事宜,而且用户延续疾速地向下转动页面,那末转动事宜可以在 3 秒内触发数千次,这可以会致使一些严峻的机能题目。

假如在口试中议论构建运用顺序,涌现转动、窗口大小调解或按下键等事宜请务必说起 防抖(Debouncing)函数撙节(Throttling)来提拔页面速率和机能。这两兄弟的实质都是以闭包的情势存在。经由过程对事宜对应的回调函数举行包裹、以自在变量的情势缓存时刻信息,末了用 setTimeout 来掌握事宜的触发频次。

Throttle: 第一个人说了算

throttle 的重要头脑在于:在某段时刻内,不论你触发了若干次回调,都只认第一次,并在计时完毕时赋予相应。

这个故事里,‘裁判’ 就是我们的撙节阀, 他掌握参赛者吃东西的机遇, “参赛者吃东西”就是我们频仍操纵事宜而不停涌入的回调使命,它受 “裁判” 的掌握,而计时器,就是上文提到的以自在变量情势存在的时刻信息,它是 “裁判” 决议是不是住手竞赛的根据,末了,守候竞赛效果就对应到回调函数的实行。

总结下来,所谓的“撙节”,是经由过程在一段时刻内疏忽厥后发生的回调要求来完成的。只需 裁判宣告竞赛最先,裁判就会开启计时器,在这段时刻内,参赛者就只管不停的吃,谁也没法晓得终究效果。

对应到现实的交互上是一样一样的:每当用户触发了一次 scroll 事宜,我们就为这个触发操纵开启计时器。一段时刻内,后续一切的 scroll 事宜都会被看成“参赛者吃东西——它们没法触发新的 scroll 回调。直到“一段时刻”到了,第一次触发的 scroll 事宜对应的回调才会实行,而“一段时刻内”触发的后续的 scroll 回调都会被撙节阀疏忽掉。

如今一同完成一个 throttle:

// fn是我们须要包装的事宜回调, interval是时刻距离的阈值
function throttle(fn, interval) {
  // last为上一次触发还调的时刻
  let last = 0
  
  // 将throttle处置惩罚效果看成函数返回
  return function () {
      // 保存调用时的this上下文
      let context = this
      // 保存调用时传入的参数
      let args = arguments
      // 纪录本次触发还调的时刻
      let now = +new Date()
      
      // 推断上次触发的时刻和本次触发的时刻差是不是小于时刻距离的阈值
      if (now - last >= interval) {
      // 假如时刻距离大于我们设定的时刻距离阈值,则实行回调
          last = now;
          fn.apply(context, args);
      }
    }
}

// 用throttle来包装scroll的回调
const better_scroll = throttle(() => console.log('触发了转动事宜'), 1000)

document.addEventListener('scroll', better_scroll)

Debounce: 末了一个参赛者说了算

防抖的重要头脑在于:我会等你究竟。在某段时刻内,不论你触发了若干次回调,我都只认末了一次。

继承大胃王竞赛故事,此次换了一种竞赛体式格局,时刻不限,参赛者吃到不能吃为止,当每一个参赛都吃不下的时刻,背面10分钟假如没有人在吃,竞赛完毕,假如有人在10分钟内还能吃,则竞赛继承,直到下一次10分钟内无人在吃时为止。

对照 throttle 来明白 debounce: 在 throttle 的逻辑里, ‘裁判’ 说了算,当竞赛时刻到时,就实行回调函数。而 debounce 认为末了一个参赛者说了算,只需还能吃的,就从新设定新的定时器。

如今一同完成一个 debounce:

// fn是我们须要包装的事宜回调, delay是每次推延实行的守候时刻
function debounce(fn, delay) {
  // 定时器
  let timer = null
  
  // 将debounce处置惩罚效果看成函数返回
  return function () {
    // 保存调用时的this上下文
    let context = this
    // 保存调用时传入的参数
    let args = arguments

    // 每次事宜被触发时,都去消灭之前的旧定时器
    if(timer) {
        clearTimeout(timer)
    }
    // 设立新定时器
    timer = setTimeout(function () {
      fn.apply(context, args)
    }, delay)
  }
}

// 用debounce来包装scroll的回调
const better_scroll = debounce(() => console.log('触发了转动事宜'), 1000)

document.addEventListener('scroll', better_scroll)

用 Throttle 来优化 Debounce

debounce 的题目在于它“太有耐烦了”。试想,假如用户的操纵非常频仍——他每次都不等 debounce 设置的 delay 时刻完毕就举行下一次操纵,因而每次 debounce 都为该用户从新天生定时器,回调函数被耽误了不计其数次。频仍的耽误会致使用户迟迟得不到相应,用户同样会发生“这个页面卡死了”的观感。

为了防止画蛇添足,我们须要借力 throttle 的头脑,打造一个“有底线”的 debounce——等你可以,但我有我的准绳:delay 时刻内,我可认为你从新天生定时器;但只需delay的时刻到了,我必需要给用户一个相应。这个 throttle 与 debounce “合体”思绪,已被许多成熟的前端库运用到了它们的加强版 throttle 函数的完成中:

// fn是我们须要包装的事宜回调, delay是时刻距离的阈值
function throttle(fn, delay) {
  // last为上一次触发还调的时刻, timer是定时器
  let last = 0, timer = null
  // 将throttle处置惩罚效果看成函数返回
  
  return function () { 
    // 保存调用时的this上下文
    let context = this
    // 保存调用时传入的参数
    let args = arguments
    // 纪录本次触发还调的时刻
    let now = +new Date()
    
    // 推断上次触发的时刻和本次触发的时刻差是不是小于时刻距离的阈值
    if (now - last < delay) {
    // 假如时刻距离小于我们设定的时刻距离阈值,则为本次触发操纵设立一个新的定时器
       clearTimeout(timer)
       timer = setTimeout(function () {
          last = now
          fn.apply(context, args)
        }, delay)
    } else {
        // 假如时刻距离超出了我们设定的时刻距离阈值,那就不等了,无论如何要反馈给用户一次相应
        last = now
        fn.apply(context, args)
    }
  }
}

// 用新的throttle包装scroll的回调
const better_scroll = throttle(() => console.log('触发了转动事宜'), 1000)

document.addEventListener('scroll', better_scroll)

参考:

Throttling and Debouncing in JavaScript
The Difference Between Throttling and Debouncing
Examples of Throttling and Debouncing
Remy Sharp’s blog post on Throttling function calls
前端机能优化道理与实践

原文:

https://medium.freecodecamp.o…

你的点赞是我延续分享好东西的动力,迎接点赞!

交换

干货系列文章汇总以下,以为不错点个Star,迎接 加群 互相进修。

https://github.com/qq44924588…

我是小智,民众号「大迁天下」作者,对前端手艺坚持进修爱好者。我会常常分享本身所学所看的干货,在进阶的路上,共勉!

关注民众号,背景复兴福利,即可看到福利,你懂的。

《Javascript 口试中经常被问到的三个题目!》

    原文作者:前端小智
    原文地址: https://segmentfault.com/a/1190000018257074
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞