javascript中模拟排队系统、深度克隆以及转盘抽奖及数组的操作

前言

JavaScript 是一种轻量级的编程语言,它赋予了网页交互性和动态功能。自诞生以来,JavaScript 已成为前端开发不可或缺的核心技术之一。它可以直接嵌入HTML页面中,通过操作DOM(文档对象模型)和CSS(层叠样式表),实现页面的动态效果、用户交互以及数据交换等。

1、利用js模拟排队系统

今天给大家分享的是js模拟排队系统,刚开始有排队序列,序列里有vip用户和普通用户,vip用户永远位于普通用户的前面,只有当当前vip用户都办理好手续,才会叫号普通用户,每5秒产生一个随机客户。
效果如图:
在这里插入图片描述
代码给出:

// 函数的闭包,立即执行
        var autoPerson = (function () {
            // 定义vip用户和普通用户
            var vipNum = 0;
            var norNum = 0;
            return function () {
                // 随机产生vip或者普通用户
                var randomNum = Math.random();
            if ( randomNum > 0.5) {
                vipNum++;
                return "V" + vipNum;
            }
            else {
                norNum++;
                return "N" + norNum;
            }
        }
    })();
        // 定义一个排队数组,长度为6
        var personArr = [];
        var perLen = 6;
        for( var i = 0; i < perLen; i++) {
            // 每循环一次掉用函数vipFirst函数一次,传入参数,随机产生vip或者普通用户
            vipFirst(autoPerson());
        }
        // 对数组进行整合,如果当前传入的客户是VIP的话
        function vipFirst(person) {
            if ( person[0] == "V") {
                // 那么遍历现存的数组
                for( var i = 0; i < personArr.length; i++) {
                    // 并且找出数组里普通用户所在的位置
                    if ( personArr[i][0] == "N") {
                        // splice数组方法,找到当前位置上的普通用户,0代表不删除,并在这个普通用户之前插入这位vip用户
                        personArr.splice(i, 0, person);
                        // 注意这边插入后,需返回,否则可能引起无限循环,重复插入,导致浏览器奔溃
                        return;
                    }
                }
            }
            // 如果当前的用户不是VIP用户的话,那么就按普通先到的用户排列
            personArr.push(person);
        }
        // 打印当前队列
        console.log("现存队列:" + personArr);
        // 设置一个计时器,每5秒执行一次
        var timer = setInterval(listMove, 5000);
        
        function listMove() {
            // 删除数组第一位,并将这个值返回给firstPer
            var firstPer = personArr.shift();
            // 打印出来当前叫号的客户
            console.log("叫号:" + firstPer);

            // 随机再来一个用户
            var newper = autoPerson();
            // 打印当前新来的客户编号
            console.log("新人:" + newper);
            // 将新来的客户如果是vip用户,就插入到普通用户前
            vipFirst(newper);
            // 再次打印当前的队列
            console.log("现存队形:" + personArr);
        }

2、JS的深度克隆,利用构造函数原型深度克隆

今天来写写,JS中的深度克隆,这个在笔面试中,考的还是比较多的,主要是对象与数组的赋值,如果直接赋值的话,那么得到的是对象或者数组在堆里的地址,那么原有的的数据修改的话,那么克隆的数据也会随着修改,这就是浅克隆,所以这边就要使用到枚举,然后再每一项赋值,这样就可以完成一份深度克隆,这样原对象里修改属性,如果你在这对象修改之前已经克隆的话,那么你这个克隆的对象,对象里的属性是不变,这就是深度克隆。
话不多说了,直接上代码:

// 假设要克隆的对象a
        var a = {
            a: 1,
            b: 2,
            c: {
                d: 3,
                e: 4,
                f: [0, 9, 8, 7, [6, 5, 4]]
            }
        };

        // 自定义克隆函数
        function clone(obj) {
            // 判断,如果传进来的参数是数组的话
            if ( obj instanceof Array) {
                // 定义一个空数组
                var arr = [];
                // 遍历整个数组
                for( var i = 0; i < obj.length; i++) {
                    // 深度克隆数组每一项
                    arr[i] = clone(obj[i]);
                }
                // 再返回出去
                return arr;
            }
            // 判断是否为对象
            if ( obj instanceof Object) {
                // 构建一个空对象
                var obj1 = {};
                // 枚举传进来的对象
                for( key in obj) {
                    // 深度克隆对象
                    obj1[key] = clone(obj[key]);
                }
                // 再返回出去
                return obj1;
            }
            // 如果传进的不是数组,也不是对象,那么就返回当前值
            return obj;
        }



        // 利用构造函数的原型克隆,也可以实现深度克隆
        function clone1(obj) {
            function F() {};
            F.prototype = obj;
            return new F()
        }

