2019前端面試題 | JS部分(附帶答案)

目前在找工做,因此各方收集了一堆面試題。其實刷面試題的過程也能更新本身對知識的認識,因此也提醒本身多看多理解。若是對下面題目有更深理解,會實時更新。遇到新題目,也會不定時更新。但願能幫助到部分朋友~javascript

1、各類函數方法定義及區別

1. typeof運算符和instanceof運算符以及isPrototypeOf()方法的區別

typeof是一個運算符,用於檢測數據的類型,好比基本數據類型null、undefined、string、number、boolean,以及引用數據類型object、function,可是對於正則表達式、日期、數組這些引用數據類型,它會所有識別爲object; instanceof一樣也是一個運算符,它就能很好識別數據具體是哪種引用類型。它與isPrototypeOf的區別就是它是用來檢測構造函數的原型是否存在於指定對象的原型鏈當中;而isPrototypeOf是用來檢測調用此方法的對象是否存在於指定對象的原型鏈中,因此本質上就是檢測目標不一樣。html

2.call()和apply()的區別

實際上,apply和call的功能是同樣的,只是傳入的參數列表形式不一樣。apply:最多隻能有兩個參數——新this對象和一個數組argArray。java

參考:www.cnblogs.com/lengyuehuah…面試

3.全局函數eval()有什麼做用?

eval()只有一個參數,若是傳入的參數不是字符串,它直接返回這個參數。若是參數是字符串,它會把字符串當成javascript代碼進行編譯。若是編譯失敗則拋出一個語法錯誤(syntaxError)異常。若是編譯成功,則開始執行這段代碼,並返回字符串中的最後一個表達式或語句的值,若是最後一個表達式或語句沒有值,則最終返回undefined。若是字符串拋出一個異常,這個異常將把該調用傳遞給eval()。ajax

4.描述如下變量的區別:null,undefined或undeclared

null 表示"沒有對象",即該處不該該有值,轉爲數值時爲0。典型用法是:正則表達式

(1) 做爲函數的參數,表示該函數的參數不是對象。json

(2) 做爲對象原型鏈的終點。小程序

undefined 表示"缺乏值",就是此處應該有一個值,可是尚未定義,轉爲數值時爲NaN。典型用法是:跨域

(1)變量被聲明瞭,但沒有賦值時,就等於undefined。數組

(2) 調用函數時,應該提供的參數沒有提供,該參數等於undefined。

(3)對象沒有賦值的屬性,該屬性的值爲undefined。

(4)函數沒有返回值時,默認返回undefined。

undeclared :js語法錯誤,沒有申明直接使用,js沒法找到對應的上下文。

5.==和===有什麼區別?

首先,== equality 等同,=== identity 恆等。==,兩邊值類型不一樣的時候,要先進行類型轉換,再比較。===,不作類型轉換,類型不一樣的必定不等。

先說 ===,這個比較簡單。下面的規則用來判斷兩個值是否===相等:

若是類型不一樣,就[不相等] 
若是兩個都是數值,而且是同一個值,那麼[相等];(!例外)的是,若是其中至少一個是NaN,那麼[不相等]。(判斷一個值是不是NaN,只能用isNaN()來判斷) 
若是兩個都是字符串,每一個位置的字符都同樣,那麼[相等];不然[不相等]。 
若是兩個值都是true,或者都是false,那麼[相等]。 
若是兩個值都引用同一個對象或函數,那麼[相等];不然[不相等]。 
若是兩個值都是null,或者都是undefined,那麼[相等]。 
複製代碼

再說 ==,根據如下規則: 若是兩個值類型相同,進行 === 比較。 若是兩個值類型不一樣,他們可能相等。根據下面規則進行類型轉換再比較:

若是一個是null、一個是undefined,那麼[相等]。 
若是一個是字符串,一個是數值,把字符串轉換成數值再進行比較。 
若是任一值是 true,把它轉換成 1 再比較;若是任一值是 false,把它轉換成 0 再比較。 
若是一個是對象,另外一個是數值或字符串,把對象轉換成基礎類型的值再比較。對象轉換成基礎類型,利用它的
toString或者valueOf方法。js核心內置類,會嘗試valueOf先於toString;例外的是Date,Date利用的是toString轉換。非js核心的對象,令說(比較麻煩,我也不大懂) 
任何其餘組合,都[不相等]。
複製代碼

