zoukankan      html  css  js  c++  java
  • 便利蜂前端面试题 2019秋季

    便利蜂2019秋季(11月)web前端笔试题
    前端技能试题v2.6


    一、单选题(总共8分,每题2分)
    1、以下不属于HTTP缓存控制协议头是( )
    A. Cache-Control    B. Content-Type   C.Etag   D.Vary
    考点:web缓存只http技术
    答案:B
    分析:已经系统了解了web缓存策略,总结了笔记,可以点此查看。Content-Type是响应头告诉浏览器返回的资源的MIME类型。

    2、cookie特性下列说法正确的是( )
    A. cookie没有长度限制,可以无限存储
    B. 浏览器可以获取任一域名的cookie   
    C. cookie不需要手动处理,请求时会自动携带
    D. 浏览器请求image时不会携带cookie
    考点:web缓存只本地存储技术中的 cookie
    答案:D
    分析:cookie的个小、条数都有限制。不同浏览器表现也不一值。
    大概都给4kb空间,每个域名50条左右。超出这阀门后,将会被忽略
    cookie获取有严格限制,不同域名(domain)下无法取的,同域名不同路径下(pach)下也不能取得。必须是同域名,和同路径(以及父子路径)
    只要设置了cookie,浏览器每次请求均会自己携带。所以c对,d不对

    3、cors中不属于简单请求的请求类型是()
    A. GET    B. HEAD  C.POST   D.DELETE
    考点:跨域技术之cors
    答案:C
    分析:CORS即跨来源资源共享,通俗说就是我们所熟知的跨域请求。
    众所周知,在以前,跨域可以采用代理、JSONP等方式,而在Modern浏览器面前,这些终将成为过去式,因为有了CORS。
    CORS可以分成两种:简单请求、复杂请求。一个简单的请求大致如下

    // HTTP方法是下列之一
    HEAD
    GET
    POST

    // HTTP头信息不超出以下几种字段
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type,但仅能是下列之一
    application/x-www-form-urlencoded
    multipart/form-data
    text/plain

    4、关于https以下描述错误的是()
    A. http是超文本传输协议,信息是明文传输。https则是具有安全性的ssl/tsl加密传输协议
    B. https一直使用非对称加密协议来保证数据安全   
    C. http默认使用80端口,https默认使用443端口来进行通信
    D. https公钥默认使用CA证书进行签名方式防止被修改
    考点:网络传输协议之https
    答案:D
    分析:考察https相关知识点。https证书需要自己申请,默认没有

    二、多选题(总分20分,每题4分)
    1、已知

    // finally方法的回调函数不接受任何参数,所以data参数无意义,永远是undefined
    fn.finally((data)=>{
        console.log(data);
    });

    请选择正确的fn,保证打印输出为‘我爱中国’()
    A. 

    fn = new Promise((res,rej)=>{
        setTimeout(()=>{
            res('我爱中国');
        });
        // 第一步:
        // promise一旦状态改变就不会再变,所以上边定时器没有意义,将只会执行rej,
        // 加了个return是防止构造函数内之后的代码执行,这里return后边没代码,所以没有意义,干扰视觉
        return rej('我爱中国'); 
    }).then(
        data => {
            return Promise.resolve(data); 
        },
        data => {
            // 第二步:
            // 这里抛出的异常,又没有catch处理,所以会报错,此函数内程序终止,但是不影响外边的(比如finally)
            throw 'I LOVE CHINA'; 
        }
    )
    //第三步执行题目代码finally
    // 最终执行结果:先打印undefined,再报错

    B. 

    //没有then处理状态改变,所以resolve也无意义,最后执行题目的finally
    fn =  Promise.resolve('我爱中国'); 
    // 最终执行结果:打印undefined

    C.

    //触发了reject状态,
    //但是then却没有第二个回调(其实连then都没有),所以会走到catch,并将值传入catch的回调内
    fn = Promise.reject('我爱中国').catch((data)=>{//所以data是'我爱中国'
        Promise.resolve(data);//但是这里又定义了个promise对象,最后也没人使用,所以这个也没有意义
    })
    //接着走题目的finally
    //最终执行结果:打印undefined

    D.

    //没有then的第二个参数,也没有catch,所以只会执行finall,最终打印undefined
    fn =  Promise.reject('我爱中国'); 

    答案:这题是个坑,没有一个对的选项
    分析:

    /*
    Promise有三种状态,pending(进行中)、fulfilled(已成功,也叫做resolve)和rejected(已失败)
    其状态一旦改变,就不会再变
     */
    let pm = new Promise((resolve,reject)=>{
    
    });
    
    /*
    Promise有3个实例方法then、catch、finally
    then:状态变更会执行此函数,此函数传入两个回调(非必须全传)
     */
    pm
    .then(()=>{
        //状态为resolve的回调
    },()=>{
        //状态为rejected的回调
    })
    .catch((e)=>{
        //用于补货构造及其3个实例函数的异常,需要注意的是如果then中没有第二个参数也会走到catch
    })
    .finally(()=>{
        //不管promise最后的状态,在执行完then或catch指定的回调后,都会执行finally方法指定的回调
    })

    考点:es6的Promise

    2、以下JSX组件使用方式写法错误的是()

    A. <MyComponents.DataPicker color='blue'/>
    B. <hello toWhat='world'/>
    C. <components[props.storyType] store={props.story}/>
    D. <Greeting {...props}/>
    答案:B C
    A属于点表示法,比如MyComponents是一个对象,里边有很多导出jsx元素的方法

    const MyComponents = {
         DataPicker:function(props){return '<div></div>'}
    }

    B选项不对,jsx明确规定,为区分与html元素。react的元素都必须以大写字母开头
    C想考察在运行时选择,但是这种写法是错误的。如果你的确想通过表达式来确定 React 元素的类型,请先将其赋值给大写开头的变量。这种情况一般会在你想通过属性值条件渲染组件时出现。要解决这个问题,我们需要先将类型赋值给大写开头的变量就可以了。参考这里

    const SpecificStory = components[props.storyType];
    <SpecificStory story={props.story}>;

    3、以下生明周期中,不可以setState() 的是()
    A. render() //不能写,会引起死循环
    B. componentWillReceiveProps() 
    C. componentWillUpdate()// 不能使用,会引起死循环
    D. componentDidMount() //可以,但是会警告。因为会引起重绘,但是此函数只执行一次。推荐在构造或者用定时器包裹setState
    答案:A  C

    4、React三大原则是()
    A. 单一数据源
    B. State是只读的
    C.单项数据流
    D. 使用纯函数来执行修改
    答案:A B D
    分析:C是其核心概念

    三、简答题(总分52分)

    1、有如下代码

    const MENU = {
        'FE':'前端开发工程师',
        'DEV':'后端开发工程师',
        'QA':'测试开发工程师'
    };
    
    function getTestScore(...args){ //第一步:“数组的扩展运算符,将一个个参数反转为数组
        const [userInfo = {}, type = 'FE'] = args; //第二步:数组的解构赋值,解构赋值时的默认值。
        const { userId } = userInfo; //第三步:解构userInfo对象里边的userId属性
        consle.log(`我的名字叫${userId},职位是${MENU[type]}`); // 第四步:打印 
    };

    请根据要求,分析答案。(如有异常,填写报错并指出报错代码段)

    (1)getTestScore(); //我的名字叫undefined,职位是前端开发工程师
    (2)getTestScore('DEV');//我的名字叫undefined,职位是前端开发工程师
    (3)getTestScore(null,'QA');//Cannot destructure property `userId` of 'undefined' or 'null'

    考点:es6 变量的解构运算符、es6的扩展运算符
    答案:已在题目后标出
    分析:一段针对一个分析,下边是具体
    没有任何参数,所以第二步解构的无果,均用默认值。 所以userInfo解构的userId为undefined,type为FE
    只有DEV一个参数,这个参数将会被映射到userInfo上,而type依然是默认值。因为UserInfo被解构为字符串DEV所以会再被隐式转换为对象去解构userId,为undefined。type为FE
    第三种情况,null不能被解构,直接挂了

    2、有如下代码

    class a {
        name='a';
        count=1;
        getName(){
           return 'a'+1;
        }
        getCount = () => {
            return this.count;
        }
    }
    
    class b extends a {
        name='b';
        count=2;
        getName(){
            return this.name+this.count;
         }
         getCount = () => {
             return this.count;
         }
    }
    
    var c = new a();
    var d = new b();

    请写出函数返回值(10分)
    (1)c.getName();// 'a1'
      Js中,字符串与任意数据类型用加号连接,都表示字符串的拼接。JS中+、+= 运算符既是算术运算符,也是字符串的连接符

    (2)d.getCount();//2
     这一题没有难度,估计是靠我class基本语法

    (3)delete d.getName;  d.getName();//b2
      delete操作只会在自身的成员(成员包含属性和方法)上起作用,
      如果你试图删除的成员不存在,那么delete将不会起任何作用,但仍会返回true。不会报错
      class中变量属性在自身成员内,但函数是定义在原型上的
      综上,删除对象d不存在的getName,其实无意义。 根据原型知识,d会查找到原型上的getName执行:b2
    (4)d.__proto__.getName(); // NaN 
       es6的继承,与如下写的还是有区别的

    function E(){
        this.ename = 'e';
        this.name = 'e';
    }
    E.prototype.getName=function(){
        console.log(this)
        console.log(this.name)
    }
    
    function F(){
        this.name = 'f'
    }
    
    F.prototype = new E()
    F.prototype.getName=function(){
        console.log(this)
        console.log(this.name)
    }
    
    var f = new F();
    View Code

      es6的继承,其实就是让父类的原型 = 子类的实例对象,但是跟如上传统写法又有区别,具体表现在
      如果父类有额外的(跟子类属性名称不同的)成员会将其属性添加到子类的成员属性上。传统不会融合到子类上
          子类b的原型对象 = a的实例。但是 这个a的实例不包含成员属性。传统不会 不包含子类的成员属性
      所以,d.__proto__其实就是一个不包含成员属性的a类的实例对象,
      然后a的实例对象去调用getName方法,该方法里找不到成员属性name和count,就去a类的原型,发现依然没有,然后在向a的原型对象的原型对象上object找,依然没有
          最后就是undefined+undefined,最后是NaN
       

    (5) d.__proto__.getCount(); //报错找不到这个方法
      es6中的静态方法,并不会被转义到function的原型上,而是被定义到成员属性上。
         因为用了extend,所以虽然getCount成为 成员属性,但是通过类继承方式隐式创建的a实例,并无如上说的特性a的实例中并无成员属性,自然没有getCount,原型链也没有 

     

     3、有如下代码,请填写执行效果(10分)

    // 第一步:将异步代码放入宏任务的event table之中,
    // 等时间到了,推入宏任务回调到event queue中,
    // 等待第二轮开始的时候首先执行宏任务中的event queue中
    setTimeout(()=>{ 
        //第六步:(第二轮事件循环开始)打印1
        console.log(1);
    });
    
    var data = {};
    for (var i = 0; i < 10; i++) {
        data[i] = function(){
            //永远会是10,因为i是全局变量,for循环完毕,i是10
            // 用let声明i或者用下边注释的方法利用闭包来保存变量就可以输出理想的值
            console.log(i);
         };
    };
    //    data[i] = ( function(i){
    //       return function(){
    //          console.log(i);
    //       }
    //    })(i)
    
    // 第二步:将异步代码放入微任务的event table之中,
    // 等执行完毕,推入微任务回调到event queue中,
    // 等待第一轮同步代码执行完毕的时候,就去执行异步栈的微任务event queue中,即本轮event loop循环就执行
    var p = new Promise((res,rej)=>{ 
        console.log(2);  //第三步:(第一轮事件循环)同步代码打印2
        res(3);
    });
    
    //第五步:(第一轮事件循环)同步代码执行完毕,开始执行异步之微任务event queue
    p.then(data=>{
        console.log(data);
    })
    //第四步:(第一轮事件循环)同步代码打印10和undefined,其中undefined是函数的默认返回值
    console.log(data['8']()); 
    
    //打印顺序:2 10 undefined 3 1

     4、请指出以下代码存在的问题(12分);

    const fetchDataList =()=>{
      return new Promise((resolve,reject)=>{
        setTimeout(()=>{
          let result = [
            {id:20190101,name:'张三'},
            {id:20190102,name:'李四'},
          ]
          resolve(result)
        },2000)
      })
      
    }
    import React from 'react';
    
    class Page extends React.Component{
      constructor(props){
        super(props);
        this.state = {
          dataList:[]
        };
      }
      componentDidMount(){
        setInterval(()=>{
          this.fresh()
        },1000);
      }
      async fresh(){
        const dataList = await fetchDataList();
        console.log(dataList)
        this.setState({dataList});
      }
      render(){
        return(<div>
            {this.state.dataList.forEach(item => (
                <div>
                    <p>编号:{item.id}</p>
                    <p>名字:{item.name}</p>
                </div>
            ))}
        </div>)
      }
    }
    export default Page;

    答案:
    a、jsx中的循环调使用了forEach。要知道react推荐用map是有原因的,说一下两者差别
        map和forEach均属于Array的实例方法。数组直接调用即可
        两者参数均是一个回调函数,且回调函数的参数一致 (item,index,arr)
        不同的是map有返回值,而forEach没有返回值:
              map通过回调函数内的return作为依据,返回一个新组合的数组,不会改变原数组
              forEach则会回调内改变原来的数组,即使回调内有return也不会让其有返回值,
              forEach如果前边有变量妄想接收它的返回值,那将是undefined(js规定方法都有返回值,如果没有,系统默认返回undefined表示没有返回值)
       所以,如上的循环并不会返回新的数组,返回的是undefined,自然也不会被遍历出内容
    b、遍历的时候,需要给顶层元素一个key,作为react同等元素diff规则依据,如果没有,这个diff性能将会耗费性能,默认会给警告
       index.js:1375 Warning: Each child in a list should have a unique "key" prop.
    c、那个定时器去获取最新数据的地方也有2个问题。
       首先setInterva不会自动销毁,会一直执行下去,在组件卸载的时候,将其clear掉
         其次,每隔2s执行一次请求来更新数据也有问题,setIntervel具有累积效应,
                如果某个操作特别耗时,超过了setInterval的时间间隔,排在后面的操作会被累积起来,然后在很短的时间内连续触发,这可能或造成性能问题
               这个地方可以单独做一个讲解,先不改这个地方
          我觉得,类似于这样实时更新数据的,可以用递归的方式成功之后,再次请求,或者websocket
    修改完所有bug后的代码

    import React from 'react';
    let i = 20190102;
    const fetchDataList =()=>{ //模拟后端接口
      return new Promise((resolve,reject)=>{
        setTimeout(()=>{
          i++
          let result = [
            {id:20190101,name:'张三'},
            {id:i,name:'李四'},
          ]
          resolve(result)
        },4000)
      })
      
    }
    class Page extends React.Component{
      constructor(props){
        super(props);
        this.mySetInterval = null;
        this.state = {
          dataList:[]
        };
      }
      componentDidMount(){
        this.mySetInterval = setInterval(()=>{
          this.fresh()
        },1000);
      }
      componentWillUnmount(){
        // 如果没有这个操作将会报错:我们不能在组件销毁后设置state,防止出现内存泄漏的情况
        //关于react中切换路由时报以上错误,实际的原因是因为在组件挂载(mounted)之后进行了异步操作,
        // 比如ajax请求或者设置了定时器等,而你在callback中进行了setState操作。
        //当你切换路由时,组件已经被卸载(unmounted)了,此时异步操作中callback还在执行,因此setState没有得到值。
        this.setState = ()=>{
          return false;
        }
    
        //清除掉定时器
        this.mySetInterval&&clearInterval(this.mySetInterval)
      }
      async fresh(){
        const dataList = await fetchDataList();
        this.setState({dataList});
      }
      render(){
        return(<div>
            <div>
            {this.state.dataList.map(item => (
                <div key={item.id}>
                    <p>编号:{item.id}</p>
                    <p>名字:{item.name}</p>
                </div>
            ))}
            <div>你好</div>
            </div>
        </div>)
      }
    }
    export default Page;
    View Code

    5、请写出下面代码运行后console输出结果(mobx为非poxy实现版本) (13分)
    这一题,需要知道mobx,就不提出来了,考试这个实际意义不大,
    如果考生没有接触过mobx就无从下手。mobx是类似于redux的状态管理库,但是没有redux出名

    四、编码题(总分20分)
    请写出发设计模式之布订阅者(bunsub)模式的代码,注意类似于线程安全和边界问题。
    这个之前做过总结,点此查看

     



  • 相关阅读:
    《JavaScript高级程序设计》读书笔记 ---继承
    技术人员在小公司成长 vs 大公司成长路径和建议
    原生JS forEach()和map()遍历的区别以及兼容写法
    《JavaScript高级程序设计》读书笔记 ---创建对象
    《JavaScript高级程序设计》读书笔记 ---理解对象
    《JavaScript高级程序设计》读书笔记 ---小结
    《JavaScript高级程序设计》读书笔记 ---单体内置对象
    《JavaScript高级程序设计》读书笔记 ---基本包装类型
    《JavaScript高级程序设计》读书笔记 ---Function 类型
    《JavaScript高级程序设计》读书笔记 ---RegExp 类型
  • 原文地址:https://www.cnblogs.com/dshvv/p/11830928.html
Copyright © 2011-2022 走看看