整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

「javascript」练习题整理(持续更新)

const arr = [1,1,1,1,1,1,3,3,3,3,32,2,2,2,2,3,3,4,-1,-10,-10,-1,4,4,5,5,9]

// set方式去重
// 不改变源数组的数据
console.log([...new Set(arr)])

// includes方式去重,  时间复杂度 O(n)
function uniq(arr) {
    let _result = []
    for(let i=0; i < arr.length; i++) {
        if (!_result.includes(arr[i])) {
            _result.push(arr[i])
        }
    }
    return _result
}
console.log(uniq(arr))
冒泡排序
let arr = [1,2,5,3,1,6,7,3,4,10,12,3,21]

function bubbleSort(arr) {
    // 浅克隆, 对外部传入的参数不进行更改, 保证函数是一个纯函数
    let _arr = [].concat(arr)
    // 核心逻辑
    for(let i=0; i<_arr.length -1; i++) {
        for(let j=0; j<_arr.length-i-1; j++) {
            if (_arr[j] > _arr[j+1]) {
                let temp = _arr[j]
                _arr[j] = _arr[j + 1]
                _arr[j + 1] = temp
            }
        }
    }
    return _arr
}

console.log(bubbleSort(arr))
快速排序(二分法)
let arr = [300,432,1342,543,23,656,45,6465,4345,232,87,97,754,345]

function quickSort(arr) {

    if(arr.length <= 1) {
        return arr
    }

    const pivot = arr[0]
    let bigger = []
    let smaller = []

    for(let i=1; i<arr.length; i++) {
        if (arr[i] > pivot) {
            bigger.push(arr[i])
        }
    }

    for(let i=1; i<arr.length; i++) {
        if (arr[i] < pivot) {
            smaller.push(arr[i])
        }
    }
    return quickSort(smaller).concat(pivot, quickSort(bigger))
}

console.log(quickSort(arr))
函数柯里化
案例一: 
function curry(fn) {
    return function() {
        let arg = arguments
        return function() {
            return fn(...arg, ...arguments)
        }
    }
}

function fn(a,b,c,d) {
    return a+b+c+d
}

let fun = curry(fn)
let fun2 = fun(1,2,3)
console.log(fun2(5))

案例二: 
let fn = a => b => c => a+b+c
console.log(fn(1)(2)(3))
数组扁平化
let arr = [0,[3,4,5],[[[[12,5,6,7,54,34],43,34],33]], {a:1}]


function flatten(arr) {
    let _arr = []
    for(let i=0; i<arr.length; i++) {
        const leixing = Object.prototype.toString.call(arr[i])
        if (leixing !== '[object Array]') {
            _arr.push(arr[i])
        } else {
            _arr = _arr.concat(flatten(arr[i]))
        }
    }
    return _arr
}

console.log(flatten(arr))
原型链上扩展方法
Array.prototype.max =  function max() {
    console.log(this)
    return Math.max.apply(Math, this)
}
let array = [1,2,3,4]
console.log(array.max())
深克隆
let arr = [1,2,3,[4,5,6], {a:1}]

function deepClone(o) {
    if (
        typeof o == 'number'
        ||
        typeof o == 'string'
        ||
        typeof o == 'boolean'
        ||
        typeof o == 'undefined'
    ) {
        return o
    } else if(Array.isArray(o)) {
        let _arr = []
        for(let i=0; i<o.length; i++) {
            _arr.push(deepClone(o[i]))
        }
        return _arr
    } else if(typeof o == 'object') {
        let _o = {}
        for(let k in o) {
            _o[k] = deepClone(o[k])
        }
        return _o
    }
}

let deep = deepClone(arr)
console.log(arr[3] == deep[3]) // false
样本筛选函数
// 功能: 传入一个数值, 随机生成指定范围内的样本数据
// 参数: 样本个数
// start: 样本起始数值
// end: 样本结束数值
function sample(num, start, end) {
    end -= 1
    let _arr = []
    while(num != _arr.length){
        let data = parseInt(Math.random() * end) + start
        if (!_arr.includes(data)) {
            _arr.push(data)
        }
    }
    return _arr
}
console.log(sample(30, 2, 32))
//  输出结果
//   [
//     9, 27, 18, 28, 24, 13, 31, 11,  6,
//     19,  7, 17, 21, 26, 30, 22,  8, 25,
//     10,  3,  2,  5,  4, 12, 20, 14, 29,
//     15, 32, 23
//   ]

字符串反转函数

let str = 'abcde'
function myReverse(str) {
    return str.split('').reverse().join('')
}

