33.前端基础-应用4

8.13 实现一个 JS 的sleep

参考答案

普通版

function sleep(sleepTime) {
  for(var start = new Date; new Date - start <= sleepTime;) {}
}
var t1 = +new Date()
sleep(3000)
var t2 = +new Date()
console.log(t2 - t1)

优点:简单粗暴,通俗易懂。

缺点:这是最简单粗暴的实现,确实 sleep 了,也确实卡死了,CPU 会飙升,无论你的服务器 CPU 有多么 Niubility。

Promise 版本

function sleep(time) {
  return new Promise(resolve => setTimeout(resolve, time))
}

const t1 = +new Date()
sleep(3000).then(() => {
  const t2 = +new Date()
  console.log(t2 - t1)
})

优点:这种方式实际上是用了 setTimeout,没有形成进程阻塞,不会造成性能和负载问题。

缺点:虽然不像 callback 套那么多层,但仍不怎么美观,而且当我们需要在某过程中需要停止执行(或者在中途返回了错误的值),还必须得层层判断后跳出,非常麻烦,而且这种异步并不是那么彻底,还是看起来别扭

Async/Await 版本

function sleep(delay) {
  return new Promise(reslove => {
    setTimeout(reslove, delay)
  })
}

!async function test() {
  const t1 = +new Date()
  await sleep(3000)
  const t2 = +new Date()
  console.log(t2 - t1)
}()

缺点: ES7 语法存在兼容性问题,有 babel 一切兼容性都不是问题

更优雅的写法

function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}

// 用法
sleep(500).then(() => {
    // 这里写sleep之后需要去做的事情
})

不要忘了开源的力量

const sleep = require("sleep")
const t1 = +new Date()
sleep.msleep(3000)
const t2 = +new Date()
console.log(t2 - t1)

优点:能够实现更加精细的时间精确度,而且看起来就是真的 sleep 函数,清晰直白。

8.14 实现一个数组对象的去重,相同value的只保留最后一个,最好有多个思路

参考答案

1.遍历数组法

它是最简单的数组去重方法(indexOf方法)

实现思路:新建一个数组,遍历去要重的数组,当值不在新数组的时候(indexOf为-1)就加入该新数组中;

var arr=[2,8,5,0,5,2,6,7,2];
function unique1(arr){
  var hash=[];
  for (var i = 0; i < arr.length; i++) {
     if(hash.indexOf(arr[i])==-1){
      hash.push(arr[i]);
     }
  }
  return hash;
}

2.数组下标判断法

调用indexOf方法,性能和方法1差不多

实现思路:如果当前数组的第 i 项在当前数组中第一次出现的位置不是 i,那么表示第 i 项是重复的,忽略掉。否则存入结果数组。

function unique2(arr){
  var hash=[];
  for (var i = 0; i < arr.length; i++) {
     if(arr.indexOf(arr[i])==i){
      hash.push(arr[i]);
     }
  }
  return hash;
}

3.排序后相邻去除法

实现思路:给传入的数组排序,排序后相同的值会相邻,然后遍历排序后数组时,新数组只加入不与前一值重复的值。

function unique3(arr){
  arr.sort();
  var hash=[arr[0]];
  for (var i = 1; i < arr.length; i++) {
     if(arr[i]!=hash[hash.length-1]){
      hash.push(arr[i]);
     }
  }
  return hash;
}

4.优化遍历数组法(推荐)

实现思路:双层循环,外循环表示从0到arr.length,内循环表示从i+1到arr.length

将没重复的右边值放入新数组。(检测到有重复值时终止当前循环同时进入外层循环的下一轮判断)

function unique4(arr){
  var hash=[];
  for (var i = 0; i < arr.length; i++) {
    for (var j = i+1; j < arr.length; j++) {
      if(arr[i]===arr[j]){
        ++i;
      }
    }
      hash.push(arr[i]);
  }
  return hash;
}

5.ES6实现

基本思路:ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

Set函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化。

function unique5(arr){
  var x = new Set(arr);
 return [...x];
}

