刷 攜程 地面業務 前端面試經歷

kinshan發表於2018-12-26

在簡書看到這篇面試題,結合作者的答案和個人的理解做了一下,因個人水平有限(不謙虛,確實很菜),如果個人做的有什麼不對的歡迎指出來,共同交流

作者:詩和元芳 連結:www.jianshu.com/p/e6efcd993… 來源:簡書 簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。

筆試

題目一

<div id="d">
    <div id = "a"></div>
    <div id = "b"></div>
    <div id = "c"></div>
</div>
<script>
    var a = [document.getElementById('a'),document.getElementById('b'),document.getElementById('c')];
    var b = [document.getElementById('d').getElementsByTagName('div')];
</script>
複製程式碼

問a 和 b 的區別

我們把結果列印出來看一下:

a

刷   攜程 地面業務 前端面試經歷

b

刷   攜程 地面業務 前端面試經歷

看MDN官方對Element.getElementsByTagName()這個說法的解釋: “Element.getElementsByTagName()方法返回一個動態的包含所有指定標籤名的元素的HTML集合HTMLCollection。指定的元素的子樹會被搜尋,不包括元素自己。返回的列表是動態的,這意味著它會隨著DOM樹的變化自動更新自身。所以,使用相同元素和相同引數時,沒有必要多次的呼叫Element.getElementsByTagName() .”

很多人(包括我和作者)都會以為這題差別是在b返回的是二維陣列,其實都是想當然了。 a返回的是一個包含三個dom元素的陣列,而b返回的是隻有一個HTMLCollection元素的陣列。這是完全的兩種結構且HTMLCollection並不繼承自Array.

  • 1、HTMLCollection是及時更新的,當文件中的DOM變化時,它是會隨之變化的
  • 2、HTMLCollection可以用 HTMLCollection.item()HTMLCollection.namedItem() 這種方式來獲取內部元素。

題目二 陣列去重

請手打一個陣列去重的方法,題目是[1,2,3,2].distinct() = [1,2,3]。
複製程式碼

關於陣列去重的方法有很多,網上資料太多不再贅述,作者用的是一種hash去重的方法。

Array.prototype.distinct = Array.prototype.distinct || function(){
            var len = this.length,
                  i = 0,
                  hash = {},
                  myArr = [];
        for(; i < len; i ++){
                  if(!hash[this[i]]){
                      hash[this[i]] = true;
                      myArr.push(this[i])
                  }
        }
    return myArr;
}
複製程式碼

這種方法可以達到題目中的要求,但並不是一種嚴謹的陣列去重方式。 假設我們的的陣列變成[1,2,3,2,'1'],這種方法就無法達到去重的效果了,這種方式無法區分數字1和字串'1',還需要通過型別判斷。 關於陣列去重,最簡單的是ES6的:

Array.prototype.distinct = Array.prototype.distinct||function(){
	console.log(this);
    return Array.from(new Set(this)); //return [...(new Set(this))];
}
複製程式碼

題目三,考察閉包

function mo(){
    var x = 0;
    return function(){
        console.log(++x)
    }
}
var a = mo();
var b = mo();
a();
a();
b();

複製程式碼

答案是1,2,1。
a 和 b是不同的兩個函式,分別保持著各自對不同的x的引用。

題目四

var p = [];
var A = new Function();
A.prototype = p;
var a = new A;
a.push(1);
console.log(a.length);
console.log(p.length);
複製程式碼

答案:1,0。
這題要理解的一點是:

a.__proto__ === p
複製程式碼

按照<<高階程式設計>>中講解的new的過程:

  • 建立一個新物件
  • 將建構函式的作用域賦給新物件(因此this就指向了這個新物件)
  • 執行建構函式中的程式碼(為這個物件新增屬性)
  • 返回新物件

我們模仿一下new這個過程發生的事: new A =>

(funciton(){
    //第一步,把__proto__指向p(A.prototype)
    //第二步,按照p(A.prototype)的樣子創造一個物件(克隆)
    var a = Object.create(A.protype);
    A.call(a);
    return a;
})()
複製程式碼

new 如果在繼承物件是沒有引數的情況下,是可以不加後面的括號的,編譯器會自動替你加上的。但是要記住new的沒有括號優先順序是低於.的,有括號是高於();

題目五,陣列降維

[1,2,3,[4,5,[6,7]]]
複製程式碼

下面是原文作者提供的兩種寫法:

function fn(arr){ 
    var tempArr = Array.from(arr.join('-'));  //join()會自動新增逗號
    for(var i = 0;i<tempArr.length;i++){ 
        if(isNaN(tempArr[i])){ 
            tempArr.splice(i,1) 
        } 
    } 
    return tempArr; 
}
複製程式碼
  function fn(arr){
         var myArr = [];
         var fn2 = function(arr2){
               for(var i = 0;i<arr2.length;i++){
                   if(Array.isArray(arr2[i])){
                        fn2.call(null,arr2[i])
                   }
                   else{
                       myArr.push(arr2[i]);
                   }
               }
         }
         fn2(arr);
         return myArr;
       }
       fn([1,2,3,[4,5,[6,7]]]);

複製程式碼

這裡再提供一種簡潔的寫法:

let flatten = arr => arr.reduce((pre,cur)=>{
	Array.isArray(cur)?pre.push(...flatten(cur)):pre.push(cur);
	return pre
},[])

複製程式碼

面試

函式宣告和函式表示式有什麼區別

答:解析器有一個函式宣告提升的過程,讀取並將函式宣告新增到執行環境中,Javascript在第一遍會宣告函式並將它們放到原始碼的頂部。使其在執行任何程式碼之前可用。

函式宣告既然會提升,優先順序是什麼,和var比呢

答:函式提升優先順序比變數提升要高,且不會被變數宣告覆蓋,但是會被變數賦值覆蓋,也會被後面的同名函式替換。

console.log(typeof(foo));   //function
function foo(){}
var foo = 5;
複製程式碼
foo = 5;
console.log(typeof(foo));  //number
function foo(){}
複製程式碼

函式宣告的提升為什麼會比var高,編譯器幹了什麼事情

引擎在執行javascript程式碼之前,會先將其進行編譯,編譯階段會找到所有宣告,並找到合適的作用域將它們關聯起來。 Javascript在第一遍會宣告函式並將它們放到原始碼的頂部 函式宣告提升的是整個函式,變數宣告提升的僅僅是var a;這部分。

函式宣告會將變數宣告覆蓋,而變數宣告只能當做重複宣告被忽略。所以函式宣告的提升比var高。(純個人理解,如有不對歡迎指出)

es6 裝飾器用過沒,是幹什麼用的(應該是es7的,反正我也沒答出來,答出來肯定還繼續深的問)

裝飾類、裝飾方法或屬性。裝飾器可以聯想到裝飾器模式:向一個現有的物件新增新的功能,同時又不改變其結構的設計模式,它是作為現有的類的一個包裝。

es6中的擴充套件運算子...的實現原理

呼叫預設的iterator介面

<-------------------以下內容是原文作者的回答,明天接著刷,大家有好的答案之類非常歡迎提供---------------------------->

es6中的解構中的...和上面的區別

答:說真的,我也不知道啥區別,不是一樣用嗎?

[...org,name] = [1,2,3,4] 這樣的話,org裡是個啥

答:開始問的放後面是啥,我想了半天,沒敢說,我說難道後面的就沒抓到,全被org抓走了?其實不是,直接報錯了,...是rest的意思,既然是rest,那就只能放在最後啊

更新說明我還不會用,區別應該是問的es7中的解構。原理就是es6直接採用for of,也就是說,所有總有迭代器的物件都能使用擴充套件運算子,在es6裡說不能放前面的,但是在es7裡如果用於物件是可以放前面的。懂了這個,上面幾題就都該會了

for of 和for in區別

答:for in 是鍵值對形式,for of 是輸出value形式,然後for of只要是配置了迭代器,都能遍歷。

this的指向問題

答:這個正常的都說了

箭頭函式中的this

答:這裡說的不好,我只說了用了箭頭函式的話,this就被傳進來了。就不需要繫結進來了。

箭頭函式中的this預設指向在定義它時,它所處的物件,而不是執行時的物件, 定義它的時候,可能環境是window

什麼是閉包(這裡答的不太好,雖然都會用啊處理的,我用類似如下程式碼舉例,貌似面試官並不滿意...)

      function aa(){
        var a = 1;
        return function bb(){
            console.log(a);
        }
    }
    aa()()
複製程式碼

什麼是作用域

答:在進入指令碼標籤編譯階段的時候就定義了各類作用域,外面的變數就在全域性作用域,函式內部的就在函式的作用域裡,作用域外的函式不能訪問某個作用域裡面的東西

什麼是作用域鏈

答:在各級執行上下文建立階段的時候,就確定了各級作用域,串起來就是作用域鏈了。比如閉包的時候外部函式出棧之後,內部函式還保留了對外部函式某個變數的引用,就是通過作用域鏈找過去的