let res = myReverse(str)
console.log(res)

偏函数
偏函数的作用: 调用之后能够获得一个特定功能的函数
// 需求: 实现一个检查类型的偏函数
function checkType(type) {
    return function(o) {
        return Object.prototype.toString.call(o) == `[object ${type}]`
    }
}

let checkIsArray = checkType('Array')
console.log(checkIsArray([1,2,3]))
// 输出结果
// true
闭包
闭包的特点: 调用永久记住当前作用域的变量

案例一: 
var a = 2

function foo() {
    var a = 1
    function bar() {
        console.log(a)
    }
    bar()
}
foo()
//输出结果
//1

案例二: 
var a = 1
function bar() {
    console.log(a)
}

(function(fn) {
    var a = 2
    fn()
})(bar)
// 输出结果
// 1
箭头函数
// 箭头函数this跟定义时上下文永远绑定
// 普通函数的this, 视运行环境而改变
function fun() {
    return () => {
        console.log(this)
    }
}

let laowang = {name: 'laowang'}
let xiaoliu = {name: 'xiaoliu'}

let arrowFun = fun.call(laowang)

arrowFun() // { name: 'laowang' }

arrowFun.call(xiaoliu) // { name: 'laowang' }

arrowFun = arrowFun.bind(xiaoliu)
arrowFun() // { name: 'laowang' }
函数新特征
// 函数非严格模式下实参与实参列表的关系
function fun(a, b) {
    a = (typeof a !== 'undefined') ? a : 10
    b = (typeof b !== 'undefined') ? b : 20

    console.log(a == arguments[0])
    console.log(b == arguments[1])

    a = 123
    b = 456

    console.log(a == arguments[0])
    console.log(b == arguments[1])
}
fun(1, 2)
// 输出结果
// true
// true
// true
// true

// 函数严格模式下实参与实参列表的关系
function fun(a, b) {
    'use strict'
    a = (typeof a !== 'undefined') ? a : 10
    b = (typeof b !== 'undefined') ? b : 20

    console.log(a == arguments[0])
    console.log(b == arguments[1])

    a = 123
    b = 456

    console.log(a == arguments[0])
    console.log(b == arguments[1])
}

fun(1, 2)
// true
// true
// false
// false

// 函数改良
// 这种方式跟非严格模式下的执行结果是一致的
function fun(a=10, b=20) {
    console.log(a == arguments[0])
    console.log(b == arguments[1])

    a = 123
    b = 456

    console.log(a == arguments[0])
    console.log(b == arguments[1])
}

fun(1, 2)
// true
// true
// false
// false
暂时性死区
解释: 变量在定义之后, 但没有声明的情况下, 是暂时不能访问的
// 案例一: 函数后面的默认参数可以访问前面的参数
// 实参其实相当于使用 let来声明一个变量
function foo(a) {
    return a + 5
}

function fun(a, b = foo(a)) {
    console.log(a + b)
}

fun(1) // 7
fun(1, 2) // 3

// 案例二: 函数后面的参数无法访问前面参数的值
function add(a = b, b) {
    return a + b
}
console.log(add(1, 2)) // 3
console.log(add(undefined, 2)) // ReferenceError: Cannot access 'b' before initialization
展开运算符
// 不使用展开运算符
let arr = [1,2,3,4]
let max = Math.max.apply(null,arr)
console.log(max)

// 改进
let arr = [1,2,3,4]
let max = Math.max(...arr)
console.log(max)
为什么使用严格模式
参考资料: https://www.runoob.com/js/js-strict.html
use strict解释: 为什么使用严格模式:

消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
消除代码运行的一些不安全之处,保证代码运行的安全;
提高编译器效率,增加运行速度;
为未来新版本的Javascript做好铺垫。
"严格模式"体现了Javascript更合理、更安全、更严谨的发展方向,包括IE 10在内的主流浏览器,都已经支持它,许多大项目已经开始全面拥抱它。

另一方面,同样的代码,在"严格模式"中,可能会有不一样的运行结果;一些在"正常模式"下可以运行的语句,在"严格模式"下将不能运行。掌握这些内容,有助于更细致深入地理解Javascript,让你变成一个更好的程序员。
迭代器
// 需求: 封装一个迭代器
function arrIterator(arr) {
    let i = 0
    return {
        next: function() {
            let done = i > arr.length - 1 ? true : false
            let value = !done ? arr[i++] : 'undefined'
            return {
                done,
                value
            }
        }
    }
}

let arr = [1,2,3,4,5]
let iterator = arrIterator(arr)
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())

