前端面试锦囊2

笔试篇

1.使用CSS实现一个三角形

/* 把上、左、右三条边隐藏掉(颜色设为 transparent) */
#demo {
  width: 0;
  height: 0;
  border-width: 20px;
  border-style: solid;
  border-color: transparent transparent red transparent;}

2.使用CSS实现一个轮播图

<div class="slide">
  <ul class="slide-auto">
    <li>one</li>
    <li>two</li>
    <li>three</li>
  </ul>
</div>
.slide {
    position: relative;
    margin: auto;
    width: 600px;
    height: 200px;
    text-align: center;
    font-family: Arial;
    color: #FFF;
    overflow: hidden;
}

.slide ul {
    margin: 10px 0;
    padding: 0;
    width: 9999px;
    transition: all 0.5s;
}

/*//自动播放*/
.slide .slide-auto {
    animation: marginLeft 10.5s infinite;
}

.slide li {
    float: left;
    width: 600px;
    height: 200px;
    list-style: none;
    line-height: 200px;
    font-size: 36px;
}

.slide li:nth-child(1) {
    background: #9fa8ef;
}

.slide li:nth-child(2) {
    background: #ef9fb1;
}

.slide li:nth-child(3) {
    background: #9fefc3;
}

@keyframes marginLeft {
    0% {
        margin-left: 0;
    }

    28.5% {
        margin-left: 0;
    }

    33.3% {
        margin-left: -600px;
    }

    62% {
        margin-left: -600px;
    }

    66.7% {
        margin-left: -1200px;
    }

    95.2% {
        margin-left: -1200px;
    }

    100% {
        margin-left: 0;
    }
}

3.请实现一个深拷贝。

//调用深拷贝方法,若属性为值类型,则直接返回;若属性为引用类型,则递归遍历。这就是我们在解这一类题时的核心的方法。
function deepClone(obj) {
    // 如果是 值类型 或 null,则直接return
    if(typeof obj !== 'object' || obj === null) {
        return obj
    }
    
    // 定义结果对象
    let copy = {}
    
    // 如果对象是数组,则定义结果数组
    if(obj.constructor === Array) {
        copy = []
    }
    
    // 遍历对象的key
    for(let key in obj) {
        // 如果key是对象的自有属性
        if(obj.hasOwnProperty(key)) {
            // 递归调用深拷贝方法
            copy[key] = deepClone(obj[key])
        }
    }
    
    return copy
} 

4.请实现一个防抖和节流。

防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行

防抖原理:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时
适用场景:
按钮提交场景:防止多次提交按钮,只执行最后提交的一次 服务端验证场景:表单验证需要服务端配合,只执行一段连续的输入事件的最后一次,还有搜索联想词功能类似

// func是用户传入需要防抖的函数
// wait是等待时间
const debounce = (func, wait = 50) => {
  // 缓存一个定时器id
  let timer = 0
  // 这里返回的函数是每次用户实际调用的防抖函数
  // 如果已经设定过定时器了就清空上一次的定时器
  // 开始一个新的定时器,延迟执行用户传入的方法
  return function(...args) {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      func.apply(this, args)
    }, wait)
  }
}

节流原理:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效
适用场景:
拖拽场景:固定时间内只执行一次,防止超高频次触发位置变动
缩放场景:监控浏览器resize
动画场景:避免短时间内多次触发动画引起性能问题

// func是用户传入需要防抖的函数
// wait是等待时间
const throttle = (func, wait = 50) => {
  // 上一次执行该函数的时间
  let lastTime = 0
  return function(...args) {
    // 当前时间
    let now = +new Date()
    // 将当前时间和上一次执行函数时间对比
    // 如果差值大于设置的等待时间就执行函数
    if (now - lastTime > wait) {
      lastTime = now
      func.apply(this, args)
    }
  }
}

setInterval(
  throttle(() => {
    console.log(1)
  }, 500),
  1
)

5.找出数组中重复的值