什麼是原型

答:prototype,好像我也說不出啥,就舉個函式的寫原型的例子。 js有哪些設計模式(我說有工廠模式,建構函式模式,原型模式,面試官說這是物件導向,不過我覺得有啥區別,物件導向程式設計不久是要用這些設計模式嗎) 這些模式都是咋寫的,我手寫給他看

為什麼要用原型

答:共享原型裡的東西給下屬繼承的物件,這樣在new的時候不用重新建立,節省記憶體空間

eval的缺點

答:我說了用法,就是可執行string,然後缺點沒說,沒怎麼研究,只是看了一眼用法型別的

with的缺點

答:沒用過,在網上看到過,說不要用,然後我就不用,應該會導致效能問題吧

在嚴格模式下能不能用eval

答:不能

es5和es6嚴格模式的區別

答:不知道

什麼是柯里化,舉React和Redux的例子

答:解釋了柯里化是啥,舉不出來例子,沒看過原始碼啊或者是對react瞭解的不夠多

什麼是純函式

答:不產生任何互動的函式?答的不好,我說reducer應該就是個純函式,猜對了而已。

純函式是指 不依賴於且不改變它作用域之外的變數狀態 的函式純函式的概念連結

頁面和伺服器之間的互動有哪幾種(ajax,websocket,不滿意)

ajax的Type有幾種(我只知道post和get)

這題我可能沒有理解... get和post的區別(我說的表象區別,url引數,安全性,大小限制,面試官不是很滿意)

與 POST 相比,GET 更簡單也更快,並且在大部分情況下都能用。 然而,在以下情況中,請使用 POST 請求: 無法使用快取檔案(更新伺服器上的檔案或資料庫) 向伺服器傳送大量資料(POST 沒有資料量限制) 傳送包含未知字元的使用者輸入時,POST 比 GET 更穩定也更可靠

HTTP請求頭上都有什麼資訊

答:UA,HOST,其他的我也沒說,就說還有幾個沒注意..

如何統計頁面上的按鈕被點選了多少次

答:和伺服器互動?反正也只能存伺服器啊...

單頁面應用和多頁面應用的區別

答:一個跳頁面是內部的,一個跳頁面是href整頁重新整理的。

哪種更容易被SEO到,優化SEO

答:猜測是多頁面,頁面多唄...優化的不知道

上兩題補充連結

cookie和localstorage區別(我說大小,安全,有效期,貌似又不是很滿意)

JSON.stringify(大OBJ)的時候會有什麼問題 答:效能損失。

script標籤順序怎麼控制,涉及到依賴必須要有先後

答:在HTML層就控制順序唄,顯然不是他要的答案

除了直接引用script標籤,如果不用import require這樣的東西,怎麼呼叫其它頁面的js

答:真不知道,a.js裡除了用script標籤引用b.js

import和require的區別

答:import是靜態載入,一旦你import,內容就進來了,require是動態載入,用的時候才載入,後面又問了一些,後面就不會了

函式節流怎麼實現

答:簡單是settimeout,時間超出就執行,沒超出再進來的話就直接clear掉。面試官覺得太簡單了。

canvas 繪製原理

答:不知道

如何使用canvas拖動一個小球撞擊另外一個小球,然後另外一個小球被撞擊出去 答:canvas一年半沒用鐵定不記得了(總共也就2年經驗),但是說了一下實現思路

canvas 裡有很多小球時如何優化效能

答:不知道

微信小程式跳轉頁面最多能跳轉多少層 不會

RN中listview 的key值的實現原理 不會

然後還問了一些關於專案上的問題,以及如何設計一個搜尋元件,需要考慮到哪些問題。 應該就這些,沒想起來的想起來再補充,感覺答的不好,很多都不記得了。 三分之一的題目 比如實現原理啊,缺點啊,為什麼啊,會有什麼問題啊,此類問題要麼不會,要麼答的不好 總共就這麼多,我要繼續鞏固基礎了~!!!!!!!

金三銀四,看見大家都在為了面試而努力 特開了一個前端模擬面試題,組織了面試的群友每天來群裡分享面試題,講題 急思眾議,共同進步,歡迎最近在面試或者準備面試的群友加入本群,加群格式: 工作年限-面試等級(初、中、高)-工作地點 (不在面試或者不準備面試或者不活躍的勿加本群,加了也會被清理)

刷   攜程 地面業務 前端面試經歷

相關文章