// 输出结果
// { done: false, value: 1 }
// { done: false, value: 2 }
// { done: false, value: 3 }
// { done: false, value: 4 }
// { done: false, value: 5 }
// { done: true, value: 'undefined' }
生成器
// 生成器
// 作用: 用于生成迭代器
function *generator(arr) {
    for(let i=0; i<arr.length; i++) {
        yield arr[i]
    }
}

let arr = [1,2,3,4,5]
const arrIterator = generator(arr)
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())

// 生成器
// 作用: 用于生成迭代器
// 案例一
function *generator(arr) {
    for(let i=0; i<arr.length; i++) {
        yield arr[i]
    }
}

let arr = [1,2,3,4,5]
const arrIterator = generator(arr)
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())

// 输出结果
// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
// { value: 4, done: false }
// { value: 5, done: false }
// { value: undefined, done: true }


// 案例二
// 生成器可以yield 一个Promise实例对象
function *generator() {
    yield sumAfter1000ms(1,2).then(res => console.log(res))
    yield sumAfter1000ms(2,2).then(res => console.log(res))
}

function sumAfter1000ms(a,b) {
    return new Promise((resolve, reject) => {
        setTimeout(function(){
            resolve(a+b)
        }, 2000)
    })
}

const iterator = generator()
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())

// 输出结果
// { value: Promise { <pending> }, done: false }
// { value: Promise { <pending> }, done: false }
// { value: undefined, done: true }
// 3
// 4
Promise
promise作用: 
- 解决毁掉地狱的问题
- 使代码调用更加清晰易懂

promise的三种状态: 
- pending
- resolve
- reject. 

promise特点: 
- 使用resolve和reject封装结果回调函数
- Promise的实例会调用.then方法

// 案例一
// 不使用promise的情况
function fun(a, b, cb) {
    setTimeout(function(){
        return cb(a + b)
    }, 2000)
}

fun(1,2, res => {
    console.log(res)
    fun(3,4, res => {
        console.log(res)
        fun(4, 5, res => {
            console.log(res)
        })
    })
})

// 案例二: 使用promise的写法
function sum(a,b) {
    return new Promise((resolve, reject) => {
        setTimeout(function() {
            resolve(a + b)
        }, 2000)
    })
}

sum(1,2) 
.then(res => {
    console.log(res)
})

// 案例三: 使用promise写法封装一个读文件操作函数
const fs = require('fs')
function readFile(filename) {
    return new Promise((resolve, reject) => {
        fs.readFile(filename, (err, res) => {
            if (err) {
                reject(new Error('所读的文件不存在'))
                return
            } 
            resolve(res.toString())
        })
    })
}

readFile('./1.txt').then(res => {
    console.log(res)
}).catch(err => {
    console.log(err)
})
async await

题,就像题目说的需要计算出时间差,虽然不太难,但这个需求经常会在项目中遇到的,我在这边做一下整理,希望能够尽量全的整理出来。有需要的朋友可以做一下参考,喜欢的可以点波赞,或者关注一下,希望可以帮到大家。

分享之前我先推荐下我自己的web前端学习交流群:675498134,不管你是小白还是大神,我都欢迎你们进群交流,不定期分享干货,包括我自己整理的最新的前端资料和教程送给大家,欢迎初学和进阶中的小伙伴,一起学习一起交流,共同进步。

计算时间差原理:

getTime()方法

方法定义: getTime() 方法可返回距 1970 年 1 月 1 日之间的毫秒数。

通常我们计算时间差都是通过获取两个时间数据,然后分别使用getTime()方法返回与固定的1970 年 1 月 1 日的时间差,通过对返回毫秒数的差,换算成时间单位,得出两个时间的时间差。

开始操作:

首先你会有一串初始的时间数据,然后通过 new Date(你的时间数据),将你的数据转成Date对象的形式。

 var t1="2017/08/28 04:56:38"; //数据
 var dateBegin = new Date(t1);//转化为Date对象的形式
 //Mon Aug 28 2017 04:56:38 GMT+0800 (中国标准时间) 这里就是Date对象的数据形式

时间格式

这里的话就要注意一下后端给的时间数据格式的问题,比如下面两种:

 第一种:"2017/08/28 04:56:38"//这种格式不用再进行处理
 第二种:"2017-08-01 18:56:38"//这种格式就要进行处理

因为new Date()方法不能处理第二种数据,所以我们这里需要将第二种数据格式转化为第一种数据的格式

 var t1="2017-05-12 00:13:53";
 var dateBegin = new Date(d1.replace(/-/g, "/"));//replace方法将-转为/

