面试题合集

面试合集,整合网上一些面试题及答案

CSS

1.CSS3 中伪元素 after 和 before

伪元素选择器可以帮助我们利用CSS创建新标签元素,而不需要HTML标签,从而简化HTML结构。两个重要的伪元素是::before、::after。伪元素前面是用两个冒号表示。

        :: before:在元素内部的前面插入内容

        :: after:在元素内部的后面插入内容

注:

        before 和 after 创建的元素属于行内元素

        before 和 after 创建的元素在文档树中找不到,所以称之为伪元素

        语法:element::before{}

        before 和 after 必须要有 content 属性

        伪元素选择器和标签选择器权重一样:0,0,0,1

2.content 属性

content 属性与 :before 及 :after 伪元素配合使用,来插入生成内容。

content 属性生成的对象称为“匿名替换元素”,生成的内容都是替换元素

content属性的特点

1. content生成的文本无法被选中

2. 设置了content属性,但无内容的元素,仍会被:empty伪类选择器选中

3. content动态生成的值无法获取。

content属性的应用

1. 清除浮动
.clear:after {
  content: '';
  display: table; /* 也可以是'block' */
  clear: both;
}
2. 实现“两端对齐”以及“垂直居中/上边缘/下边缘对齐”效果

参考范例:content辅助元素与布局 » CSS世界demo演示

3. 生成文本
<template>
    <div style="padding: 20px">
        <p class="ask">为什么open-quote/close-quote很少使用?</p>
        <p class="answer">因为直接使用字符更干脆!</p>
    </div>
</template>
<style scoped>
    .ask:before {
        content:'提问:“';
    }
    .answer:before {
        content:'回答:“';
    }
    .ask:after,
    .answer:after {
        content: '”';
    }
</style>
4. 计数器

一个简单的范例如下:

<template>
    <div style="padding: 20px">
        <div class="reset">
            <div class="counter">我是王小二的第5个孩子</div>
            <div class="counter">我是王小二的第7个孩子</div>
            <div class="counter">我是王小二的第9个孩子</div>
        </div>
    </div>
</template>
<style scoped>
    .reset {
        counter-reset: wangxiaoer 3;// 第1个参数用于给计数器取个自定义的名称,如此处wangxiaoer
                                    // 第2个参数为计数器的初始值(计数的起点),默认为0
    }
    .counter:before {
        content: counter(wangxiaoer) '. ';// 方法counter() 用于显示计数,参数为计数器的名称  wangxiaoer
        counter-increment: wangxiaoer 2;// 第1个参数为计数器的名称  wangxiaoer
                                        // 第2个参数为计数器的步长(即每次计数时的改变幅度),默认为1
    }
</style>

 显示为:
5.我是王小二的第5个孩子
7.我是王小二的第7个孩子
9.我是王小二的第9个孩子

注意事项

显示content计数值的那个DOM元素在文档流中的位置一定要在counter-increment元素的后面,否则是没有计数效果的。

 3.盒模型

标准盒子模型和怪异盒模型

 1)一个盒子由外到内可以分成四个部分:margin(外边距)、border(边框)、padding(内边距)、content(内容)。会发现margin、border、padding是CSS属性,因此可以通过这三个属性来控制盒子的这三个部分。而content则是HTML元素的内容。

 2)width和height属性设置的就是盒子的宽度和高度。盒子的宽度和高度的计算方式由box-sizing属性控制。

        box-sizing属性值
        content-box:默认值,width和height属性分别应用到元素的内容框。在宽度和高度之外绘制元素的内边距、边框、外边距。
        border-box:为元素设定的width和height属性决定了元素的边框盒。就是说,为元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制。通过从已设定的宽度和高度分别减去 边框 和 内边距 才能得到内容的宽度和高度。
        inherit:规定应从父元素继承box-sizing属性的值

        当box-sizing:content-box时,这种盒子模型成为标准盒子模型,当box-sizing: border-box时,这种盒子模型称为IE盒子模型(怪异盒模型)。

盒模型的计算:

标准盒子模型中,width(height)= content;

