面试记录06/27

本文详细介绍了JavaScript中数组的splice和slice方法,包括它们的参数、操作和返回值。splice用于添加、删除或替换数组元素,会改变原数组;而slice则返回一个新的数组副本,不修改原数组。此外,还提到了Vue的$nextTick、JavaScript的事件循环机制以及CSS中盒子的居中布局技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数组的splice和slice的区别

splice:粘接(胶片),拼接
slice: 切,割,切成片,切开

splice

splice(开始位置,要删除的元素的数量,要插入的元素)方法通过删除或者替换现有元素或者添加新元素来修改原数组,会返回被删除的元素组成的数组

添加

从下标为1的位置开始,删除0个元素,从1 的位置开始插入 9 和 10, 返回一个空数组

const arr = [1, 2, 3, 4, 5];
arr.splice(1,0,9,10);
console.log(arr);// [1, 9, 10, 2, 3, 4, 5]

删除

从下标为2的位置开始,删除三个元素

const arr = [1, 2, 3, 4, 5];
//返回被删除的元素组成的数组[3, 4, 5]
arr.splice(2,3);
console.log(arr);// [1, 2]

插入

从从下标为1的位置开始,删除三个数,再插入a,b

const arr = [1, 2, 3, 4, 5];
//返回被删除的元素组成的数组[2, 3, 4]
arr.splice(1,3,'a','b');
console.log(arr);// [1, 'a', 'b', 5]

slice

slice(提取开始的位置,提取结束的位置)方法返回一个新数组,包含从原数组中指定的开始位置到结束位置(不包括结束位置)的元素,不会改变原数组,且两个参数都是可选的
从下标为2的位置开始截取,到下标为4的位置为止,不包含下标为4的位置,原数组没有改变

const arr = [1, 2, 3, 4, 5];
//返回返回[3, 4]
arr.slice(2,4);//
console.log(arr);// [1, 2, 3, 4, 5]原数组没有改变

如果slice()两个参数都不写,则直接复制数组,是浅拷贝

let arr = [1,2,3];
let arr1 = arr.slice();
arr1[0]=190;
console.log(arr);//改变arr1,原数组不会改变

如果slice()只写一个参数,则从这个位置一直截取到数组的末尾

let arr = [1,2,3];
let arr1 = arr.slice(1);
console.log(arr1);//[2,3]
console.log(arr);//[1,2,3]

总结

slice()是纯粹的读取操作,不会对原数组进行修改,而splice()是对数组精选操作会修改原数组
slice()的参数是起始位置和结束位置,返回选定元素组成的新数组;splice()的参数是起始位置、删除的元素的个数、插入的元素(可选参数)返回被删除的元素组成的数组,没有被删除的元素就返回空数组
slice()的结束位置是不包含再选取范围内的,而splice()中删除元素的个数是包含再操作范围内的
slice()不会改变原数组的长度,而splice()可以改变数组的长度
slice() 是用来提取数组中的一部分元素,不改变原数组,而 splice() 是用来操作数组,可以删除、替换或插入元素,会改变原数组。

reduce

reduce(callbackFn, initialValue(可选))
callbackFn为数组中每个元素执行的函数,它的返回值作为下一次调用callbackFn时的accumulator参数,对于最后一次调用,返回值将会作为reduce()的返回值
callbackFn(accumulator, currentValue, currentIndex, array)
accumulator:上一次调用callbackFn的结果,在第一次调用时,如果指定了initialValue,则为这个initialValue的值,否则为array[0]的值
currentValue:当前元素的值,在第一次调用时,如果指定了initialValue,则为array[0]的值,否则为array[1]的值
currentIndex:currentValue在数组中的索引位置,在第一次调用时如果指定了initalValue,则为0,否则为1
array: 调用了reduce()的数组本身
initialValue可选,第一调用回调时初始化accumulator的值,如果指定了initalValue,则callbackFn从数组中的第一个值作为currentValue开始执行,如果没有指定initialValue,则accumulator初始化为数组中的第一个值,并且从callbackFn从数组中的第二个值作为currentValue开始执行,在这种情况下,如果数组为空(没有第一个值可以作为accumulator返回),则会抛出错误
空值合并运算符(??)是一个逻辑运算符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。
实现reduce

Array.prototype.myReduce = function(callbackFn, initialValue){
  let arr = Array.prototype.slice.call(this),//将当前数组拷贝一份
    //上一次执行函数的结果,如果存在initialValue,就是initialValue,否则就是arr[0]
      res = initialValue ? initialValue : arr[0],
    // 数组循环的开始位置
      startIndex = initialValue ? 0 : 1;
  // 遍历数组让数组中的每一项都执行callbackFn函数,将每次执行callbackFn函数得到的返回值,
  // 赋值给res
  for(let i = startIndex; i < arr.length; i++){
    /**
    res上一次的值
    arr[i]当前这一项
    i当前项的下标
    调用myReduce函数的数组本身
    */
    res = callbackFn(res, arr[i], i, this);
  }
}

Vue.$nextTick

在下次DOM更新循环结束在之后执行延迟回调,在修改数据之后立即使用这个方法,获取更新后的DOM
可以理解成,Vue在更新DOM时是异步执行的,当数据发生变化,Vue将开启一个异步更新队列,把这些变化都放到这个异步队列里面,同时还会对这个队列里面的操作进行去重,视图需要等队列中所有数据变化完成后,在统一进行更新
简单点说就是放在$nextick中的操作不会立即执行,而是等到数据更新、DOM更新完成之后在执行,

使用场景

如果想要在数据修改之后立即获得更新后的DOM 就可以使用Vue.$nextTick()
created中获取DOM的操作

浏览器事件循环机制

Javascript是单线程的,也就是说只有一个主线程来处理所有的任务,那么JavaScript是如何实现单线程非阻塞的呢?那就是通过事件循环机制

执行栈和任务队列

javascript在执行代码的时候,是从上到下按顺序执行的
当遇到同步任务的时候会把同步任务添加到执行栈中执行
遇到异步任务的时候,不会立即执行,而是加入到异步队列中,等待栈中的同步任务执行完之后,在执行异步任务队列中的异步任务
而异步任务又分为宏任务和微任务
宏任务:setTimeout,setInterval,setImmediate,I/O,UI rendering
微任务:process.nextTick,Promist,MutationObserver,Object,observe

事件循环的过程

处理同步任务,依次把同步任务放入到执行栈中执行
遇到异步任务把异步任务放入到异步任务队列中
等同步任务执行完之后,处理任务队列
按顺序执行所有的微任务
进行必要的UI渲染
接着执行宏任务中的异步代码
开始下一轮事件循环

v-if和v-for优先级的问题

在vue2中v-for的优先级会比v-if高,哪怕只渲染列表的一小部分元素,也得在每次城府渲染的时候遍历整个列表
vue3中v-if的优先级比v-for高,所以v-if执行的时候,它调用的变量还不存在,就会导致异常
什么情况下会出现v-if和v-for一起使用?
为了过滤列表中的项目,这时候可以使用计算属性返回一个过滤后的列表在进行循环
为了避免渲染本应该被隐藏的列表,此时可以通过将v-if移动到容器元素上例如外面包一层template

盒子垂直水平居中

定位 + margin:auto

<style>
    .father{
        width:500px;
        height:300px;
        border:1px solid #0a3b98;
        position: relative;
    }
    .son{
        width:100px;
        height:40px;
        background: #f0a238;
        position: absolute;
        top:0;
        left:0;
        right:0;
        bottom:0;
        margin:auto;
    }
</style>
<div class="father">
    <div class="son"></div>
</div>

定位 + margin:负值(自身宽高的一半)因此必须要有宽高

<style>
    .father {
        position: relative;
        width: 200px;
        height: 200px;
        background: skyblue;
    }
    .son {
        position: absolute;
        top: 50%;
        left: 50%;
        margin-left:-50px;
        margin-top:-50px;
        width: 100px;
        height: 100px;
        background: red;
    }
</style>
<div class="father">
    <div class="son"></div>
</div>

定位 + transform:translate(-50%,-50%)可以不用宽高

<style>
    .father {
        position: relative;
        width: 200px;
        height: 200px;
        background: skyblue;
    }
    .son {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%,-50%);
        width: 100px;
        height: 100px;
        background: red;
    }
</style>
<div class="father">
    <div class="son"></div>
</div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值