zoukankan      html  css  js  c++  java
  • 一些面试题总结

    1.请用原生代码实现选取目标元素所有满足条件的父级元素。

    描述:如选出id为target的所有含有类名为father的上级元素

    思路:使用递归实现,但是尽量不要创建额外的全局变量

    代码:

    var a=document.getElementById("this");
            function getParent(dom){
                var d=dom.parentNode;
                var arr=[];
                if(d){
                    if(d.className=="target"){
                        arr.push(d);
                    }
                    if(d.parentNode){
                        return arr.concat(getParent(d));
                    }else{
                        return arr;
                    }
                }else{
                    return arr;
                }
            }
            console.log(getParent(a));

    2.使用深度优先的原则遍历一棵树

    描述:其实就是采用递归去遍历一个json串,如代码中结构的数据所示

    输出:

    var tree={
                leaf1:{
                    leaf2:"value2"
                },
                leaf4:{
                    leaf6:{
                        leaf7:{
                            leaf8:"value8",
                            leaf10:"value10"
                        },
                        leaf9:"value9"
                    }
                },
                leaf3:"value3"
            };
    
    function ergodicTree(tree,arr){
                arr=arr||[];
                for(var item in tree){
                    var i=tree[item];
                    var brr=[];
                    brr.push(item);
                    if(typeof i=="object"){
                        ergodicTree(i,arr.concat(brr));
                    }else{
                        brr.push(i);
                        console.log(arr.concat(brr));
                    }
                }
            }

     3.用js实现快速排序

    function quick(arr){
        var left=[];
        var right=[];
        if(arr.length<=1){return arr;}
        var index=Math.floor(arr.length/2);
        var mid=arr.splice(index,1)[0];
        for(var i=0;i<arr.length;i++){
           if(arr[i]>mid){
              right.push(arr[i]);
           }else{
              left.push(arr[i]);
           }
        }
        return quick(left).concat([mid],quick(right));
    }

     4.简述Object.getOwnPropertyNames / Object.keys 及 for...in 的区别

    getOwnPrppertyNames 能够列举出当前object的全部非原型属性,包括可枚举的和不可枚举的。

    keys 只能列举出object的非原型可枚举属性

    for...in 能遍历object的全部可枚举属性

    5.简述for...in 和 for...of的异同

    相同点:二者都是有遍历、迭代的功能

    不同点: 1.当二者遍历相同类型的数据时,for...in 遍历时的参数是数据的key,而for...of是数据的value

                 2.for...in 可以遍历object、array等, 而 for...of 只能遍历map set array等可迭代变量

    6.react中子组件如何更新父组件的state

    在子组件中调用父组件中定义的函数,这个函数通过props传到子组件中

    7.vue中,如何封装一个组件,在不适用template的前提下,输出一下dom结构:<component-a><component-b foo="bar"/></component-a>?

    很简单,使用vue的render createElement 函数

    Vue.component('component-b',{
        props:{
            foo:{
                type:String,
                required:true
            }
        },
        render(h){
            return h('div',['组件B',this.$props.foo])
        }
    });
    
    Vue.component('component-a',{
        render(h){
            return h('div',['组件A',h('component-b',{
                props:{
                    foo:'bar'
                }
            })]);
        }
    })
    
    export default {
        name:'tcm',
        render(h){
            return h('div',[h('component-a')]);
        }
    }

    8.在SPA项目中如何实现动态模块依赖?

    分别以vue和react +webpack 为例:

    vue:  在vue的单文件中不需要额外的plugin或loader配置,直接使用如下方式即可动态加载模块及组件

           

    // 加载js模块
    import('./asyncMod').then(res=>{
         console.log(res.default);
         res.default();
    });
    
    
    // 加载组件
    
    const Layout = () => import('./page/layout');

    react: react中的配置比较复杂,babel7 环境下需要 安装 @babel/plugin-syntax-dynamic-import  插件

    其中加载异步模块与vue是一样的

    而异步加载组件则需要进一步封装一个高阶组件

    import React, { Component } from "react";
    
    export default function asyncComponent(importComponent) {
      class AsyncComponent extends Component {
        constructor(props) {
          super(props);
    
          this.state = {
            component: null
          };
        }
    
        componentDidMount() {
            // const { default: component } = await importComponent();
            let _this=this;
            importComponent().then(res=>{
                _this.setState({
                    component: res.default
                });
            })
        }
    
        render() {
          const C = this.state.component;
    
          return C ? <C {...this.props} /> : null;
        }
      }
    
      return AsyncComponent;
    }

    使用时调用高阶组件即可:

    const Layout = asyncComponent(()=>import('./page/layout'));

    9.content-type/content-encoding/transfer-encoding分别是什么含义?分别有哪些值?

    content-type: 体头部用于指示资源的MIME类型 。 常见的值为  text/html; charset=utf-8  等等

    transfer-encoding: 消息首部指明了将http请求实体安全传递给用户所采用的编码形式。  值为: chunked  gzip  deflate  identity  compress

                               详细参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Transfer-Encoding

    content-encoding: 是一个实体消息首部,用于对特定媒体类型的数据进行压缩。当这个首部出现的时候,它的值表示消息主体进行了何种方式的内容编码转换。这个消息首部用来告知客户端应该怎样解码才能获取在 Content-Type 中标示的媒体类型内容

                               值为: gzip br deflate  identity  compress

                               详细参考: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Encoding

    10. 编写一个函数,计算n个数字的和,n>=0,要求:不能使用循环,必须使用尾递归,算法复杂度为O(n).

    function sum(num,total){
       if(!total){
           total = 0;
       }
       total += num;
       if(num<=0){
           return total;
       } else {
           return sum(num-1,total);
       }
    }


    function sum(num){
    if(num<=1){
    return num;
    } else {
    return num+sum(num-1)
    }
    }

    11. 实现js深拷贝,要求:a.不能使用循环数组下标做数组拷贝(考虑到稀疏数组)。b.不能拷贝对象原型链上的属性

    注: 这个问题提的有点傻逼,不循环数组下标还要深拷贝,对象数组怎么办?这他娘的怎么深拷贝?

    不考虑内容是对象的情况下: newArr = arr.slice()  就实现了深拷贝

    (这里默认不采用 JSON.parse 和 JSON.stringify)

    function judgeType(s){
        if(s==null){
            return 'null';
        }
        let str = Object.prototype.toString.call(s);
        let reg = /[w+s(w+)]/;
        var ss = str.match(reg)[1];
        return ss.toLowerCase();
    }
    
    
    function copyArray(arr){
        let aa = [];
        arr.forEach(e=>{
            switch(judgeType(e)){
                case 'array':
                    aa.push(copyArray(e));
                    break;
                case 'object':
                    aa.push(copyObject(e));
                    break;
                default:
                    aa.push(e);
            }
        });
        return aa;
    }
    
    function copyObject(obj){
        let keys = Object.getOwnPropertyNames(obj);
        let oo = {};
        keys.forEach(e=>{
            let val = obj[e];
            switch(judgeType(val)){
                case 'array':
                    oo[e] = copyArray(val);
                    break;
                case 'object':
                    oo[e] = copyObject(val);
                    break;
                default:
                    oo[e] = val;
            }
        });
        return oo;
    }

    12. exports 和 module.exports 有什么区别?AMD 和 CMD有何区别?

    exports 是指向module.exports的一个指针,相当于 exports = module.exports 。

    它是指向module.exports的,所以在使用时不能直接赋值

    // exports指向了包含了a函数的对象,而不是module.exports,导致模块化失效
    exports = {
        a(){
           .....
       }  
    }    
    
    
    // 正确使用方法
    
    exports.a = function a(){.....}

    AMD讲究的是依赖前置,就是在定义模块的时候就把依赖写在define函数的引用中

    CMD讲究依赖就近,在define函数体中随便requrire,用的时候就requrie即可

    // CMD
    define(function(require, exports, module) {
         var a = require('./a')
         a.doSomething()
         // 此处略去 100 行
         var b = require('./b') // 依赖可以就近书写
         b.doSomething()
         // ...
    })
    
    // AMD 默认推荐的是
    define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
         a.doSomething()
         // 此处略去 100 行
         b.doSomething()
         //...
    })

      

    13.React 生命周期和 setState操作关系 及 setState在合成事件和原生事件中执行的区别

    生命周期中setState的使用情况:

        无意义使用:componentWillMount,componentWillUnmount;

        有条件使用:componentDidUpdate;

        禁止使用:componentWillUpdate,shouldComponentUpdate;

        正常使用:componentWIllReceiveProps,componentDidMount。

    生命周期中setState是否触发更新:

        componentWillMount和componentWillReceiveProps中,setState会被react内部处理,而不触发render;

        其他生命周期均正常出发更新渲染。

    setState在原生事件中是同步执行,在合成事件中是异步执行

    因为合成事件自己实现了冒泡机制,整个冒泡过程在batchedUpdates这个批处理事务中处理,在合成事件中的setState走到enqueueUpdate的时候,就都会被放进dirtyComponents中等待批处理,此时等待close操作才能将dirtyComponents中存储的state落实到渲染中。所以整个过程是异步的。

    而原生事件中没有这一过程,说到底同步还是异步看之前有没有进行过batchedUpdates批处理。

     

     14.阐述一下http缓存策略

    缓存策略分为强制缓存和对比缓存。

    强制缓存:只要请求了一次,在有效时间内,不会再请求服务器(请求都不会发起),直接从浏览器本地缓存中获取资源

                   cache-control 和 Expires ,同时存在时cache-control 优先级高于Expires

    对比缓存:无论是否变化,是否过期都会发起请求,如果内容没过期,直接返回304,从浏览器缓存中拉取文件,否则直接返回更新后的内容

                   Etag / If-None-Match 优先级高于 Last-Modified / If-Modified-Since

    二者对比:强缓存优先级 > 对比缓存优先级

    15.阐述macro-task和micro-task 的区别

    首先:全部代码(script)算一个macrotask.。
    第一步:浏览器先执行一个macrotask;执行的过程中,创造了新的macrotask(setTimeout之类的),然后接着执行,把promise加入到micro-task队列里面
    第二步:浏览器执行microtask(例如promise),这里会将microtask里面所有任务都取出
    第三步:重复,浏览器会再执行一个macrotask
    总的来说:macrotask每次只取一个,而microtask会一次取完
    macrotask 包括:
    • setTimeout
    • setInterval
    • setImmediate
    • requestAnimationFrame
    • I/O
    • UI rendering

    microtask包括:

    • process.nextTick
    • Promises
    • Object.observe
    • MutationObserver

    16.如何根据页面的坐标获取相对应的元素?

    document.elementFromPoint(x,y) 

    17.如何在前端页面发起导出excel请求?

    async handleExportClick(){
          this.makePost();
          return false;
        },
        makePost(date){
          let inputs = '<input type="hidden" name="date" value="'+ this.messageDataDate +'"/>';
          let $form=$('<form action="/api/mm/export/excel" method="post">'+inputs+'</form>');
          $form.appendTo('body').submit().remove();
        },

    18.用js单向链表实现队列,实现队列的push 和 shift 功能

    function ListNode(val){
        this.val = val;
        this.next = null;
    }
    
    function createList(vals){
         var head = {};
         var curr = head;
         vals.forEach(e=>{
             curr = curr.next = new ListNode(e);
       
         })
         return head.next;
    }
    
    class MyListNode {
        constructor(vals){
            this.List = createList(vals);
        }
    
        push(val){
            var list = this.List;
            var head = {};
            var curr = head;
            while(true){
                curr = curr.next = list;
                if(list.next===null){
                    curr = curr.next = new ListNode(val);
                    console.log(head,curr);
                    break;
                }
                list = list.next;
            }
            this.List = head.next;
        }
    
        shift(){
            this.List = this.List.next;
        }
    }

    20. react 和 vue 多层组件嵌套,在不使用redux和vuex的情况下,最外层父组件如何向最里层传值?

    react : 使用context

    1. 建立context数据初始化对象state,并用React.createContext(state) 生成context
    2. 在父组件中引用context对象,并放入static属性contextType(此属性名称固定,不得更改)中
    3. 子组件也引用context对象并放入static属性contextType中,在引用数据时使用this.context即可获取

    vue: 使用provide/inject

    1. 最外层父组件中定义名为Provide(不可更改)方法,该方法的返回值为对象或者函数 Provide(){return {a:1,b:2,c:3};}
    2. 在最内层子组件中使用inject 属性,属性值为数组,inject:['a','b'],在组件中通过 this.a this.b即可使用数据

  • 相关阅读:
    python读文件指定行的数据
    在linux系统中实现各项监控的关键技术(2)--内核态与用户态进程之间的通信netlink
    在linux系统中实现各项监控的关键技术(1)--cpu使用率的计算
    spring事件驱动模型--观察者模式在spring中的应用
    B2C自营商城的订单设计方案
    RabbitMQ死信队列
    springboot操作rabbitmq
    Rabbitmq--topic
    docker-compose.yml rabbitmq
    运行rabbitmq
  • 原文地址:https://www.cnblogs.com/JhoneLee/p/5971152.html
Copyright © 2011-2022 走看看