//1.定义一个新数组,遍历源数组,值不在新数组就push进该新数组中:
function unique(array){
    var temp = []; //一个新的临时数组
    for(var i = 0; i < array.length; i++){
        if(temp.indexOf(array[i]) == -1){
            temp.push(array[i]);
        }
    }
    return temp;
}
var arr = [1,'aaa',2,4,5,2,'aaa',5,6,5];
console.log(unique(arr));  // [1, "aaa", 2, 4, 5, 6]
//set和map
var arr = [1,2,1,'aaa',2,'aaa','2'];
var newArr = [...new Set(arr)];
//或者  var newArr = Array.from(new Set(arr))
console.log(newArr)      //[1, 2, "aaa", "2"]

6.请对数组进行排序

sort() 函数用于对数组单元从低到高进行排序。
rsort() 函数用于对数组单元从高到低进行排序。
asort() 函数用于对数组单元从低到高进行排序并保持索引关系。
arsort() 函数用于对数组单元从高到低进行排序并保持索引关系。
ksort() 函数用于对数组单元按照键名从低到高进行排序。
krsort() 函数用于对数组单元按照键名从高到低进行排序。

7.实现数组去重和对象数组去重。

数组去重实现的基本原理如下:

① 初始化一个空数组
② 将需要去重处理的数组中的第1项在初始化数组中查找,如果找不到(空数组中肯定找不到),就将该项添加到初始化数组中
③ 将需要去重处理的数组中的第2项在初始化数组中查找,如果找不到,就将该项继续添加到初始化数组中
④ ……
⑤ 将需要去重处理的数组中的第n项在初始化数组中查找,如果找不到,就将该项继续添加到初始化数组中
⑥ 将这个初始化数组返回

双层for循环

function distinct(arr) {
    for (let i=0, len=arr.length; i<len; i++) {
        for (let j=i+1; j<len; j++) {
            if (arr[i] == arr[j]) {
                arr.splice(j, 1);
                // splice 会改变数组长度,所以要将数组长度 len 和下标 j 减一
                len--;
                j--;
            }
        }
    }
    return arr;
}

Array.filter() 加 indexOf/includes

//利用indexOf检测元素在数组中第一次出现的位置是否和元素现在的位置相等,如果不等则说明该元素是重复元素
function distinct(a, b) {
    let arr = a.concat(b);
    return arr.filter((item, index)=> {
        //return arr.indexOf(item) === index
        return arr.includes(item)
    })
}

ES6 中的 Set 去重

function distinct(array) {
   return Array.from(new Set(array));
}

reduce实现对象数组去重

var newArr = arr.reduce(function (prev, cur) {
    prev.indexOf(cur) === -1 && prev.push(cur);
    return prev;
},[]);

对象数组去重

const responseList = [
  { id: 1, a: 1 },
  { id: 2, a: 2 },
  { id: 3, a: 3 },
  { id: 1, a: 4 },
];
const result = responseList.reduce((acc, cur) => {
    const ids = acc.map(item => item.id);
    return ids.includes(cur.id) ? acc : [...acc, cur];
}, []);
console.log(result); // -> [ { id: 1, a: 1}, {id: 2, a: 2}, {id: 3, a: 3} ]

8.手动实现JSONP跨域

1.创建script标签
2.设置script标签的src属性,以问号传递参数,设置好回调函数callback名称
3.插入到html文本中
4.调用回调函数,res参数就是获取的数据

function jsonp(url, jsonpCallback, success) {
  const script = document.createElement('script')
  script.src = url
  script.async = true
  script.type = 'text/javascript'
  window[jsonpCallback] = function(data) {
    success && success(data)
  }
  document.body.appendChild(script)
}

5.设置 CORS: Access-Control-Allow-Origin:*
postMessage

9.请将’mian shi’输出为:‘ihs naim’

function reverseString(str) {
  return str.split("").reverse().join("");
}
 
reverseString("mian shi");
console.log(reverseString("mian shi"));
//递归
function reverseString(str) {
	if (str === "")
		return "";
	else
		return reverseString(str.substr(1)) + str.charAt(0);
}
 
console.log(reverseString('mian shi'))

Vue篇

10.Vue和React区别,详解?