扩展:如果重复,则去掉该元素

数组下标去重

function unique22(arr){
  var hash=[];
  for (var i = 0; i < arr.length; i++) {
     if(arr.indexOf(arr[i])==arr.lastIndexOf(arr[i])){
      hash.push(arr[i]);
     }
  }
  return hash;
}

8.15 function rand(min, max, N):生成长度是N,且在min、max内不重复的整数随机数组

参考答案:

把考点拆成了4个小项;需要用递归算法实现:
a) 生成一个长度为n的空数组arr。
b) 生成一个(min-max)之间的随机整数rand。
c) 把随机数rand插入到数组arr内,如果数组arr内已存在与rand相同的数字,则重新生成随机数rand并插入到 arr内[需要使用递归实现,不能使用for/while等循环]
d) 最终输出一个长度为n,且内容不重复的数组arr。

function buildArray(arr, n, min, max) {
    var num = Math.floor(Math.random() * (max - min + 1)) + min;
    if (!arr.includes(num)) { arr.push(num); }
    return arr.length === n ? arr : buildArray(arr, n, min, max);
}
var result = buildArray([], 5, 2, 32);
console.table(result);

8.16 闭包的理解

参考答案:

闭包:

​ 一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围), 这样的组合就是闭包closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。

闭包的特点:

​ 让外部访问函数内部变量成为可能;
​ 可以避免使用全局变量,防止全局变量污染;
​ 可以让局部变量常驻在内存中;
​ 会造成内存泄漏(有一块内存空间被长期占用,而不被释放)

应用场景

  1. 埋点(是网站分析的一种常用的数据采集方法)计数器
function count() {
  var num = 0;
  return function () {
    return ++num
  }
}
var getNum = count();
var getNewNum = count();
document.querySelectorAll('button')[0].onclick = function(){
  console.log('点击加入购物车次数: '+getNum());
}
document.querySelectorAll('button')[1].onclick = function(){
  console.log('点击付款次数: '+getNewNum());
}    
  1. 事件+循环

按照以下方式添加事件,打印出来的i不是按照序号的

形成原因就是操作的是同一个词法环境,因为onclick后面的函数都是一个闭包,但是操作的是同一个词法环境

   var lis = document.querySelectorAll('li');
   for (var i = 0; i < lis.length; i++) {
            lis[i].onclick = function () {
                alert(i)
            }       
    }

解决办法:

使用匿名函数之后,就形成一个闭包, 操作的就是不同的词法环境

var lis = document.querySelectorAll('li');  
for (var i = 0; i < lis.length; i++) {
     (function (j) {
                lis[j].onclick = function () {
                    alert(j)
                }
            })(i)
 }

8.17 字符串中的单词逆序输出(手写)

参考答案:

方法一:

function strReverse(str) {
   return str.split("").reverse().join("") 
}

方法二:

function strReverse(str) {
    var i=str.length;
    var nstr = ""; 
    i=i-1; 
    for (var x = i; x >=0; x--) { 
        nstr+=str.charAt(x)
    }
    return nstr
}

方法三:

function strReverse(str) {
      if(str.length == 0)return null; 
      var i = str.length; 
      var dstr = ""; 
      while(--i >= 0) 
      { 
          dstr += str.charAt(i);  
      } 
      return dstr; 
}

方法四:

function strReverse(str) {
  return str.split('').reduce((prev, next) => next + prev);
}

方法五:

function strReverse(str) {
    var newstr="";
           for(var i=0;i<str.length;i++){
               newstr=str.charAt(i)+newstr;
           }
           return newstr
}

方法六:

function strReverse(str) {
            if(str.length===1){
                return str
            }
            return str.slice(-1)+strReverse(str.slice(0,-1));
}
全部评论

相关推荐

11-02 09:49
已编辑
货拉拉_测试(实习员工)
热爱生活的仰泳鲈鱼求你们别卷了:没事楼主,有反转查看图片
点赞 评论 收藏
分享
微风不断:兄弟,你把四旋翼都做出来了那个挺难的吧
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务