6.同步異步?

一、進程同步:就是在發出一個功能調用時,在沒有獲得結果以前,該調用就不返回。也就是必須一件一件事作,等前一件作完了才能作下一件事 二、異步的概念和同步相對。當一個異步過程調用發出後,調用者不能馬上獲得結果。實際處理這個調用的部件在完成後,經過狀態、通知和回調來通知調用者。

2、各類概念/原理

1. 什麼是事件代理/事件委託?

事件代理/事件委託是利用事件冒泡的特性,將本應該綁定在多個元素上的事件綁定在他們的祖先元素上,尤爲在動態添加子元素的時候,能夠很是方便的提升程序性能,減少內存空間。

2.什麼是事件冒泡?什麼是事件捕獲?

冒泡型事件:事件按照從最特定的事件目標到最不特定的事件目標(document對象)的順序觸發。

捕獲型事件:事件從最不精確的對象(document 對象)開始觸發,而後到最精確(也能夠在窗口級別捕獲事件,不過必須由開發人員特別指定)。

支持W3C標準的瀏覽器在添加事件時用addEventListener(event,fn,useCapture)方法,基中第3個參數useCapture是一個Boolean值,用來設置事件是在事件捕獲時執行,仍是事件冒泡時執行。而不兼容W3C的瀏覽器(IE)用attachEvent()方法,此方法沒有相關設置,不過IE的事件模型默認是在事件冒泡時執行的,也就是在useCapture等於false的時候執行,因此把在處理事件時把useCapture設置爲false是比較安全,也實現兼容瀏覽器的效果。

3.如何阻止冒泡?

w3c的方法是e.stopPropagation(),IE則是使用e.cancelBubble = true。例如: window.event? window.event.cancelBubble = true : e.stopPropagation();

return false也能夠阻止冒泡。

4.如何阻止默認事件?

w3c的方法是e.preventDefault(),IE則是使用e.returnValue = false,好比:

function stopDefault( e ) { 
    //阻止默認瀏覽器動做(W3C) 
    if ( e && e.preventDefault ) 
        e.preventDefault(); 
    //IE中阻止函數器默認動做的方式 
    else 
        window.event.returnValue = false; 
}
複製代碼

return false也能阻止默認行爲。

5.簡述javascript中this的指向

第一準則是:this永遠指向函數運行時所在的對象,而不是函數被建立時所在的對象。

  • 普通的函數調用,函數被誰調用,this就是誰。
  • 構造函數的話,若是不用new操做符而直接調用,那即this指向window。用new操做符生成對象實例後,this就指向了新生成的對象。
  • 匿名函數或不處於任何對象中的函數指向window 。
  • 若是是call,apply等,指定的this是誰,就是誰。
  • 參考:www.cnblogs.com/beidan/p/53…

5.原生對象和宿主對象

原生對象是ECMAScript規定的對象,全部內置對象都是原生對象,好比Array、Date、RegExp等;

宿主對象是宿主環境好比瀏覽器規定的對象,用於完善是ECMAScript的執行環境,好比Document、Location、Navigator等。

6.基本數據類型和引用數據類型

基本數據類型指的是簡單的數據段,有5種,包括null、undefined、string、boolean、number;

引用數據類型指的是有多個值構成的對象,包括object、array、date、regexp、function等。

主要區別:

  • 聲明變量時不一樣的內存分配:前者因爲佔據的空間大小固定且較小,會被存儲在棧當中,也就是變量訪問的位置;後者則存儲在堆當中,變量訪問的實際上是一個指針,它指向存儲對象的內存地址。
  • 也正是由於內存分配不一樣,在複製變量時也不同。前者複製後2個變量是獨立的,由於是把值拷貝了一份;後者則是複製了一個指針,2個變量指向的值是該指針所指向的內容,一旦一方修改,另外一方也會受到影響。
  • 參數傳遞不一樣:雖然函數的參數都是按值傳遞的,可是引用值傳遞的值是一個內存地址,實參和形參指向的是同一個對象,因此函數內部對這個參數的修改會體如今外部。原始值只是把變量裏的值傳遞給參數,以後參數和這個變量互不影響。

7.深拷貝和淺拷貝

區別 www.cnblogs.com/echolun/p/7…

深拷貝的方法 www.cnblogs.com/Mrrabbit/p/…

