zoukankan      html  css  js  c++  java
  • 最终题目准备

    1,vue的列表组件为什么要加key?

      增加diff算法的同级比较效率,  key是唯一索引,可以一目了然的看到同一级的是否变化,如果没有key, 那就只能一个个的去进行比较了。

    2, ['1', '2', '3'].map(parseInt)结果是多少?        [1, NaN, NaN];

      map函数的默认参数为 item,index和arr,  parseInt的参数为 字符串 和 进制数。   所以转换为求  parseInt('1', 0) parseInt('2', 1) parseInt('3', 2)的值。

      关于求进制数: parseInt(str, radix)

        radix的范围是在 2和36之间, 当进制数为0的时候,默认为10进制。  str的值从第一个开始不能大于对应的进制数。如果第一个数大于对应的进制数,则返回NaN。 如果第一个数一旦小于进制数,就开始做运算,直到碰到大于进制数的就停下来。

        exp:  parseInt('43256789', 5);    4*5*5 + 3* 5 + 2 = 117

    3,节流和防抖, 有什么区别, 怎么实现?

      节流:  限制一段时间内函数只执行一次。

      防抖:  函数一段事件执行一次, 如果在这段时间内被触发,则重新计算时间。

      参考 : https://www.cnblogs.com/wjyz/p/10225193.html

    4, 介绍下 Set  Map  WeakSet   WeakMap的区别

      set 对应的是数组,  类似数组, 允许存储任何类型的值,但没有重复的成员。set内部的比较是用全等。 size是数量, 方法有keys, values, entries和forEach。

      weakset:  只能储存对象引用。 由于是弱引用, 只要没被其他的变量或者属性引用,就会被回收。 所以无法被遍历,无法拿到所有的元素,也没有size属性。

      Map: 对应的是obj对象。 是以key,value的形式存储的。  key可以为任意数据结构, 而对象的key只能为字符串。

      weakmap: 键值对的集合,只接受对象作为键名。弱引用,不能遍历。

    5,深拷贝

         function isObject(obj) {
            return typeof obj === 'object' && obj !== null;
        }
    
        function deepClone(target, hash = new WeakMap()) {
            if (!isObject(target)) return target;
            if (hash.has(target)) return hash.get(target);
    
            let clone = Array.isArray(target) ? []: {};
            hash.set(target, clone);
    
            for (let key in target) {
                if (Object.prototype.hasOwnProperty.call(target, key)) {
                    if (isObject(target[key])) {
                        clone[key] = deepClone(target[key], hash);
                    } else {
                        clone[key] = target[key];
                    }
                }
            }
    
            return clone;
        }
    View Code

    6,setTimeout, promise   ,  async  await  有什么区别

      setTimeout :  定时器的回调函数是 属于 宏任务, 当前执行栈清空后执行。

      promise:  promise的then函数是微任务, 放在微任务队列, 当前同步任务执行完之后就立马执行微任务队列。

      async / await: async函数返回promise, 正常情况下await后面也是promise,如果不是promise,则会被变为promise,并且立即resolve。

    7, async / await 使如何通过同步写法的方式来实现异步的。

      async/await是 generator的语法糖,   在遇到异步的操作时, 会暂停该函数, 交出执行权, 当该异步完成后, 再继续执行。

    8, var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];    扁平化数组并且去重 按顺序排列

    [...new Set(arr.flat(Infinity))].sort((a,b) => a-b);

    9,js异步解决方案的发展历程 以及优缺点

      1,callback:  回调地狱, 强耦合,不能用try catch捕获错误。不能return

      2, promise: 解决回调地狱, 采用链式调用。 不过语义很不清楚,一眼看去都是then的堆积。无法取消promise

      3,generator:可以控制函数的执行, 也可以进行函数内外的数据交换和错误的处理。

      4,async: 代码简洁,符合语义。因为有自动执行器,所以代码量少。

    10, 如何实现一个new

    function _new(fn, ...args) {
        let obj = Object.create(fn.prototype);
        let result = fn.apply(obj, args);
        return Object.prototype.toString.call(result) === '[object Object]' ? result : obj;
    }

    11, 简单讲解一下http2的多路复用

      多路复用代替了http1的序列和阻塞机制,所有相同域名的请求都通过一个tcp连接并发完成。 http1并发多个请求需要多个tcp连接,浏览器一般会限制为6个。 http2的多路复用会消除因多个tcp连接带来的延时和内存消耗,而且单个连接上可以进行并行交错的请求和响应,互相不干扰。

    12,tcp的三次握手和四次挥手

      三次握手: 客户端发送一个带SYN标志的数据包给服务器,服务器收到后返回一个带有SYN/ACK标志的数据包表示确认,客户端再回传一个带ACK标志的数据包表示握手结束。

      四次挥手: 客户端进程发出连续释放报文,并停止发送数据。 服务器收到连续释放报文,发出确认报文。 服务器将最后的数据发送完毕,向客户端发送连续释放报文。 客户端收到后,发出确认。 服务器收到客户端的确认, 进入closed状态。

    13, cookie和token都放在header中, 为什么不劫持token呢

      token是为了防止csrf跨站请求攻击的。  浏览器在发送http时会自动带上cookie, 但是不会自动带上token。

    14,  var a = ? ,  if (a == 1 && a == 2 && a== 3) { console.log(1)}    a在什么情况下 会打印1;

      因为用 == 号比较的时候,会进行隐式转换, 对于对象来说,隐式转换会调用自身的toString或者valueof方法。

    var a = {
        n: 1,
        toString() {
            return this.n++
        }
    }
    a==1 && a==2 && a==3 ; true
    toString 改为valueof也可以

    如果a为数组 有一种方法更简单
    var a = [1,2,3];
    a.toString = a.shift;
    a == 1 && a==2 && a==3 ; true

     15,bfc及其应用

      bfc为块级格式化上下文,bfc内部的元素无论怎样都不会影响外部元素。

      触发条件: html元素, display为inline-block table-cell和table-caption,position不为relative或static  overflow为 auto scroll或hidden   float的值不为none

      基本用途: 去除margin重叠, 清除浮动 , 流体布局。

    16,在vue中,为何子组件不能修改父组件传递的prop,如果修改了,vue是如何监控到属性的修改并给出警告的?

      如果传递的prop为引用类型,子组件修改的话不会报错,如果是基本类型,子组件修改的时候会失败,并且vue会给出警告。

      因为在修改prop的时候,触发set会判断是否在根组件或者是更新子组件。 如果不是那就说明更新的是props, 会给出警告。

    17,双向绑定和vuex是否冲突

      在严格模式下,的确冲突, 因为在数值改变时,v-model会直接修改属性值,但是这个修改不是在mutaition中操作的,所以会报错。 解决方法:

        1,在input中绑定vuex的state, 监听input或change事件,在回调中操作mutation

        2,使用带有setter的双向绑定计算属性。

    18,为什么通常在发送数据埋点请求的时候使用的是1×1像素的透明gif图片

      此方法主要应用于只需向服务器发送数据,无需服务器回复。

        避免跨域, 不会阻塞页面, gif在所有格式中体积最小。

    19,vue的响应式原理 Object.defineProperty有什么缺陷, 为什么vue3改用了proxy?

      Object.defineProperty无法监控到数组下标的变化,所以vue内部重写了数组的一些操作方法,但也只是针对了这几种方法做了hack,通过下标操作数据的话,vue就监听不到。

      Object.defineProperty只能劫持对象的属性,因此需要对对象的每个属性进行遍历来进行数据的监听,如果属性也是对象,还需要进行深度遍历。

      es6的proxy有以下两个优点: 1,可以劫持整个对象,提高性能, 那么当然数组新加的属性就可以监听到了。

    20,div垂直水平居中

      参考  https://www.cnblogs.com/wjyz/p/11389519.html

    21,如何实现冒泡排序,时间复杂度是多少, 如何改进

        function bubble(arr) {
           const len = arr.length - 1;
           for (let i = 0; i < len; i++) {
               let isOk = true;
               for (let j = 0; j < len - i; j++) {
                   if (arr[j] > arr[j+1]) {
                       [arr[j], arr[j+1]] = [arr[j+1], arr[j]];
                       isOk = false;
                   }
               }
               if (isOk) break;
           }
           return arr;
       }
    View Code

    22, 某公司1到12月份的销售额存在一个对象中 {1:222, 2:123, 5:888},请把数据处理为如下结构:[222, 123, null, null, 888, null, null, null, null, null, null, null]。

    Array.from({length: 12}).map((_,index) => obj[index + 1] || null);

    23,要求设计LazyMan类, 满足以下的功能

    LazyMan('Tony');
    // Hi I am Tony
    
    LazyMan('Tony').sleep(10).eat('lunch');
    // Hi I am Tony
    // 等待了10秒...
    // I am eating lunch
    
    LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
    // Hi I am Tony
    // I am eating lunch
    // 等待了10秒...
    // I am eating diner
    
    LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
    // Hi I am Tony
    // 等待了5秒...
    // I am eating lunch
    // I am eating dinner
    // 等待了10秒...
    // I am eating junk food
    View Code
          class LazyClass {
                constructor(name) {
                    this.eventQueen = [];
                    this.name = name;
                    this.init();
                }
                init() {
                    console.log('Hi I am ' + this.name);
                    setTimeout(() => {
                        this.next();
                    });
                    return this;
                }
                eat(things) {
                    let that = this;
                    this.eventQueen.push(function () {
                        console.log('I am eating '+ things);
                        that.next();
                    });
                    return this;
                }
                sleep(time) {
                    let that = this;
                    this.eventQueen.push(function () {
                        setTimeout(() => {
                            console.log('等待了' + time + 's');
                            that.next();
                        }, time*1000);
                    })
                    return this;
                }
    
                sleepFirst(time) {
                    let that = this;
                    this.eventQueen.unshift(function () {
                        setTimeout(() => {
                            console.log('等待了' + time + 's');
                            that.next();
                        }, time *1000)
                    });
                    return this;
                }
                next() {
                    let fn = this.eventQueen.shift();
                    fn && fn();
                }
    
            }
    
    
    
            function LazyMan(name) {
                return new LazyClass(name);
            }

    24,比较opacity:0, visibility:hidden, display:none的优劣和适用场景

      都可以让元素不可见,

      display:none:  不渲染dom,不占据空间,无法监听事件,属性改变时会引起页面回流, transition不支持。

      visibility:hidden : 占据空间,渲染dom, 无法监听事件, 属性改变引起页面重绘。

      opacity:0  : 占据空间,渲染dom, 可以监听事件, 配合transition进行显示和隐藏, 属性改变引起页面重绘

    25,箭头函数和普通函数的区别是什么? 构造函数可以使用new生成实例,箭头函数可以吗?

      箭头函数和普通函数的区别:   箭头函数没有this, 箭头函数使用的是箭头函数所在函数的this,因为也无法使用call apply和bind来绑定和改变this。

                    箭头函数没有arguments属性,如果要使用可以用rest参数, 不可以使用yield命令,因此不能用作Generator函数。

      箭头函数不能当做构造函数,因为不能使用new命令,否则会报错。

    26,给定两个数组,计算他们的交集;  例如:给定 nums1 = [1, 2, 2, 1],nums2 = [2, 2],返回 [2, 2]。

        function getSame(arr1, arr2) {
                let result = [];
                let newArr2 = [...arr2];
                arr1.forEach(item => {
                    let index = newArr2.indexOf(item);
                    if (index > -1) {
                        newArr2.splice(index, 1);
                        result.push(item);
                    }
                });
                return result;
            }

    27,已知代码:  <img src="1.jpg" style="480px!important;”>  如何修改才能让图片宽度为300px?  下面的代码不能修改... 

      max- 300px;

    28, token加密的步骤

      后端通过随机数加签名来生成一个token, 前端拿到token后在接口调用的时候添加token,后端判断请求中携带的token进行验证。

    29,模拟实现一个promise.finally

    Promise.prototype.finally = function (callback) {
        let P = this.constructor;
        return this.then( value => P.resolve(callback()).then(() => value), error => P.resolve(callback()).then(()=> { throw error}) )
    }

    30,随机生成一个长度为 10 的整数类型的数组,例如 [2, 10, 3, 4, 5, 11, 10, 11, 20],将其排列成一个新数组,要求新数组形式如下,例如 [[2, 3, 4, 5], [10, 11], [20]]

         function getNewArray(arr) {
                let newArr = [...new Set(arr)];
                let hash = {length: 0};
                newArr.forEach(item => {
                    let index = Math.floor(item / 10);
                    if (!hash[index]) {
                        hash[index] = [];
                        hash.length++;
                    }
                    hash[index].push(item);
                });
                return Array.from(hash);
            }

    31,实现一个字符串匹配算法,从长度为n的字符串s中,查找是否存在字符串t,t的长度是n,若存在则返回位置

          function findStr(str, part) {
               if (part.length > str.length) return -1;
               for (let i = 0; i < str.length - part.length; i++) {
                   if (str.slice(i, i+part.length) === part) {
                       return i;
                   }
               }
               return -1;
           }

    32,数组里面有10万个数据,取第一个元素和第十万个元素时间相差多少

      数组本质上也是对象,其索引是字符串,查找数组的元素就是通过索引查找哈希表的过程,所以消耗的时间大致一样。

    33,vue的父组件和子组件生命周期钩子执行顺序是什么

      渲染: 父 beforeCreate --> 父created --> 父beforeMount --> 子beforeCreate --> 子created --> 子beforeMount --> 子mounted --> 父mounted

      更新: 父 beforeUpdate --> 子beforeUpdate --> 子updated --> 父updated

      销毁: 父beforeDestroy --> 子beforeDestroy --> 子 destroyed --> 父 destroyed

    34,promise.all的使用、原理和错误处理

      promise.all的参数必须有Iterator接口,参数的所有子元素都必须是promise示例,如果不是则自动调用promise.resolve转为promise示例。

      promise.all的状态由子元素的状态决定,只有子元素的状态都变成fulfilled,promise.all的状态才变为fulfilled,此时子元素的返回值组成一个数组,传给promise.all的回调函数。只要子元素有一个变为rejected,promise.all就变成rejected,返回第一个被rejected的子元素的返回值。

    35,axios、fetch和ajax有什么区别

      ajax: XMLHttpRequest对象,最早出现的发送请求的技术。

      axios: 使用promise对ajax的封装。 

      fetch:fetch是es6的用来代替ajax的异步请求技术。是原生的js,基于promise,为了扩展其他应用。

    36,vue组件的通信方式

      1,props、$emit

      2,$emit 、$on 

      3,$attrs和$listeners

      4,provide、inject

      5,vuex

    37,vuex工作原理

      vuex是专门使用于vue的状态管理工具,它集中管理所有组件的状态,并提供一系列方法来获取和操作状态。

      读取的数据和状态存放在state里面, getter为state的计算属性,state的值发生变化它也会被重新计算,改变状态就是提交mutations,如果是异步的任务则需要封装在action里面。 module是将store分割成模块,每个模块都具有上面的各个属性。

    38,什么是虚拟dom, 为什么虚拟dom会提高性能

      虚拟dom其实就是js的一个对象,通过对象来描述真实的dom。 

      频繁的操作真实dom,效率是很低的。 virtual dom通过使用数据对象来描述dom树,在每次视图更新的时候,比较与真实dom的差异, 只需要一次性更新有变化的dom,减少很多不必要的dom操作。 所以说 virtual是用来减少大范围频繁的重绘。

    39,vue计算属性和方法的区别

      计算属性是基于响应式依赖来进行缓存的,只有在相关的依赖发生变化的时候才进行求值。 而方法的话就不会进行缓存,总是会执行该函数。

    40,vue事件总线

    var bus = new Vue();
    
    定义事件 : bus.$on('事件名称', fn);
    触发事件: bus.$emit('事件名称', fn);
    View Code

    41,spa单页面的理解,优缺点是什么

      在页面初始化时加载相应的html、css和js,一旦页面加载完成,spa不会因为用户的操作而进行页面的重新加载或者跳转,而是使用路由机制实现内容的切换。

      优点: 用户体验好,内容的改变不需要加载整个页面,避免了重复的渲染。 对服务器压力小。 前后端分工明确。

      缺点: 初次加载耗时多, 前进后退路由管理, seo难度较大

    42,npm run dev之后的执行过程

      首先会在项目的根目录下寻找 package.json文件, 找到scripts对象对应的dev,执行对应的命令, webpack-dev-server 为一个node服务器,然后就会把当前的页面展示在node服务器的对应端口上。

    43,为什么组件中的data是一个函数

      因为组件是用来复用的,如果组件中的data是一个对象,那么每一个组件都是公用的一个data对象,data的值会相互影响,而当data为一个函数,那么每个示例可以维护一份被返回的对象,互相独立,互不影响。

    44,vue是如何实现双向数据绑定的

       https://www.cnblogs.com/wjyz/p/11419073.html

    45,var、let和const的区别

      let和const不存在变量提升, 并且只在当前的代码块中有效。  而且还存在暂时性死区, 不允许重复的声明。 const 声明的常量不能改变值,不过当值 为对象时可以改变内容。

    46,vue-router的router-link和a标签有什么区别

      router-link渲染出来的也是a标签,看vue-router的源码,router-link接管了渲染的a标签的行为, click的时候阻止了a标签默认的跳转,取得to的属性,通过history或者hash来进行页面的切换,并不会刷新页面。

    47,实现convert方法,将数组的list转换为tree结构

    var list = [
                {id:1,name:'部门A',parentId:0},
                {id:2,name:'部门B',parentId:0},
                {id:3,name:'部门C',parentId:1},
                {id:4,name:'部门D',parentId:1},
                {id:5,name:'部门E',parentId:2},
                {id:6,name:'部门F',parentId:3},
                {id:7,name:'部门G',parentId:2},
                {id:8,name:'部门H',parentId:4}
            ];
    // 转换后的结果如下
    let result = [
        {
          id: 1,
          name: '部门A',
          parentId: 0,
          children: [
            {
              id: 3,
              name: '部门C',
              parentId: 1,
              children: [
                {
                  id: 6,
                  name: '部门F',
                  parentId: 3
                }, {
                  id: 16,
                  name: '部门L',
                  parentId: 3
                }
              ]
            },
            {
              id: 4,
              name: '部门D',
              parentId: 1,
              children: [
                {
                  id: 8,
                  name: '部门H',
                  parentId: 4
                }
              ]
            }
          ]
        },
      ···
    ];
    View Code
    参考了一个大佬对对象引用的操作:
    
        function convert(list) {
                let result = [];
                let map = list.reduce((prev, next) => {
                    prev[next.id] = next;
                    return prev;
                }, {});
    
                //这时候 list 和 map里面的元素是相互引用的,
                for (let item of list) {
                    if (item.parentId === 0) {
                        result.push(item);
                        continue;
                    }
                    if (item.parentId in map) {
                        let parent = map[item.parentId];
                        parent.children = parent.children || [];
                        parent.children.push(item); // 后面的新增children 都会影响到根元素的内容
                    }
                }
                return result;
            }
    View Code

    48,实现Promise.race

            Promise._race = function (promises) {
                return new Promise((resolve, reject) => {
                    promises.forEach(promise => {
                        promise.then(resolve, reject);
                    })
                })
            }    

    49,实现模糊查询结果的关键词高亮

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            .red{
                color:red;
            }
        </style>
    </head>
    <body>
    <input type="text" id="input">
    <ul id="list"></ul>
    
        <script>
            let list = ['ab', 'abc', 'abd', 'abcdef', 'abcef','abcdefghij'];  // 模拟查询的数据
            let container = document.getElementById('list');
            let input = document.getElementById('input');
    
            function debounce(fn) {   // 防抖, 用户输入完成后300ms触发
                let timeout;
                return function (...args) {
                    if (timeout) {
                        clearTimeout(timeout);
                        timeout = null;
                    }
                    timeout = setTimeout(() => {
                        fn.apply(this, args);
                    },300)
                }
            }
    
            function handleInput(name) {
                let reg = new RegExp(`(${name})`);
                const result = list.reduce((prev, next) => {
                    if (reg.test(next)) {
                        let match = RegExp.$1;
                        let str = `<li>${next.replace(match, '<b class="red">'+match+'</b>')}</li>`;
                        prev.push(str);
                    }
                    return prev;
                }, []);
                if (name === '') {
                    container.innerHTML = '';
                    return;
                }
                if (result.length === 0) {
                    container.innerHTML = '暂无结果';
                } else {
                    container.innerHTML = result.join('');
                }
            }
            input.addEventListener('input', debounce(e => {
                handleInput(e.target.value);
            }))
        </script>
    </body>
    </html>
    View Code

     50,已知数据格式,实现函数fn找到对应id的所有父级id

    const data = [{
        id: '1',
        name: 'test1',
        children: [
            {
                id: '11',
                name: 'test11',
                children: [
                    {
                        id: '111',
                        name: 'test111'
                    },
                    {
                        id: '112',
                        name: 'test112'
                    }
                ]
    
            },
            {
                id: '12',
                name: 'test12',
                children: [
                    {
                        id: '121',
                        name: 'test121'
                    },
                    {
                        id: '122',
                        name: 'test122'
                    }
                ]
            }
        ]
    }];
    
    fn(data, '121');  //  [1, 12, 121]
    View Code

      

            function find(data, id) {
                if (Array.isArray(data)) {
                    while(data.length) {
                        let item = data.shift();
                        if (item.id == id) {
                            return item.hash.split('-');
                        }
                        if (item.children && item.children.length) {
                            item.children.map( one => {
                                one.hash = (item.hash || item.id) + '-' + one.id;
                                data.push(one);
                            })
    
                        }
                    }
                }
                return [];
            }    

      

      

      

  • 相关阅读:
    server域名与IIS的目录安全性
    机械臂生成URDF文件操作过程
    ROS2 学习参考链接
    solidworks 导入urdf 到ubuntu 在rviz 和 gazebo 显示
    vscode koroFileHeader插件配置
    python 获取当前类中非私有方法
    solidworks 导出urdf 在python ikpy库 使用注意点
    solidworks 打开step 文件并导出文件
    ikpy joint和 link区别
    python 导入包错误
  • 原文地址:https://www.cnblogs.com/wjyz/p/11378447.html
Copyright © 2011-2022 走看看