便利蜂前端面試題 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)模式的代碼,注意類似於線程安全和邊界問題。
這個之前做過總結,點此查看

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM