本文目录
前言
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);
}
第三种效果如下:
在学习的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。