3、原生JS实现简易转盘抽奖

今天给大家分享一个利用原生JS完成的简易的转盘抽奖。
HTML与CSS在这边不是主要讲的内容。因此HTML与CSS就没有过多的注释,在这里说一点CSS,主要利用到了CSS的class类名,与JS一起控制背景颜色,以及中奖结果的显示与隐藏,但大部分是JS,所以JS这里基本没行都有详细的注释,简单的功能,欢迎一起技术探讨,一起成长。
效果如下: 点击查看效果

代码给出:
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>turntable</title>
    /*<link rel="stylesheet" href="css/index.css">*/
    <!-- css -->
    <style>
	body, table, tr, td {
        margin: 0;
        padding: 0;
    }
    .wrapper {
        position: relative;
        width: 300px;
        height: 300px;
        margin: 100px auto 0;
        text-align: center;
    }
    table {
        display: inline-block;
    }
    td, th {
        width: 100px;
        height: 100px;
        border: 1px solid #ccc;
        border-radius: 20px;
    }
    th {
        cursor: pointer;
        user-select: none;
    }
    /* 设置标识样式 */
    tr .active {
        background-color: #ff6700;
    }
    /* 设置中奖结果 */
    .results {
        display: none;
        position: absolute;
        top: 0;
        left: 50px;
        width: 200px;
        height: 100px;
        border: 1px solid black;
        border-radius: 30px;
        text-align: center;
        line-height: 100px;
        background-color: skyblue;
    }
	</style>
</head>
<body>
    <div class="wrapper">
        <table>
            <tr>
                <td class="active">今</td>
                <td>天</td>
                <td>吃</td>
            </tr>
            <tr>
                <td>什</td>
                <th id="play">开始</th>
                <td>么</td>
            </tr>
            <tr>
                <td>来</td>
                <td>抽</td>
                <td>下</td>
            </tr>
        </table>
        <div class="results">今天吃火锅</div>
    </div>
   <!-- <script src="js/index.js"></script> -->
   <!-- js -->
   <script>
	// 获取开始元素
var playBtn = document.getElementById('play');
// 获取所有td元素,获取到伪数组
var tdAry = document.getElementsByTagName('td');
// 将伪数组的长度存储在tdLen变量中
var tdLen = tdAry.length;
// 设置计时器变量,刚开始为空
var startTime = null;
// 自己构造数组,使橘红色背景能够按照自己想要的方向进行循环移动
var tdList = [0, 1, 2, 4, 7, 6, 5, 3];
// 设置橘红色背景标识
var tdId = 0;
// 设置已经奔跑的次数,刚开始为0次
var time = 0;
// 固定跑3圈,一圈8次
var fixNum = 24
// 定义最大随机数
var MaxNum;
// 定义随机数,开始和结束的阈值
var randomNum;
// 获取中奖结果元素
var results = document.getElementsByClassName('results')[0];

// 绑定点击事件,当鼠标点击开始按钮后,触发playStart函数
playBtn.onclick = playStart;

function playStart() {
    // 如果计时器不为空,那就意味着这个线程已经在跑了,就直接退出。
    if (startTime != null) {
        return;
    }
    results.style.display = 'none';
    // 奔跑的次数
    time = 0;
    // 最大随机数,取值[0, 8],确保每个都能被选到
    MaxNum = parseInt(Math.random() * 9) + fixNum;
    // 随机阈值,控制刚开始跑几步加速,以及剩几步减速,取值范围[3, 7]
    randomNum = parseInt(Math.random() * 5 + 3);
    // 开启计时器,每200毫秒执行一次move函数
    startTime = setInterval(move,200);
    
}