1、React严格上只针对MVC的view层,Vue则是完全的MVVM模式。
2、虚拟 DOM不一样 vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树.而React,每当应用的状态被改变时,全部组件都会重新渲染。
3、组件写法不一样 React推荐的做法是 JSX + inline style, 也就是把HTML和CSS全都写进JavaScript了,即’all in js’; Vue推荐的做法是webpack+vue-loader的单文件组件格式,即html,css,jd写在同一个文件;
4、state对象在react应用中不可变的,需要使用setState方法更新状态;在vue中,state对象不是必须的,数据由data属性在vue对象中管理
5、vue是双向数据绑定,react是单项数据绑定
看法 :
当工程规模比较大时双向数据绑定会很难维护,vue适合不会持续的小型的web应用,使用vue.js能带来短期内较高的开发效率. 否则采用react。

11.vue中v-if和v-show有什么区别?

v-if按照条件是否渲染,可以在必要的时候才去渲染组件,减少整个页面的初始渲染开销。
v-show是display的block或none,在初始渲染时有更高的开销,但是切换开销很小,更适合于频繁切换的场景。

12.$nextTick是什么?

nextTick 可以让我们在下次 DOM 更新循环结束之后执行延迟回调,用于获得更新后的 DOM

13.v-for key的作用是什么?

key的作用主要是为了高效的更新虚拟DOM;
当Vue用 v-for 正在更新已渲染过的元素列表是,它默认用“就地复用”策略

14.常用的事件修饰符?

stop:阻止事件的冒泡
prevent:阻止事件的默认行为
once:只触发一次
self:只触发自己的事件行为时,才会执行

15.Vue全家桶指的是什么?

Vue+Vue-router+Vuex+axios

16.v-if和v-for的优先级?

当v-if和v-for一起使用时,优先使用v-for

17.组件通信方式?

父子组件通信
父组件通过 props 传递数据给子组件,子组件通过 emit 发送事件传递数据给父组件,这两种方式是最常用的父子通信实现办法

<!--父组件中-->
<input :value.sync="value" />
<!--以上写法等同于-->
<input :value="value" @update:value="v => value = v"></comp>
<!--子组件中-->
<script>
  this.$emit('update:value', 1)
</script>

兄弟组件通信
对于这种情况可以通过查找父组件中的子组件实现,也就是 this. p a r e n t . parent. parent.children,在 $children 中可以通过组件 name 查询到需要的组件实例,然后进行通信。
跨多层级组件通信

//假设有父组件 A,然后有一个跨多层级的子组件 B
// 父组件 A
export default {
  provide: {
    data: 1
  }
}
// 子组件 B
export default {
  inject: ['data'],
  mounted() {
    // 无论跨几层都能获得父组件的 data 属性
    console.log(this.data) // => 1
  }
}

18.vue-loader是什么?使用它的用途有哪些?

Vue Loader 是一个 webpack 的 loader,它允许你以一种名为单文件组件 (SFCs)的格式撰写 Vue 组件
用途:解析和转换 .vue 文件,提取出其中的逻辑代码 script、样式代码 style、以及 HTML 模版 template,再分别把它们交给对应的 Loader 去处理

19.Vue的双向数据绑定原理是什么?

vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变

20.vuex中有几个核心属性,分别是什么?他们的特点?

五个核心属性:state, getters, mutations, actions, modules
state => 基本数据
getters => 从基本数据派生的数据
mutations => 提交更改数据的方法,同步!
actions => 像一个装饰器,包裹mutations,使之可以异步。
modules => 模块化Vuex
详情可参考vuex的官方文档

https://vuex.vuejs.org/zh/guide/

21.mixins的理解及应用?

vue中提供了一种混合机制–mixins,来分发 Vue组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项

mixins 选项合并
当组件和混入对象含有同名data属性选项时,这些选项将以恰当的方式进行“合并”。比如,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。
同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。
值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对,混入对象的方法会被覆盖。
mixins在引入组件之后,则是将组件内部的内容如data等方法、method等属性与父组件相应内容进行合并。相当于在引入后,父组件的各种属性方法都被扩充了

22.请详细说下你对vue生命周期的理解以及使用场景?