8.解釋一下原型繼承的原理

參考:www.cnblogs.com/syfwhu/p/44…

9.解釋下爲何接下來這段代碼不是IIFE(當即調用的函數表達式):

function foo(){
    //code
}()
複製代碼

以function關鍵字開頭的語句會被解析爲函數聲明,而函數聲明是不容許直接運行的。 只有當解析器把這句話解析爲函數表達式,纔可以直接運行,怎麼辦呢?以運算符開頭就能夠了。

(function foo(){
    // code..
})()
複製代碼

10.請儘量詳盡的解釋AJAX的工做原理

ajax簡單來講是經過XmlHttpRequest對象來向服務器發異步請求,從服務器得到數據,而後用javascript來操做DOM而更新頁面。

ajax的優勢

  • 最大的一點是頁面無刷新,在頁面內與服務器通訊,給用戶的體驗很是好。
  • 使用異步方式與服務器通訊,不須要打斷用戶的操做,具備更加迅速的響應能力。
  • 能夠把之前一些服務器負擔的工做轉嫁到客戶端,利用客戶端閒置的能力來處理,減輕服務器和帶寬的負擔,節約空間和寬帶租用成本,ajax的原則是「按需取數據」,能夠最大程度的減小冗餘請求。
  • 基於標準化的並被普遍支持的技術,不須要下載插件或者小程序。

ajax的缺點

  • ajax對瀏覽器後退機制形成了破壞,也就是說用戶沒法經過瀏覽器的後退按鈕回到前一次操做的頁面。雖然有些瀏覽器解決了這個問題,好比Gmail,但它也並不能改變ajax的機制,它所帶來的開發成本是很是高的,和ajax框架所要求的快速開發是相背離的。這是ajax所帶來的一個很是嚴重的問題。
  • 安全問題。技術同時也對IT企業帶來了新的安全威脅,ajax技術就如同對企業數據創建了一個直接通道。這使得開發者在不經意間會暴露比之前更多的數據和服務器邏輯。
  • 對搜索引擎的支持比較弱。
  • 破壞了程序的異常機制。至少從目前看來,像ajax.dll,ajaxpro.dll這些ajax框架是會破壞程序的異常機制的。關於這個問題,我曾經在開發過程當中遇到過,可是查了一下網上幾乎沒有相關的介紹。後來我本身作了一次試驗,分別採用ajax和傳統的form提交的模式來刪除一條數據……給咱們的調試帶來了很大的困難。
  • 另外,像其餘方面的一些問題,好比說違背了url和資源定位的初衷。例如,我給你一個url地址,若是採用了ajax技術,也許你在該url地址下面看到的和我在這個url地址下看到的內容是不一樣的。這個和資源定位的初衷是相背離的。
  • 一些手持設備(如手機、PDA等)如今還不能很好的支持ajax,好比說咱們在手機的瀏覽器上打開採用ajax技術的網站時,它目前是不支持的,固然,這個問題和咱們沒太多關係。

11.get和post有什麼區別?

其實,GET和POST本質上二者沒有任何區別。他們都是HTTP協議中的請求方法。底層實現都是基於TCP/IP協議。所謂區別,只是瀏覽器廠家根據約定,作得限制而已。

  • get是經過明文發送數據請求,而post是經過密文;
  • get傳輸的數據量有限,由於url的長度有限,post則不受限;
  • GET請求的參數只能是ASCII碼,因此中文須要URL編碼,而POST請求傳參沒有這個限制
  • GET產生一個TCP數據包;POST產生兩個TCP數據包。對於GET方式的請求,瀏覽器會把http header和data一併發送出去,服務器響應200(返回數據);而對於POST,瀏覽器先發送header,服務器響應100 continue,瀏覽器再發送data,服務器響應200 ok(返回數據)。
  • 參考:www.cnblogs.com/logsharing/…

12.請解釋變量聲明提高

經過var聲明的變量會被提高至做用域的頂端。不只僅是變量,函數聲明也同樣會被提高。當同一做用域內同時出現變量和函數聲明提高時,變量仍然在函數前面。

參考:www.cnblogs.com/guanhuachen…

13.請指出document.onload和document.ready兩個事件的區別

頁面加載完成有兩種事件,一是ready,表示文檔結構已經加載完成(不包含圖片等非文字媒體文件),二是onload,指示頁面包含圖片等文件在內的全部元素都加載完成。