function move() {
    // 每执行一次奔跑次数time就加1
    time++;
    // 每次运行当前的背景色清空
    tdAry[tdList[tdId]].className = "";
    // 每执行一次背景色标识就加1
    tdId++;
    // 判断如果标识大于7的话就标识tdId就等于0,否则的话就等于它本身,这个步骤如果没有进行判断和赋值的话,tdId就会一直自增下去,那么对应的td元素将没有,后台就会报错
    tdId = tdId > 7 ? 0 : tdId;
    // 设置当前的td背景色
    tdAry[tdList[tdId]].className = "active";
    
    //如果奔跑的次数等于随机阈值的话,那么当前的计时器清空,重新开启一个新的计时器,并且是每20毫秒执行一次,这个步骤是控制加速的 
    if (time == randomNum) {
        clearInterval(startTime);
        startTime = setInterval(move,20);
    }

    // 如果奔跑的次数加上随机的阈值的话,那么就将当前的加速的计时器清空,并且重新开启一个每200毫秒的计时器,这个步骤是控制减速的
    if (time + randomNum >= MaxNum) {
        clearInterval(startTime);
        startTime = setInterval(move,200);
    }

    // 如果奔跑的次数大于等于最大的奔跑次数,那么清空当前计时器,并且计时器等于null,直接返回出去,一次抽奖结束。这个步骤是控制抽奖结束。
    if (time >= MaxNum) {
        clearInterval(startTime);
        startTime = null;
        // switch语句判断抽奖结果,这部分比较简单,就不赘述了。
        switch(tdList[tdId]) {
            case 0:
                results.innerText = '今天吃转转乐';
                results.style.display = 'block';
                break;
            case 1:
                results.innerText = '今天吃蜀九香';
                results.style.display = 'block';
                break;
            case 2:
                results.innerText = '今天吃KFC';
                results.style.display = 'block';
                break;
            case 4:
                results.innerText = '今天吃海底捞';
                results.style.display = 'block';
                break;
            case 7:
                results.innerText = '今天吃外卖';
                results.style.display = 'block';
                break;
            case 6:
                results.innerText = '今天吃土';
                results.style.display = 'block';
                break;
            case 5:
                results.innerText = '今天吃牛排';
                results.style.display = 'block';
                break;
            case 3:
                results.innerText = '今天吃草本汤';
                results.style.display = 'block';
                break;
        }
        return;
    }

}


	</script>
</body>
</html>

4、js去除数组里重复的条目,返回被删除的条目的新数组

今天给大家分享的是利用js进行数组的去重,还是老样子,该注释的都注释在代码里了

欢迎一起技术探讨,一起成长。

效果如下:
在这里插入图片描述
代码如下:

// 给本地数组对象,添加一个原型方法distinct
        Array.prototype.distinct = function () {
            // 定义一个空数组
            var ret = [];
            // 循环遍历数组
            for( var i = 0; i < this.length; i++) {
                // 循环遍历每次都比i大1,意味着,i是第一位时,j是2位,拿数组第一位与第二位,以及以此对比,如果跟数组第一位重复,那么删除,以此类推。仅且仅当不重复时,也就是没有裁剪,才需要j++,否则裁剪,j自动变为下一位
                for( var j = i + 1; j < this.length; ) {
                    if ( this[i] === this[j]) {
                        // 将裁剪后的数组的第一位添加到自己定义的空数组里
                        ret.push(this.splice( j, 1 )[0]);
                    }
                    else {
                        j++;
                    }
                }
            }
            // 返回数组
            return ret;
        }

5、正则表达式,js里的正则应用

在js中定义正则有直接量,和RegExp类。
直接量的方式为: /字符模式/标志字符 这样说可能不太好理解,直接上代码吧,直接量可以直接写成这样 var reg = /a[0-9]/g 这个匹配是什么意思呢,匹配a1~a9任意一个,仅且只能一个,g在这里是全匹配的意思,还有 i 意思是不分大小写 m 多行匹配。
+:至少一个。 *:零个或多个。?:零个或一个。 限定词 ^:第一个单词开始匹配,$最后一个单词。其他规则也不多说了,太多太多了,我也没记全,讲讲用的比较频繁的吧,记住匹配方法就可以了。
匹配年龄。要求1-150 。那么我们这边定义直接量进行匹配,上代码和结果:
在这里插入图片描述
不要看到这一大串是什么东东就慌了,我们来分析下,首先开始位置为脱字符^,结束位置为美元符 $,这两个一起的意思是说,匹配当前行,就比如说你输入框输入年龄,那么这个年龄就是当前行,这个就是匹配当前行。

接着来,我们发现表达式有个括号,啥意思,因为再看,里面有三个或 | 这个符号就是或的意思,那么在这里面或比较多,所以外面表达式用括号括起来,以防止它本身语句混乱。

接着看,我们都说了3个或,那是不是又可以拆成,[1-9][0-9]?,1[0-4][0-9],150。
第一个表达式 [1-9][0-9]? 那么这个中括号括起来是什么意思,中括号括起来的意思是说,当前只能选其中一个,第一位只能选择 1 到 9,第二位只能取 0 到 9,那么这个后面问号是啥东西,这个问号,前面已经说了,可以有0个或者1个,所以第一个表达式的意思就是可以取值 1到99 ,这个好理解吧。

