1. 程式人生 > >【前端面試】js基礎

【前端面試】js基礎

目錄

變數提升

  • js的基本型別有哪些?引用型別有哪些?

基本型別:Undefined(宣告沒有初始化)、Null(沒有宣告,不存在)、String、Number、Boolean  (變數存放在棧區)

引用型別:object、Array、RegExp(正則表示式)、Date、Function、特殊的基本包裝型別(String、Number、Boolean)以及單體內建物件(Global、Math)。(同時儲存在棧記憶體和堆記憶體)

區別聯絡:引用型別可以新增屬性和方法; 在複製變數值時,基本型別會在變數物件上建立一個新值,再複製給新變數。此後,兩個變數的任何操作都不會影響到對方;而引用型別是將儲存在變數物件的值複製一份給新變數,但是兩個變數的值都指向儲存在堆中的一個物件,也就是說,其實他們引用了同一個物件,改變其中一個變數就會影響到另一個變數。

  • 如何判斷一個變數是Array型別?如何判斷一個變數是Number型別?(都不止一種)

typeof可以判斷 number   string    boolean   undefined,對於[ ]、null、{ }輸出都為object,所以要判斷array不能使用typeof;

Object.prototype.toString.call 這是object原生原型的一個擴充套件函式,可以精確物件型別例如Object.prototype.toString.call('[ ]')輸出就是[object Array];   Object.prototype.toString.call('{ }')輸出是[object Object]

constructor也可以判斷資料型別,[].constructor輸出就是Array

  • JS常見的dom操作api

節點查詢:document.getElementById(根據id查詢元素,大小寫敏感) 、document.getElementsByTagName (根據標籤查詢元素,*表示查詢所有標籤,返回一個HTMLCollection)、document.getElementsByName(根據元素的name屬性查詢)、document.getElementsByClassName(根據類名查詢)、document.querySelector(返回單個Node,如果匹配到多個結果,返回第一個)、document.querySelectorAll(返回一個NodeList) 、document.forms(獲取當前頁面所有的form)等

節點建立:   createElement (通過 createElement 建立的元素並不屬於 document 物件,它只是創建出來,並未新增到html文件中,要呼叫 appendChild 或 insertBefore 等方法將其新增到HTML文件中)、 createTextNode 、 cloneNode(接收一個bool引數,用來表示是否複製子元素) 和 createDocumentFragment (建立一個 DocumentFragment ,也就是文件碎片,它表示一種輕量級的文件,主要是用來儲存臨時節點,大量操作DOM時用它可以大大提升效能)

節點修改:appendChild 、insertBefore 、removeChild 、replaceChild

節點關係:parentNode 、children 、childNodes 、firstChild  、lastChild 、previousSibling、nextSibling 、 nextElementSibling

元素屬性:setAttribute、getAttribute

元素樣式:window.getComputedStyle(通過 element.sytle.xxx 只能獲取到內聯樣式,藉助 window.getComputedStyle 可以獲取應用到元素上的所有樣式,IE8或更低版本不支援此方法。)、getBoundingClientRect(用來返回元素的大小以及相對於瀏覽器可視視窗的位置)

  • 解釋一下事件冒泡和事件捕獲,如何阻止冒泡?如何阻止預設事件?

事件冒泡:從事件的目標開始往上冒泡,直到頁面的最上一級標籤;通俗來講就是,就是當設定了多個div的巢狀時;即建立了父子關係,當父div與子div共同加入了onclick事件時,當觸發了子div的onclick事件後,子div進行相應的js操作,但是父div的onclick事件同樣會被觸發。 可以通過event.stopPropagation();方法阻止時間冒泡。

事件捕獲:從最上一級開始往下查詢,直到捕獲到事件目標

程式設計師可以自己選擇繫結事件時採用事件捕獲還是事件冒泡,方法就是繫結事件時通過addEventListener函式,它有三個引數,第三個引數若是true,則表示採用事件捕獲,若是false,則表示採用事件冒泡。例:

ele.addEventListener('click',doSomething2,true)     //true=捕獲     false=冒泡

  • 事件委託(手寫例子)

事件委託:利用事件冒泡,只指定一個事件處理程式,就可以管理某一型別的所有事件。

優點:在JavaScript中,新增到頁面上的事件處理程式數量將直接關係到頁面的整體執行效能,因為需要不斷的與dom節點進行互動,訪問dom的次數越多,引起瀏覽器重繪與重排的次數也就越多,就會延長整個頁面的互動就緒時間,這就是為什麼效能優化的主要思想之一就是減少DOM操作的原因;如果要用事件委託,就會將所有的操作放到js程式裡面,與dom的操作就只需要互動一次,這樣就能大大的減少與dom的互動次數,提高效能;

例:

<ul id="ul1">
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li>
</ul>


window.onload = function(){
  var oUl = document.getElementById("ul1");
  oUl.onclick = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    if(target.nodeName.toLowerCase() == 'li'){
        	alert(123);
         alert(target.innerHTML);
    }
  }
}
  • 對閉包的理解?什麼時候構成閉包?閉包的實現方法?閉包的優缺點?

閉包就是函式的區域性變數集合,只是這些區域性變數在函式返回後會繼續存在;

在函式內部定義一個函式就會產生閉包。

閉包的最大用處有兩個,一個是讀取函式內部的變數,另一個就是讓這些變數的值始終保持在記憶體中。

由於閉包會使得函式中的變數都被儲存在記憶體中,記憶體消耗很大,所以不能濫用閉包,否則會造成網頁的效能問題,在IE中可能導致記憶體洩露。解決方法是,在退出函式之前,將不使用的區域性變數全部刪除。

  • this有哪些使用場景?跟C,Java中的this有什麼區別?如何改變this的值?

作為物件方法呼叫(this繫結到當前物件)、

作為函式呼叫(函式可以直接被呼叫,此時 this 繫結到全域性物件;但是正確的設計方式是內部函式的 this 應該繫結到其外層函式對應的物件上,為了規避這一設計缺陷,出現了變數替代的方法,約定俗成,該變數一般被命名為 that)、

作為建構函式呼叫(建構函式實際上是為了支援面向物件程式設計,要使用new呼叫,否則跟普通函式一樣)

  • call,apply,bind

call()和apply()這兩個方法第一個引數都為this指標指向的目標物件,它們的區別是第二個引數開始傳參方式不同。 
call傳參:obj,arg2,arg3 
apply傳參:obj,[arg2,arg3,…]

bind() 第一個引數為this指標指向的目標物件,bind方法執行後返回的是一個新函式

如果這個三個方法都沒有提供第一個引數或引數是this、null、undefined中的一種,那麼都將預設第一個引數為Global物件 。

  • 顯示原型和隱式原型,手繪原型鏈,原型鏈是什麼?為什麼要有原型鏈

 顯式原型:prototype       隱式原型:__proto__

在js中萬物皆物件,方法(Function)是物件,方法的原型(Function.prototype)是物件,物件具有屬性(__proto__)稱為隱式原型,物件的隱式原型指向構造該物件的建構函式的顯式原型。    方法(Function)是一個特殊的物件,除了和其他物件一樣具有__proto__屬性以外,它還有一個自己特有的原型屬性(prototype),這個屬性是一個指標,指向原型物件。原型物件也有一個屬性叫constructor,這個屬性包含一個指標,指向原建構函式。

用法:建立例項時,將例項中共享的原型放到原型物件中,讓所有例項共享這部分的屬性;想要修改所有例項繼承的屬性,修改原型物件中的屬性即可;若想修改單個例項中的屬性,重寫原型中已經存在的屬性即可,不會影響其他例項的屬性。

原型鏈:所有物件都是由它的原型物件繼承而來,而原型物件自身也是一個物件,他也有自己的原型物件,這樣層層上溯形成一個類似連結串列的結構,就是原型鏈。通過原型鏈可以實現繼承。

  • 建立物件的多種方式

動態原型模式:

function Person(name) {
  this.name = name
  if(typeof this.say != 'function') {
    Person.prototype.say = function(
    alert(this.name)
  }
}
  • 實現繼承的多種方式和優缺點

原型鏈繼承:引用型別的屬性被所有例項共享;

借用建構函式:避免了引用型別的屬性被所有例項共享;

組合繼承:原型鏈和借用建構函式的技術組合到一塊,使用原型鏈實現對原型屬性和方法的繼承,通過借用建構函式來實現對例項屬性的繼承; 融合原型鏈繼承和建構函式的優點,是 JavaScript 中最常用的繼承模式。

  • new 一個物件具體做了什麼

首先建立了一個空物件,將空物件的proto成員指向原函式物件的prototype成員物件,將F函式this指標替換成當前新物件再呼叫原函式。

  • 手寫Ajax,XMLHttpRequest

var xhr = new XMLHttpRequest();
xhr.open("GET", url, false);
xhr.onreadtstatechange = function () {
    if (xhr.readystate == 4) {
        //響應內容解析完成,可以在客戶端呼叫了
        if (xhr.status == 200) {
            //客戶端的請求成功了
            alert(xhr.responseText);
        }
    }
}
xhr.send(null);
  • 變數提升

變數提升就是把變數提升提到函式的top的地方。但是隻是提升變數的宣告,並不會把賦值也提升上來。

函式提升是把整個函式都提到前面去。在我們寫js code 的時候,我們有兩種寫法,一種是函式表示式(var foo = function foo(){}),另外一種是函式宣告方式(function foo(){})。我們需要重點注意的是,只有函式宣告形式才能被提升。

  • 舉例說明一個匿名函式的典型用例

​​​​​​​建立閉包


//通過閉包可以 返回區域性變數
function box() {
    var user = 'Lee';
    return function () {//通過匿名函式返回box()區域性變數
        return user;
};
}
alert(box()());//通過box()()來直接呼叫匿名函式返回值
 
var b = box();
  • 指出JS的宿主物件和原生物件的區別,為什麼擴充套件JS內建物件不是好的做法?有哪些內建物件和內建函式?

​​​​​​​

  • attribute和property的區別

​​​​​​​

  • document load和document DOMContentLoaded兩個事件的區別

DOMContentLoaded: DOM解析完成即觸發此事件,不等待styles, images等資源的載入;

load:依賴的資源也已載入完成;  DOMContentLoaded繫結到document,load繫結到window

我們需要給一些元素的事件繫結處理函式。但問題是,如果那個元素還沒有載入到頁面上,但是繫結事件已經執行完了,是沒有效果的。這兩個事件大致就是用來避免這樣一種情況,將繫結的函式放在這兩個事件的回撥中,保證能在頁面的某些元素載入完畢之後再繫結事件的函式。

DOM文件載入的步驟為

  1. 解析HTML結構。

  2. 載入外部指令碼和樣式表文件。

  3. 解析並執行指令碼程式碼。

  4. DOM樹構建完成。//DOMContentLoaded

  5. 載入圖片等外部檔案。

  6. 頁面載入完畢。//load

在第4步,會觸發DOMContentLoaded事件。在第6步,觸發load事件。

document.addEventListener("DOMContentLoaded", function() {
   // ...程式碼...
}, false);
 
window.addEventListener("load", function() {
    // ...程式碼...
}, false);
  • === 和 == , [] === [], undefined === undefined,[] == [], undefined == undefined

​​​​​​​== 代表相同, ===代表嚴格相同;進行雙等號比較時候: 先檢查兩個運算元資料型別,如果相同, 則進行===比較, 如果不同, 則願意為你進行一次型別轉換, 轉換成相同型別後再進行比較, 而===比較時, 如果型別不同,直接就是false.

雙等號==: 

  (1)如果兩個值型別相同,再進行三個等號(===)的比較

  (2)如果兩個值型別不同,也有可能相等,需根據以下規則進行型別轉換在比較:

    1)如果一個是null,一個是undefined,那麼相等

    2)如果一個是字串,一個是數值,把字串轉換成數值之後再進行比較

注意[] === [] 、[] == []返回均為false

  • typeof能夠得到哪些值

​​​​​​​number   string    boolean   undefined,對於[ ]、null、{ }輸出都為object;

  • 什麼是“use strict”,好處和壞處​​​​​​​

  • 函式的作用域是什麼?js 的作用域有幾種?

​​​​​​​指在函式內宣告的所有變數在函式體內始終是可見的,這就意味著變數在宣告之前已經可用了。

全域性,區域性。使用時注意變數宣告會提前

  • JS如何實現過載和多型

​​​​​​​過載:一組具有相同名字,不同引數列表的函式/方法。

實現:1.使用argumnets物件的length,判斷引數長度

           2.typeof等判斷

多型:

  • 常用的陣列api,字串api

  • 原生事件繫結(跨瀏覽器),dom0和dom2的區別?

1. DOM0級事件處理程式(屬性繫結,相容性好)

  通過javascript制定事件處理程式的傳統方式,將一個函式賦值給一個事件處理程式屬性。特點是簡單,跨瀏覽器。
        var btn = document.getElementById("btn");
             btn.onclick = function(){
             alert('cliked');
         }
 dom0級方法制定的事件處理程式被認為是元素的方法,因此這個時候事件處理程式是在元素的作用域中執行,this指向當前元素。

        btn.onclick = null;  //刪除事件處理程式

2. DOM2級事件處理程式(函式繫結,相容性不好)

DOM2級規範以一種符合邏輯的方式來標準化DOM事件,IE9,Firefox,Opera,Safari,Chrome全部已經實現了"DOM2級事件"模組的核心部分。IE8是最後一個仍然使用其專有事件系統的主要瀏覽器。

addEventListener() 事件繫結          removeEventListener()事件刪除

如果定義了兩個dom0級事件,dom0級事件會覆蓋;dom2不會覆蓋,會依次執行;dom0和dom2可以共存,不互相覆蓋,但是dom0之間依然會覆蓋。

  • 給定一個元素獲取它相對於檢視視窗的座標

  • 如何實現圖片滾動懶載入

  • js 的字串型別有哪些方法? 正則表示式的函式怎麼使用?

​​​​​​​​​​​​​​

  • 深拷貝

  • 編寫一個通用的事件監聽函式

  • web端cookie的設定和獲取

  • setTimeout和promise的執行順序

  • JavaScript 的事件流模型都有什麼?

  • navigator物件,location和history

  • js的垃圾回收機制

  • 記憶體洩漏的原因和場景

  • DOM事件的繫結的幾種方式

  • DOM事件中target和currentTarget的區別

  • typeof 和 instanceof 區別,instanceof原理

  • js動畫和css3動畫比較

  • JavaScript 倒計時(setTimeout)

  • js處理異常

  • js的設計模式知道那些

  • 輪播圖的實現,以及輪播圖元件開發,輪播10000張圖片過程

  • websocket的工作原理和機制。

  • 手指點選可以觸控的螢幕時,是什麼事件? 什麼是函式柯里化?以及說一下JS的API有哪些應用到了函式柯里化的實現?(函式柯里化一些瞭解,以及在函數語言程式設計的應用,- 最後說了一下JS中bind函式和陣列的reduce方法用到了函式柯里化。)

  • JS程式碼除錯-