14.如何從瀏覽器的URL中獲取查詢字符串參數?

getUrlParam : function(name){
        //baidu.com/product/list?keyword=XXX&page=1
        var reg     = new RegExp('(^|&)' + name + '=([^&]*)(&|$)');
        var result  = window.location.search.substr(1).match(reg);
        return result ? decodeURIComponent(result[2]) : null;
    }
複製代碼

  • 首先設置一個函數,給這個函數傳遞一個參數,也就是url的search部分的key值;
  • 設置一個正則表達式,以&開頭或沒有,中間是參數,後面以#或&結尾或沒有;
  • 經過window.location.search.substr(1).match()匹配,返回一個數組
  • 若是數組不爲空,返回數組的第3個值,也就是正則表達式的第二個子串

15.什麼是三元表達式?「三元」表示什麼意思?

三元表達式:? :。三元--三個操做對象。

在表達式boolean-exp ? value0 : value1 中,若是「布爾表達式」的結果爲true,就計算「value0」,並且這個計算結果也就是操做符最終產生的值。若是「布爾表達式」的結果爲false,就計算「value1」,一樣,它的結果也就成爲了操做符最終產生的值。

16.JavaScript裏arguments到底是什麼?

Javascrip中國每一個函數都會有一個Arguments對象實例arguments,它引用着函數的實參,能夠用數組下標的方式"[]"引用arguments的元素。arguments.length爲函數實參個數,arguments.callee引用函數自身。

在函數代碼中,使用特殊對象arguments,開發者無需明確指出參數名,經過使用下標就能夠訪問相應的參數。

function test() {
        var s = "";
        for (var i = 0; i < arguments.length; i++) {
            alert(arguments[i]);
            s += arguments[i] + ",";
        }
        return s;
    }
    test("name", "age");//name,age
複製代碼

arguments雖然有一些數組的性質,但其並不是真正的數組,只是一個類數組對象。其並無數組的不少方法,不能像真正的數組那樣調用.jion(),.concat(),.pop()等方法。

17.什麼是"use strict";?使用它的好處和壞處分別是什麼?

在代碼中出現表達式-"use strict"; 意味着代碼按照嚴格模式解析,這種模式使得Javascript在更嚴格的條件下運行。

好處:

  • 消除Javascript語法的一些不合理、不嚴謹之處,減小一些怪異行爲;
  • 消除代碼運行的一些不安全之處,保證代碼運行的安全;
  • 提升編譯器效率,增長運行速度;
  • 爲將來新版本的Javascript作好鋪墊。

壞處:

  • 一樣的代碼,在"嚴格模式"中,可能會有不同的運行結果;
  • 一些在"正常模式"下能夠運行的語句,在"嚴格模式"下將不能運行。

18.請解釋一下JavaScript的同源策略

同源策略,即擁有相同的協議(protocol),端口(若是指定),主機(域名)的兩個頁面是屬於同一個源。 然而在IE中比較特殊,IE中沒有將端口號加入同源的條件中,所以上圖中端口不一樣那一項,在IE中是算同源的。 <script> <img> <iframe>中的src,href均可以任意連接網絡資源,是不遵循通源策略的。

19.請解釋JSONP的工做原理,以及它爲何不是真正的AJAX。

JSONP (JSON with Padding)是一個簡單高效的跨域方式,HTML中的script標籤能夠加載並執行其餘域的javascript,因而咱們能夠經過script標記來動態加載其餘域的資源。例如我要從域A的頁面pageA加載域B的數據,那麼在域B的頁面pageB中我以JavaScript的形式聲明pageA須要的數據,而後在 pageA中用script標籤把pageB加載進來,那麼pageB中的腳本就會得以執行。JSONP在此基礎上加入了回調函數,pageB加載完以後會執行pageA中定義的函數,所須要的數據會以參數的形式傳遞給該函數。JSONP易於實現,可是也會存在一些安全隱患,若是第三方的腳本隨意地執行,那麼它就能夠篡改頁面內容,截獲敏感數據。可是在受信任的雙方傳遞數據,JSONP是很是合適的選擇。

AJAX是不跨域的,而JSONP是一個是跨域的,還有就是兩者接收參數形式不同!

20.經過new建立一個對象的時候,構造函數內部有哪些改變?