不知道大家是什么情况,反正因为我们后端给我的数据就是第二种的,所以我会提一下这个东西(捂脸)。

另一个时间数据:

既然是时间差的话,就肯定要有两个数据,不然怎么两相比较,一般两个数据中都会有一个当前时间的数据。

 var dateEnd = new Date();//当前时间数据

完整计算时间差(天、小时、分钟、秒)的代码:

先获取之间的毫秒差,通过毫秒差换算出你所需要的时间单位,然后时间单位之间的换算根据的是他们的倍数关系。

function timeFn(d1) {//di作为一个变量传进来
 //如果时间格式是正确的,那下面这一步转化时间格式就可以不用了
 var dateBegin = new Date(d1.replace(/-/g, "/"));//将-转化为/,使用new Date
 var dateEnd = new Date();//获取当前时间
 var dateDiff = dateEnd.getTime() - dateBegin.getTime();//时间差的毫秒数
 var dayDiff = Math.floor(dateDiff / (24 * 3600 * 1000));//计算出相差天数
 var leave1=dateDiff%(24*3600*1000) //计算天数后剩余的毫秒数
 var hours=Math.floor(leave1/(3600*1000))//计算出小时数
 //计算相差分钟数
 var leave2=leave1%(3600*1000) //计算小时数后剩余的毫秒数
 var minutes=Math.floor(leave2/(60*1000))//计算相差分钟数
 //计算相差秒数
 var leave3=leave2%(60*1000) //计算分钟数后剩余的毫秒数
 var seconds=Math.round(leave3/1000)
 console.log(" 相差 "+dayDiff+"天 "+hours+"小时 "+minutes+" 分钟"+seconds+" 秒")
 console.log(dateDiff+"时间差的毫秒数",dayDiff+"计算出相差天数",leave1+"计算天数后剩余的毫秒数"
 ,hours+"计算出小时数",minutes+"计算相差分钟数",seconds+"计算相差秒数");
}
var t3="2017-08-18 04:56:38";
timeFn(t3);

demo时间差数据截图

不成熟的计算月、年:

 //这里的dayDiff就是上文计算出的天数差
 let monthDiff=Math.floor(dayDiff/30);//以30天为一个月不够精准严谨
 //获取相差的月份
 if (monthDiff<12){
 timeThis=monthDiff+"个月前发布";//获取相差的月份
 return
 }
 let yearDiff=Math.floor(monthDiff/12);//获取相差的年份
 if(yearDiff>=1){
 timeThis=yearDiff+"年前发布";
 return
 }

当天数相差较大的时候,单纯计算天数已经不能满足需求了,因为我们PM说的统一以30天为一个月的分界线,然后这里月份的计算情况感觉很复杂的样子没有继续研究下去。

获取当前月份的天数

 function getDays() {
 //构造当前日期对象
 var date = new Date();
 var year = date.getFullYear();//获取年份
 var mouth = date.getMonth() + 1;//获取当前月份
 var days;//定义当月的天数;
 if (mouth == 2) {//当月份为二月时,根据闰年还是非闰年判断天数
 days = year % 4 == 0 ? 29 : 28;
 }
 else if (mouth == 1 || mouth == 3 || mouth == 5 || mouth == 7 || mouth == 8 || mouth == 10 || mouth == 12) {
 //月份为:1,3,5,7,8,10,12 时,为大月.则天数为31;
 days = 31;
 }
 else {
 //其他月份,天数为:30.
 days = 30;
 }
 return days;
 }

网上找了个获取当前月份天数的函数,上面的注释也足够全,我就一起贴上来,连接在下面。

后话

上面就是本文计算时间差的内容了,希望看完本文能给大家一点帮助。最后一个提示:一般需要处理的数据不会只有一两个,很可能会给一个数组,你需要处理每个数组元素的时间数据,这时候建议用forEach()函数遍历整个数组。

如果觉得我的文章对您有用,请点赞收藏。您的支持将鼓励我继续创作。

知识分享到这里就结束了,web前端学习的可以来我的群,群里每天都有对应资料学习:675498134,欢迎初学和进阶中的小伙伴。

ue 示例

在JavaScript或Vue中获取当前时间并格式化输出到精确的时分秒,你可以使用Date对象结合字符串拼接或者模板字符串来实现。下面是一个简单示例,展示了如何在Vue中完成这项任务:

<template>
  <div>
    <p>当前时间:{{ formattedTime }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      formattedTime: ''
    };
  },
  mounted() {
    this.updateTime();
    setInterval(this.updateTime, 1000); // 每秒更新一次
  },
  methods: {
    updateTime() {
      const now = new Date();
      // 使用模板字符串进行格式化
      this.formattedTime = `${now.getFullYear()}-${this.padZero(now.getMonth() + 1)}-${this.padZero(now.getDate())} ${this.padZero(now.getHours())}:${this.padZero(now.getMinutes())}:${this.padZero(now.getSeconds())}`;
    },
    // 辅助函数,用于补零操作
    padZero(num) {
      return num < 10 ? '0' + num : num;
    }
  },
  beforeDestroy() {
    // 清除定时器,避免内存泄漏
    clearInterval(this.timer);
  }
};
</script>

在这个示例中,我们在Vue组件的mounted生命周期钩子中初始化了一个定时器,每秒钟调用updateTime方法来更新当前时间,并在组件销毁前通过beforeDestroy钩子清理定时器。

updateTime方法中,我们创建了一个新的Date对象来获取当前时间,然后使用模板字符串和辅助函数padZero来确保月份、日期、小时、分钟和秒数如果是个位数,则在其前补零,以便格式统一和美观。

这样,页面上就会显示一个实时更新的当前时间,格式为“年-月-日 时:分:秒”。

Vue3 Composition API 示例

在Vue3中,虽然一些API和写法有所变化,但获取和格式化当前时间的基本逻辑与Vue2相似。以下是使用Vue3 Composition API的一个示例:

<template>
  <div>
    <p>当前时间:{{ formattedTime }}</p>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';

const formattedTime = ref('');
let timer = null;

const updateTime = () => {
  const now = new Date();
  formattedTime.value = `${now.getFullYear()}-${padZero(now.getMonth() + 1)}-${padZero(now.getDate())} ${padZero(now.getHours())}:${padZero(now.getMinutes())}:${padZero(now.getSeconds())}`;
};

const padZero = (num) => {
  return num < 10 ? '0' + num : num;
};

onMounted(() => {
  updateTime();
  timer = setInterval(updateTime, 1000); // 每秒更新一次
});

onBeforeUnmount(() => {
  // 清除定时器
  clearInterval(timer);
});
</script>

在这个Vue3的示例中,我们使用了Composition API来管理状态和生命周期钩子。ref用于定义响应式数据formattedTime,而onMounted和onBeforeUnmount分别替代了Vue2中的mounted和beforeDestroy生命周期钩子。

updateTime函数和padZero辅助函数的功能与Vue2示例相同,用于获取当前时间并进行格式化处理,以及在数字小于10时前面添加零。

这样,你就可以在Vue3应用中实现实时更新并格式化显示当前时间的功能。

TypeScript 公共函数封装

使用TypeScript可以为你的代码增加类型安全。下面是如何封装一个获取并格式化当前时间的公共函数,这个函数可以在Vue3的项目中作为公共方法使用。

首先,在你的Vue3项目的某个公用文件夹(如src/utils)下创建一个名为dateTimeUtils.ts的文件,并编写如下代码:

// src/utils/dateTimeUtils.ts

export function formatCurrentTime(): string {
  const now = new Date();
  return `${now.getFullYear()}-${padZero(now.getMonth() + 1)}-${padZero(now.getDate())} ${padZero(now.getHours())}:${padZero(now.getMinutes())}:${padZero(now.getSeconds())}`;
}

function padZero(num: number): string {
  return num < 10 ? '0' + num : num.toString();
}

这个模块导出了一个formatCurrentTime函数,它返回当前时间的格式化字符串。同时,内部使用了padZero辅助函数来保证数字的格式正确。

然后,在你的Vue3组件中,你可以这样使用这个公共函数:

// 某个Vue3组件.vue文件

<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { formatCurrentTime } from '@/utils/dateTimeUtils'; // 根据你的实际路径调整

const formattedTime = ref('');

onMounted(() => {
  formattedTime.value = formatCurrentTime();
  setInterval(() => {
    formattedTime.value = formatCurrentTime();
  }, 1000);
});
</script>

<template>
  <div>
    <p>当前时间:{{ formattedTime }}</p>
  </div>
</template>

这里,我们导入了formatCurrentTime函数,并在组件挂载时设置初始值,之后每秒更新一次显示的时间。注意,为了避免潜在的内存泄漏,如果组件需要销毁时停止时间更新,你可能还需要在适当的生命周期钩子中清除定时器,正如之前Vue2和Vue3 Composition API示例中所示。不过,在此示例中为了保持简洁,省略了该部分代码。