Ie盒子模型(怪异盒模型)中,

width(height)= border+padding+content;

box-sizing:border-box(怪异盒模型);

box-sizing:content-box(标准盒模型);

4.元素居中方法(常用)

1.flex布局 

display: flex;
justify-content: center;
align-items: center;

 2.定位

position: absolute;
left:50%;
top:50%;
transform: translate(-50%,-50%);(在当前位置偏移自身宽高的一半)

 JS

1.防抖和节流

本质上是优化高频率执行代码的一种手段

防抖(Debounce)和节流(Throttle)都是用来控制某个函数在一定时间内触发次数,两者都是为了减少触发频率,以便提高性能或者说避免资源浪费。

定义:

  • 防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
  • 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效

一个经典的比喻:

想象每天上班大厦底下的电梯。把电梯完成一次运送,类比为一次函数的执行和响应

假设电梯有两种运行策略 debounce 和 throttle,超时设定为15秒,不考虑容量限制

电梯第一个人进来后,15秒后准时运送一次,这是节流。

电梯第一个人进来后,等待15秒。如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,这是防抖。

 代码实现:

防抖

function debounce(fn, delay){
 
      let timerId = null
 
      return function(){
          const context = this
          if(timerId){window.clearTimeout(timerId)}
 
          timerId = setTimeout(()=>{
              fn.apply(context, arguments)
              timerId = null
          },delay)
      }
  }

节流

function throttle(fn, delay){
 
      let canUse = true
 
      return function(){
         if(canUse){
              fn.apply(this, arguments)
              canUse = false
              setTimeout(()=>canUse = true, delay)
         }
     }
 }

 区别

相同点:

  • 都可以通过使用 setTimeout 实现
  • 目的都是,降低回调执行频率。节省计算资源


不同点:

  • 函数防抖,在一段连续操作结束后,处理回调,利用clearTimeout和 setTimeout实现。函数节流,在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能
  • 函数防抖关注一定时间连续触发的事件,只在最后执行一次,而函数节流一段时间内只执行一次

例如,都设置时间频率为500ms,在2秒时间内,频繁触发函数,节流,每隔 500ms 就执行一次。防抖,则不管调动多少次方法,在2s后,只会执行一次。

应用场景

防抖在连续的事件,只需触发一次回调的场景有:

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测
  • 窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。

节流在间隔一段时间执行一次回调的场景有:

  • 滚动加载,加载更多或滚到底部监听
  • 搜索框,搜索联想功能

2.深拷贝和浅拷贝

1.JS中数据类型分为

基本数据类型 (Number, String, Boolean, Null, Undefined, Symbol)
对象数据类型 ( Object )

2.存储区别

基本数据类型:直接将数据储存在栈内存中。
引用数据类型:其地址存在栈内存中,而真实数据存储在堆内存中。

 3.深浅拷贝的定义

浅拷贝:在栈内存中重新开辟一块内存空间,并将拷贝对象储存在栈内存中的数据存放到其中。
深拷贝:基于浅拷贝的过程如果栈内存里面存储的是一个地址,那么其在堆内存空间中的数据也会被重新拷贝一个并由栈空间新创建的地址指向。 

4.基本数据类型的拷贝

在对于基本类型的赋值操作都属于深拷贝如下面的例子:

let a = 10;
let b = a;
a = 20;
console.log(a); // 20
console.log(b); // 10 

 拷贝过程: 首先会在栈中开辟另一块空间,并将被拷贝对象的栈内存数据完全拷贝到该块空间中,这样两个变量其实指向的并不是同一个数据

5.引用类型的拷贝

当引用类型数据进行赋值拷贝时都属于浅拷贝如下面例子:

let a = [0, 1, 2, 3];
let b = a;
a[0] = 99
console.log(a); // [99,1,2,3]
console.log(b); // [99,1,2,3]

 6.实现深拷贝

es6展开运算符---一层