那么第二个表达式也是同理,1[0-4][0-9],第一位只能取1,第二位可以取0到4,第三位可以取0到9,所以这个表达式的意思就是,可以取值100到149,这样加上我们第一个表达式,现在已经满足,取值1到149了。

那么还差最后一个数150,我们直接加上即可。OK匹配年龄完成。还有3个,匹配qq号,匹配邮箱,提取任意网址的参数。


6、二分法有序数组搜索

时间复杂度为O(nlogN)。
自定义函数,两个形参,第一个是要搜索的数组,第二个是要搜索的元素。如果这个元素存在在这个数组里的话,则返回这个元素所在的索引值,否则的话返回-1.
具体效果如下(假设一个有序数组):
在这里插入图片描述
搜索3这个元素是否在这个有序数组里,是的话则返回它所在的索引值,结果发现,是存在的。那么再搜索11是否在这个有序数组里,结果返回是-1,是不存在的。
好了,代码给出:

 // 假设有序数组
        var arr = [1, 2, 3, 4, 5, 6, 9, 10];

        // 数组二分法,第一个参数为传入的数组,第二个参数是,要搜索这个数组里的元素,如果存在则返回这个元素的索引,如果没有则返回-1
        function indexOf(arr, val) {
            // 向下取整,确保更能接近数组的中间元素
            var i = Math.floor(arr.length / 2);
            // 判断传入的元素是否等于这个数组的中间元素,如果相对那么直接返回这个元素的索引
            if ( val === arr[i] ) {
                return i;
            }
            // 如果数组的长度为1,并且前面的判断不符合,那么直接返回-1,提高性能,少做一次判断
            if ( arr.length == 1 ) {
                return -1;
            }
            // 如果传入的元素小于这个数组的中间值,那么直接返回再次调用,indexOf,再寻找前半部分的元素,递归。
            else if ( val < arr[i] ) {
                return indexOf(arr.slice(0, i), val);
            }
            // 如果传入的参数比数组中间的元素大,那么再次调用indexOf,在寻找后半部分的元素,递归,注意此处,不能直接返回了,因为裁剪后的子数组,索引从0开始。如果没有找到的话就等于-1,如果查找到的话,那么索引值等于当前子数组的索引值加上 i+1(前面的二分法后一位的索引)
            else if ( val > arr[i] ) {
                var s = indexOf(arr.slice(i+1), val);
                return s == -1 ? s : s + i + 1;
            }
        }

7、3种时间复杂度实现不同类型的无序数组去重

js中不同类型的无序数组去重,
arr是我自己自定义的一个数组。这种去重的时间复杂度为O(n²),因为它进行了2次长度为n的循环。第一种代码如下:

// 定义一个数组
        var arr = [ 1, 2, 3, 4, 5, 3, 2, 5, 6, 7, 8, "1", {a: 1, b: 2}];
        // 时间复杂度为O(n²);
        function one(arr) {
            // 定义一个空数组
            var newArr = [];
            // 遍历数组
            for( key of arr) {
                // in -> 索引值,of -> 具体元素
                // console.log(key);
                // 如果这个空数组里没有这个元素的话,就给它添加上
                if ( newArr.indexOf(key) === -1) {
                    newArr.push(key);
                }
            }
            // 结果返回
            return newArr;
        }

第一种方法的效果如下:
在这里插入图片描述
第二种方法,时间的复杂度为O(nlogN),因为它对数组进行排序了,这种方法会改变原有数组的排序。如果不在乎就没事,如果在乎就不能使用这种方法。第二种代码如下:

// 时间复杂度为O(nlogN),不过这查重会导致不会安装原有的数组进行排序,即不稳定性,如果不在乎数组的排序,也可以,不影响,如果在乎就不行了
        function two(arr) {
            // 创建空数组
            var newArr = [];
            // 对数组排序
            arr.sort();
            // 遍历数组
            for( var i = 0; i < arr.length; i++) {
                // 如果当前的这个元素不等于下一个元素
                if ( arr[i] !== arr[i+1] ) {
                    // 那么将这个元素插入到新数组
                    newArr.push(arr[i]);
                }
            }
            return newArr;
        }

第二种效果如下:
在这里插入图片描述
第三种方法,运用到了ES6的集合对象,时间复杂度为O(n)。

第三种代码给出:

// 时间复杂度为O(n) ,利用ES6里的Set集合对象,它返回的是一个集合,不重复的
        function three(arr) {
            // 创建一个集合对象
            var set = new Set(arr);
            // 把集合再传回去,再转成数组
            return Array.from(set);
        } 

第三种效果如下:
在这里插入图片描述

在学习的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你华还是你华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值