• 前端小组考核题


    一、JS部分:

     1、深、浅拷贝的区别?你知道哪些实现深拷贝的方法?

    概念:

    浅拷贝 :只复制指向某个对象的指针,而不复制对象本身,相当于是新建了一个对象,该对象复制了原对象的指针,新旧对象还是共用一个内存块

    深拷贝:是新建一个一模一样的对象,该对象与原对象不共享内存,修改新对象也不会影响原对象

    两者的区别:假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着改变了,说明这是浅拷贝,如果B没改变,那就是深拷贝

    实现深拷贝的方法:

    (1)利用递归实现

    递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。

    1. var obj = { //原数据,包含字符串、对象、函数、数组等不同的类型
    2. name:"test",
    3. main:{
    4. a:1,
    5. b:2
    6. },
    7. fn:function(){
    8. },
    9. friends:[1,2,3,[22,33]]
    10. }
    11. function copy(obj){
    12. let newobj = null; //声明一个变量用来储存拷贝之后的内容
    13. //判断数据类型是否是复杂类型,如果是则调用自己,再次循环,如果不是,直接赋值即可,
    14. //由于null不可以循环但类型又是object,所以这个需要对null进行判断
    15. if(typeof(obj) == 'object' && obj !== null){
    16. //声明一个变量用以储存拷贝出来的值,根据参数的具体数据类型声明不同的类型来储存
    17. newobj = obj instanceof Array? [] : {};
    18. //循环obj 中的每一项,如果里面还有复杂数据类型,则直接利用递归再次调用copy函数
    19. for(var i in obj){
    20. newobj[i] = copy(obj[i])
    21. }
    22. }else{
    23. newobj = obj
    24. }
    25. console.log('77',newobj)
    26. return newobj; //函数必须有返回值,否则结构为undefined
    27. }
    28. var obj2 = copy(obj)
    29. obj2.name = '修改成功'
    30. obj2.main.a = 100
    31. console.log(obj)
    32. console.log(obj2)

    (2)json中的parse和stringify 

    实现深拷贝:原理就是用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,

    缺点:当对象里面有函数的话,深拷贝后,函数会消失。

    1. var arr = ['jack',25,{hobby:'tennise'}];
    2. let arr1 = JSON.parse(JSON.stringify(arr))
    3. arr1[2].hobby='rose'
    4. arr1[0]='rose'
    5. console.log( arr[2].hobby) //tennise
    6. console.log( arr[0]) //jack

    (3)Jquery的$.extend: 

    1. var defaults = {name:'张三',age:18,sex:"true",scores:{chinese:70,science:100}};
    2. var options = {name:'李四',age:20,scores:{chinese:98,math:99,english:100}}
    3. var settings = $.extend(true,defaults,options);
    4. console.log(defaults);
    5. console.log(options);
    6. console.log(settings);

    2、如何判断一个函数是否作为了构造函数?

         使用instanceof 判断:

        

    3、new操作符都做了哪些事情?

    new主要做了以下工作:

    1. 先创建了一个新的对象newObj
    2. 将新对象newObj与构造函数通过原型链进行连接
    3. 将构造函数的this绑定到新对象newObj
    4. 根据构建函数返回类型作判断,如果是值类型,返回newObj。如果是引用类型,就返回这个引用类型的对象

     4、什么是类数组?列举你知道的类数组转为数组的方法。

    类数组是一个对象,属性名使用数字,并且带有length属性。

    1. let objArr = {
    2. 0:"name",
    3. 1:"age",
    4. 2:"color"
    5. length:3
    6. };

    类数组转换为数组的方法:

    1、slice函数

    let arr1 = Array.prototype.slice.call(objArr);

    2、扩展运算符 只能把有iterator接口的类数组转为数组;

    1. let Str = 'hello';
    2. let arr = [...Str];
    3. console.log(arr);

    3、Array.form(); es6新增的方法

    let arrr = Array.from(objArr);

    5、如图,连续多次bind()的结果是什么?

     3 3   在js中,多次bind()只有第一次绑定会生效。

    6、说说什么是防抖和节流?尝试自定义防抖函数debounce和节流函数throttle?

    函数防抖:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

    1. function debounce(fn, delay) {
    2. var timer = null;
    3. return function() {
    4. if (timer) clearTimeout(timer);
    5. // 获取this和argument
    6. var _this = this;
    7. var _arguments = arguments;
    8. timer = setTimeout(function() {
    9. // 在执行时,通过apply来使用_this和_arguments
    10. fn.apply(_this, _arguments);
    11. }, delay);
    12. }
    13. }

    函数节流(throttle):指定时间间隔内只会执行一次任务。

    1. function throttle(fn, interval) {
    2. var last = 0;
    3. var timer = null; // 记录定时器是否已经开启
    4. return function () {
    5. // this和arguments;
    6. var _this = this;
    7. var _arguments = _arguments;
    8. var now = new Date().getTime();
    9. if (now - last > interval) {
    10. if (timer) { //若已经开启,则不需要开启另外一个定时器了
    11. clearTimeout(timer);
    12. timer = null;
    13. }
    14. fn.apply(_this, _arguments);
    15. last = now;
    16. } else if (timer === null) { // 没有立即执行的情况下,就会开启定时器
    17. //只是最后一次开启
    18. timer = setTimeout(function () {
    19. timer = null; // 如果定时器最后执行了,那么timer需要赋值为null
    20. fn.apply(_this, _arguments);
    21. },interval)
    22. }
    23. }
    24. }

     7、写出 ['10', '10', '10', '10', '10'].map(parseInt) 的结果

    结果:[ 10,NaN,2,3,4 ]

    parseInt的用法

    8、ES6箭头函数和普通函数有哪些区别?

    1.箭头函数没有phototype,所以箭头函数本身没有this

    2.箭头函数的this在定义时指向外层第一个普通函数,如果外层没有普通函数,则指向window

    3.箭头函数本身的this指向不能改变,但可以修改它要继承的对象this

    4.箭头函数this指向全局,不能调用arguments

    5.箭头函数this指向普通函数时,使用arguments继承于该普通函数

    6.使用new调用箭头函数会报错,因此箭头函数没有constructor

    7.箭头函数不支持new.target

    8.箭头函数不支持重命名函数参数,普通函数参数支持

    9、如何使用js计算一个html页面中有多少种标签?

    10、 写出下面代码的输出结果:

    (1)提示: 变量提升

    答案:undefined 10

    (2)提示:函数提升

    答案:

    11、 map方法和forEach的不同之处?

    forEach() 方法不会返回执行结果,而是undefined。

    也就是说,forEach()会修改原来的数组。而map()方法会得到一个新的数组并返回。

    二、Vue2部分 

    1、v-show和v-if的主要区别 ?

    v-show指令:元素始终被渲染到HTML,它只是简单的伪元素设置css的style属性,当不满足条件的元素被设置style=“display:none”的样,是通过修改元素的的CSS属性(display)来决定实现显示还是隐藏
    v-if指令:满足条件是会渲染到html中,不满足条件时是不会渲染到html中的,是通过操纵dom元素来进行切换显示

    2、vue2中的data是什么类型?解释为什么这样设计。

    data是一个函数类型,因为需要重复利用,所以需要相互独立。

    3、vue-router传参的方式有哪些?

    (1)、router-link路由导航方式传参

    (2)、调用$router.push实现路由传参

    (3)、通过路由属性name匹配路由,再根据params传递参数

    (4)、通过query来传递参数

    4、你知道哪些vue-router的钩子函数,说说他们都是什么时候触发的?

    首先做的的事情就是实例化vue对象,也就是创建一个vue实例,紧接着 初始化事件以及生命周期;
    触发 beforCreate,是创建实例之前执行的钩子事件,此事件执行完成后进行初始化注入;
    触发created,是创建实例之后执行的钩子事件 ;
    然后Vue会判断,是否含有"el"选项,如果没有,则使用vm.$mount()挂载模板;如果有,就判断是否含有template,然后进行编译模板的工作,将data对象里面的数据和使用vue语法声明的模板编译成浏览器可读的html;
    触发 beforMount,是将编译好的HTML挂载到对应的虚拟dom上时执行的钩子事件,此时页面并没有内容;
    然后将编译好的HTML替换掉el属性所指向的dom;
    此时触发mounted,是将编译好的HTML挂载完成后执行的钩子,这个钩子函数中一般进行一些ajax的请求获取数据进行数据的初始化,注意:mounted在整个实例中只执行一次
    此时,实例已经将编译后的HTML挂载完成,开始实时监控数据的变化,并随之更新dom
    beforeUpdate,是更新之前执行的钩子;updated是更新完成后执行的钩子;
    接下来,vue实例开始执行销毁工作,拆除数据监听,子组件和事件监听;
    此时触发beforeDestroy,是实例销毁工作完成前执行的钩子;
    等待实例销毁工作完成后,触发destroyed,是销毁工作完成后执行的钩子。

     5、vue组件之间的通信方式有哪些?

    父组件→子组件:利用props属性
    子组件→父组件:利用自定义事件,使用$emit()发送事件和要传递的数据
    父组件 访问 子组件:利用 $children或者$refs属性进行访问,注意$refs默认是一个空对象,需要在子组件上绑定res属性,来告诉父组件要访问的是哪个子组件
    子组件 访问 父组件 : 利用$parent,也可以使用$root直接访问根组件

    6、简述vue生命周期

    vue每个组件都是独立的,每个组件都有一个属于它的生命周期,从一个组件创建、数据初始化、挂载、更新、销毁,这就是一个组件所谓的生命周期。

    7、什么是SPA?说说SPA和MPA的优缺点

    SPA(SinglePage Application)单页面应用,顾名思义,就是只有一个主页面,一开始只需要加载一次js,css等资源,对各个功能模块进行组件化,所以单页面应用的跳转,就是切换组件,只局部刷新,适合移动应用开发;仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载
    MPA(MutiPage Application)多页面应用,是有多个独立页面的应用。每个页面必须重复加载相关资源,跳转页面会整体刷新。
    SPA优点: 页面切换快
    缺点: 首屏时间稍慢,SEO差
    MPA优点: 首屏时间快,SEO效果好
    缺点: 页面切换慢

    8、简述Vue2响应式原理。

    当把一个普通的JavaScript对象传入Vue实例作为data选项,Vue会遍历此对象所有的property,并使用Object.defineProperty把这些property转为setter/getter,这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。
    其次,每个Vue实例都对应着一个watcher实例,他会在组件渲染的时候把接触过的数据property记录为依赖。之后如果依赖项的setter触发,会通知watcher重新渲染响应的组件。

     三、算法部分:(不使用第三方库)

    1、使用js实现一个方法,对数组进行去重,尽可能多的写出不同的方式

    一、利用ES6 Set去重(ES6中最常用)

    1. function unique (arr) {
    2. return Array.from(new Set(arr))
    3. }
    4. var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
    5. console.log(unique(arr))
    6.  //[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]

    不考虑兼容性,这种去重的方法代码最少。这种方法还无法去掉“{}”空对象,后面的高阶方法会添加去掉重复“{}”的方法。

    二、利用for嵌套for,然后splice去重(ES5中最常用)

    1. function unique(arr){
    2. for(var i=0; ilength; i++){
    3. for(var j=i+1; jlength; j++){
    4. if(arr[i]==arr[j]){ //第一个等同于第二个,splice方法删除第二个
    5. arr.splice(j,1);
    6. j--;
    7. }
    8. }
    9. }
    10. return arr;
    11. }
    12. var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
    13. console.log(unique(arr))
    14. //[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}] //NaN和{}没有去重,两个null直接消失了

    双层循环,外层循环元素,内层循环时比较值。值相同时,则删去这个值。

    2、用js实现一个方法:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次,找出那个只出现一次元素。

    1. var singleNumber =function(nums){
    2. //声明一个空对象用于记录
    3. var obj={};
    4. for(var i=0;ilength;i++){
    5. //此时读取对象的属性需要用[]
    6. if(!obj[nums[i]]){
    7. obj[nums[i]] =1;
    8. }
    9. else{
    10. obj[nums[i]]+=1;
    11. }
    12. //取出属性值为1的
    13. for(var j in obj){
    14. if(obj[j] ==1)
    15. return j;
    16. }
    17. }
  • 相关阅读:
    Docker搭建Redis集群
    Centos7构建LNMP平台
    SpringBoot的starter到底是什么?
    前端开发:$nextTick()的使用及原理
    云计算 - 以阿里云为例,企业上云策略全览与最佳实践
    【security】spring security放行不生效,security放行后还是被拦截,路径变成了error
    lintcode 581 · 最长重复子序列【中等 vip 动态规划 /递归】
    OCPP1.6协议
    Paillier算法简介
    Java Netty - Buffer类
  • 原文地址:https://blog.csdn.net/weixin_61466362/article/details/127077424