var a = [1, 2, [3, 4]]
var b = [...a];
a[2][1] = 88
b[1] = 99
console.log(a); // [1,2,[3,88]]
console.log(b); // [1,99,[3,88]]

 注意: 可见es6的展开运算符对于一维数据是深拷贝效果,但是对于多维数据任然是浅拷贝效果。

 JSON.parse(JSON.stringify(obj))---多层

let a = [1,2,[3,4,{name:'toy'}]]
let b = JSON.parse(JSON.stringify(a))
a[2][0] = 5
a[2][2].name = 'tom'
console.log(a)// [1,2,[5,4,{name:'tom'}]]
console.log(b)// [1,2,[3,4,{name:'toy'}]]

注意: 函数不会被拷贝

递归拷贝

function deepClone(oldData){
    if(typeof oldData === 'object' && oldData !==null){
        let res = Array.isArray(oldData) ? [] : {}
        for(let k in oldData){
            if(oldData.hasOwnProperty(k)){
                res[k] = deepClone(oldData[k])
            }
        }
        return res
    }else{
        return oldData
    }
}

3.闭包是什么?利弊?如何解决弊端?

定义:函数嵌套函数,其内部函数可以访问外部函数的变量,外部函数无法操作内部函数的变量的特性。我们把这个特性称作闭包。

好处:

  • 隔离作用域,保护私有变量;有了闭包才有局部变量,要不然都是全局变量了。
  • 让我们可以使用回调,操作其他函数内部;
  • 变量长期驻扎在内存中,不会被内存回收机制回收,即延长变量的生命周期;

弊端:内层函数引用外层函数变量,内层函数占用内存。如果不释放内存,过多时,易引起内存泄露。

解决办法

1.能不用闭包就不用
2.及时释放

无法自动销户,就及时手动回收,使用后将函数的引用赋null。

4.let const var 区别

5.双等和三等的区别

6.普通函数和箭头函数的区别

VUV

1.ref的作用是什么?

ref的作用是被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的$refs对象上。

常见使用场景: 

  • 使用ref获取页面DOM元素
  • 使用 ref获取子组件对象

 2.vue修饰符都有哪些 

修饰符主要分为表单修饰符和事件修饰符,表单修饰符主要指的是v-model修饰符,事件修饰符是v-on修饰符

v-model修饰符:

  • v-model.number 以parseFloat转成数字类型

  • v-model.trim 去除首尾空白字符

  • v-model.lazy 在change时触发而非inupt时

v-on修饰符:

  • @click.stop - 阻止事件冒泡
  • @click.prevent - 阻止默认行为
  • @click.once - 程序运行期间, 只触发一次事件处理函数
  • .@click.native 在组件内使用,如果组件没有事件,则native可以添加一个原生事件
  • @keyup.enter - 监测回车按键
  • @keyup.esc - 监测返回按键

 3.你的接口请求一般放在哪个生命周期中?为什么要这样做?

接口请求可以放在钩子函数created、beforeMount、mounted中进行调用,因为在这三个钩子函数中,data已经创建,可以将服务端端返回的数据进行赋值。

但是推荐在created钩子函数中调用异步请求,因为在created钩子函数中调用异步请求有以下优点:
能更快获取到服务端数据,减少页面loading时间
SSR不支持beforeMount、mounted钩子函数,所以放在created中有助于代码的一致性
created是在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。如果在mounted钩子函数中请求数据可能导致页面闪屏问题

4.data 中某一个属性的值发生改变后,视图会立即同步执行重新渲染吗?

不会立即同步执行重新渲染。Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化, Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。

  如果同一个watcher被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环tick中,Vue 刷新队列并执行实际(已去重的)工作。

5.new Vue()发生了什么?

6.Vue中的data为什么是 个函数?

  • 1.vue中组件是用来复用的,为了防止data复用,将其定义为函数。
  • 2.vue组件中的data数据都应该是相互隔离,互不影响的,组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响,就需要通过data函数返回一个对象作为组件的状态。
  • 3.当我们将组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,拥有自己的作用域,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
  • 4.当我们组件的date单纯的写成对象形式,这些实例用的是同一个构造函数,由于JavaScript的特性所导致,所有的组件实例共用了一个data,就会造成一个变了全都会变的结果。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值