Vue中实例从创建到销毁的过程就是生命周期,即指从创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程

Vue生命周期总共可以分为8个阶段:创建前后, 载入前后,更新前后,销毁前销毁后

生命周期描述
beforeCreate执行时组件实例还未创建,通常用于插件开发中执行一些初始化任务
created组件初始化完毕,各种数据可以使用,常用于异步数据获取
beforeMount未执行渲染、更新,dom未创建
mounted初始化结束,dom已创建,可用于获取访问数据和dom元素
beforeUpdate更新前,可用于获取更新前各种状态
updated更新后,所有状态已是最新
beforeDestroy销毁前,可用于一些定时器或订阅的取消
destroyed组件已销毁,作用同上

23.第一次加载会触发哪些生命周期?

beforeCreate, created, beforeMount, mounted

24.Vue中过滤器?

过滤器分为:全局过滤器和局部过滤器
全局过滤器的使用:在src下新建一个文件夹,存放自定义的过滤器,之后在入口文件的mian.js中import引入使用即可

1、 当有局部和全局两个名称相同的过滤器时候,会以就近原则进行调用,即:局部过滤器优先于全局过滤器被调用!
2、 一个表达式可以使用多个过滤器。过滤器之间需要用管道符“|”隔开。其执行顺序从左往右

25.你是怎么封装一个组件的?

想要封装好一个组件,必须要熟练掌握的三个技能:1.父组件传值到子组件(props) 2.子组件传值到父组件( e m i t ) 3. 插 槽 使 用 ( s l o t ) 。 对 于 一 个 独 立 的 组 件 , p r o p s 是 用 来 为 组 件 内 部 注 入 核 心 内 容 ; emit)3.插槽使用(slot)。对于一个独立的组件,props是用来为组件内部注入核心内容; emit3.使slotpropsemit用来使这个组件通过一些操作来融入其它组件中
首先在components文件夹下创建一个你要封装的组件文件夹,新建一个index.vue,写入组件代码,然后在components下还有一个index.js文件,咱们要在index.js中注册上自己定义的组件
其次如果全局引用就在main.js文件中引入它,局部调用就在需要的页面引入

26.watch发生再哪个生命周期?

mounted

27.谈谈你对 keep-alive 的了解?

keep-alive 可以实现组件的缓存,当组件切换时不会对当前组件进行卸载。常用的2个属性include/exclude ,2个生命周期activated ,deactivated

28.computed 和 watch 的区别和运用的场景?

computed:计算属性,依赖其他属性值,并且computed的值有缓存,只有他依赖的属性值发生改变,下一次获取computed的值时才会从新计算computed的值
watch:更多的是一个观察的作用,类似于某些数据的监听回调,每当监听的数据发生变化时都会执行回调进行后的操作
运用场景:
computed:当我们需要进行数值计算,并依赖其他数据时,应该使用computed,利用其缓存特性,避免每次获值时,都要重新计算
watch:当需要在数据变化时执行异步或开销较大的操作是,应该使用watch,它允许我们执行异步操作,限制我们执行该操作的频率

29.Vuex的严格模式是什么,有什么作用,怎么开启?

在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。也就说想要改变状态,必须要使用mutation函数
用户实例化Store的时候传入strict为true就开启了严格模式

30.proxy与Object.defineProperty的优劣势对比?

Proxy 的优势如下:

Proxy代理整个对象,Object.defineProperty只代理对象上的某个属性;
数组新增删除修改时,Proxy可以监听到;
Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
如果对象内部要全部递归代理,则Proxy可以只在调用时递归,而Object.defineProperty需要在一开始就全部递归,Proxy性能优于Object.defineProperty;
对象上定义新属性时,Proxy可以监听到;

Object.defineProperty 的优势如下:

兼容性好,支持 IE9及以上,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue 的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。

31.Vue3的新特性

重写了虚拟dom的实现,运行时编译,update性能提高,ssr速度提高
核心api支持tree-shaking,能够按需打包
Composition API使用纯函数分隔复用代码
新增三个组件:Fragment、Teleport、Suspense
Custom Renderer API

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值