function Person(){}
Person.prototype.friend = [];
Person.prototype.name = '';
var a = new Person();
a.friend[0] = '王琦';
var b = new Person();
console.log(b.friend);//Array [ "王琦" ]
複製代碼
  • 建立一個空對象,而且 this 變量引用該對象,同時還繼承了該函數的原型。
  • 屬性和方法被加入到 this 引用的對象中。
  • 新建立的對象由 this 所引用,而且最後隱式的返回 this 。

22.什麼是跨域?有什麼方法解決跨域帶來的問題?

跨域須要針對瀏覽器的同源策略來理解,同源策略指的是請求必須是同一個端口,同一個協議,同一個域名,不一樣源的客戶端腳本在沒有明確受權的狀況下,不能讀寫對方資源。

受瀏覽器同源策略的影響,不是同源的腳本不能操做其餘源下面的對象。想要操做另外一個源下的對象是就須要跨域。

解決方法: jsonp

23. 什麼是原型?

原型鏈:簡單來說就是原型組成的鏈,好比函數的原型是Function,Function的原型是Object,Object的原型仍然是Object,一直追溯到最終的原型對象。

函數經過prototype來追溯原型對象,對象經過_proto_來追溯原型對象。

經過一個構造函數建立出來的多個實例,若是都要添加一個方法,給每一個實例去添加並非一個明智的選擇。這時就該用上原型了。

在實例的原型上添加一個方法,這個原型的全部實例便都有了這個方法。

原型鏈繼承:

function Show(){
this.name="run";
}

function Run(){
this.age="20"; //Run繼承了Show,經過原型,造成鏈條
}
Run.prototype=new Show();
var show=new Run();
alert(show.name)//結果:run
複製代碼

24. 什麼是閉包?使用場景是?

閉包就是可以讀取其餘函數內部變量的函數,一般是函數嵌套時產生,它的最大用處有兩個,一個是能夠讀取函數內部的變量,另外一個就是讓這些變量的值始終保持在內存中,不會在外部函數調用後被自動清除。

25. 瞭解過Promise嗎?與回調地獄有什麼關係?

www.liaoxuefeng.com/wiki/001434…

3、關於定時器的那些事兒~(偏小白邏輯)

1.若是用戶持續點擊一個按鈕,如何只提交一次請求,且不影響後續使用?(其實就是如何節流這個真的問的好多!!!!)

何爲節流 觸發函數事件後,短期間隔內沒法連續調用,只有上一次函數執行後,過了規定的時間間隔,才能進行下一次的函數調用,通常用於http請求。

解決原理 對處理函數進行延時操做,若設定的延時到來以前,再次觸發事件,則清除上一次的延時操做定時器,從新定時。

function conso(){
          console.log('is run');
      }
      var btnUse=true;
     $("#btn").click(function(){
         if(btnUse){
             conso();
             btnUse=false;
         }
         setTimeout(function(){
             btnUse=true;
         },1500) //點擊後相隔多長時間可執行
     })
複製代碼

2.如何防抖?(通常都和節流一塊兒問,必定要搞懂!!)

何爲防抖 屢次觸發事件後,事件處理函數只執行一次,而且是在觸發操做結束時執行,通常用於scroll事件。

解決原理 對處理函數進行延時操做,若設定的延時到來以前再次觸發事件,則清除上一次的延時操做定時器,從新定時。

let timer;
window.onscroll  = function () {
    if(timer){
        clearTimeout(timer)
    }
    timer = setTimeout(function () {
        //滾動條位置
        let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
        console.log('滾動條位置:' + scrollTop);
        timer = undefined;
    },200)
}
複製代碼

或者是這樣:

function debounce(fn, wait) {
    var timeout = null;
    return function() {  
        if(timeout !== null)   clearTimeout(timeout);        
        timeout = setTimeout(fn, wait);    
    }
}
// 處理函數
function handle() {    
    console.log(Math.random()); 
}
// 滾動事件
window.addEventListener('scroll', debounce(handle, 1000));
複製代碼

2.猜猜以下題目的結果?

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  setInterval(() => this.s1++, 1000);
  setInterval(function () {
    this.s2++;
  }, 1000);
}

var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
複製代碼

答案是:

s1: 3
s2: 0
複製代碼
相關文章
相關標籤/搜索