37道WEB前端開發面試題之JavaScript篇章!

來源:互聯網
上載者:User

標籤:tar   怎麼   creat   orm   完成   name   函數   計數   load()   

  • ajax, 跨域, jsonp
  • 參考: 《JavaScript》進階程式設計第21章:Ajax和Comet jQuery中Ajax操作

    1. apply和call的用法和區別:

    用法:

    都能繼承另一個對象的方法和屬性,區別在於參數列表不一樣

    區別:

    Function.apply(obj, args) args是一個數組,作為參數傳給Function

    Function.call(obj, arg1, arg2,...) arg*是參數列表

    apply一個妙用: 可以將一個數組預設的轉化為一個參數列表

    舉個栗子: 有一個數組arr要push進一個新的數組中去, 如果用call的話需要把數組中的元素一個個取出來再push, 而用apply只有Array.prototype.push.apply(this, arr)

    1. bind函數的相容性

    用法:

    bind()函數會建立一個新函數, 為綁定函數。當調用這個綁定函數時,綁定函數會以建立它時傳入bind方法的第一個參數作為this,傳入bind方法的第二個以及以後的參數加上綁定函數運行時本身的參數按照順序作為原函數的參數來調用原函數.

    一個綁定函數也能使用new操作符建立對象:這種行為就像把原函數當成構造器。提供的 this 值被忽略,同時調用時的參數被提供給類比函數。

    1. 解釋下事件代理

    事件委託利用了事件冒泡, 只指定一個事件處理常式, 就可以管理某一類型的所有事件.

    例: html部分: 要點擊li彈出其id

    html部分

    <ul id="list">

    <li id="li-1">Li 2</li>

    <li id="li-2">Li 3</li>

    <li id="li-3">Li 4</li>

    <li id="li-4">Li 5</li>

    <li id="li-5">Li 6</li>

    <li id="li-6">Li 7</li>

    </ul>

    //js部分

    document.getElementById("list").addHandler("click", function(e){

    var e = e || window.event;

    var target = e.target || e.srcElement;

    if(target.nodeName.toUpperCase == "LI"){

    console.log("List item", e,target.id, "was clicked!");

    }

    });

    1. 解釋下js中this是怎麼工作的?

    this 在 JavaScript 中主要由以下五種使用情境。

    作為函數調用,this 綁定全域對象,瀏覽器環境全域對象為 window 。

    內建函式內建函式的 this 也綁定全域對象,應該綁定到其外層函數對應的對象上,這是 JavaScript的缺陷,用that替換。

    作為建構函式使用,this 綁定到新建立的對象。

    作為對象方法使用,this 綁定到該對象。

    使用apply或call調用 this 將會被顯式設定為函數調用的第一個參數。

    1. 繼承

    參考:js怎麼實現繼承?

    1. AMD vs. CommonJS?

    AMD是依賴提前載入

    CMD是依賴延時載入

    1. 什麼是雜湊表?

    雜湊表(Hash table,也叫散列表),是根據關鍵碼值(Key value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對應到表中一個位置來訪問記錄,以加快尋找的速度。這個映射函數叫做散列函數,存放記錄的數組叫做散列表。

    使用雜湊尋找有兩個步驟:

    使用雜湊函數將被尋找的鍵轉換為數組的索引。在理想的情況下,不同的鍵會被轉換為不同的索引值,但是在有些情況下我們需要處理多個鍵被雜湊到同一個索引值的情況。

    所以雜湊尋找的第二個步驟就是處理衝突。處理雜湊碰撞衝突。有很多處理雜湊碰撞衝突的方法,比如拉鏈法和線性探測法。

    元素特徵轉變為數組下標的方法就是散列法。散列法當然不止一種,下面列出三種比較常用的:

    1,除法散列法

    最直觀的一種,使用的就是這種散列法,公式: index = value % 16

    學過彙編的都知道,求模數其實是通過一個除法運算得到的,所以叫“除法散列法”。

    2,平方散列法

    求index是非常頻繁的操作,而乘法的運算要比除法來得省時(對現在的CPU來說,估計我們感覺不出來),所以我們考慮把除法換成乘法和一個位移操作。公式: index = (value * value) >> 28 (右移,除以2^28。記法:左移變大,是乘。右移變小,是除。)

    如果數值分配比較均勻的話這種方法能得到不錯的結果,但我上面畫的那個圖的各個元素的值算出來的index都是0——非常失敗。也許你還有個問題,value如果很大,value * value不會溢出嗎?答案是會的,但我們這個乘法不關心溢出,因為我們根本不是為了擷取相乘結果,而是為了擷取index。

    3,斐波那契(Fibonacci)散列法

    解決衝突的方法:

    1. 拉鏈法

    將大小為M 的數組的每一個元素指向一個條鏈表,鏈表中的每一個節點都儲存散列值為該索引的索引值對,這就是拉鏈法.

    對採用拉鏈法的雜湊實現的尋找分為兩步,首先是根據散列值找到等一應的鏈表,然後沿著鏈表順序找到相應的鍵。

    1. 線性探測法:

    使用數組中的空位解決碰撞衝突

    參考:淺談演算法和資料結構: 十一 雜湊表 雜湊表的工作原理

    1. 什麼是閉包? 閉包有什麼作用?

    閉包是指有權訪問另一個函數範圍中的變數的函數. 建立閉包常見方式,就是在一個函數內部建立另一個函數.

    作用:

    匿名自執行函數 (function (){ ... })(); 建立了一個匿名的函數,並立即執行它,由於外部無法引用它內部的變數,因此在執行完後很快就會被釋放,關鍵是這種機制不會汙染全域對象。

    緩衝, 可保留函數內部的值

    實現封裝

    實現模板

    參考: js閉包的用途

    1. 偽數組:

    什麼是偽數組:

    偽數組是能通過Array.prototype.slice 轉換為真正的數組的帶有length屬性的對象

    比如arguments對象,還有像調用getElementsByTagName,document.childNodes之類的,它們都返回NodeList對象都屬於偽數組

    我們可以通過Array.prototype.slice.call(fakeArray)將偽數組轉變為真正的Array對象: 返回新數組而不會修改原數組

    參考:偽數組

    1. undefined和null的區別, 還有undeclared:

    null表示沒有對象, 即此處不該有此值. 典型用法:

    (1) 作為函數的參數,表示該函數的參數不是對象。

    (2) 作為對象原型鏈的終點。

    ( 3 ) null可以作為空白指標. 只要意在儲存對象的值還沒有真正儲存對象,就應該明確地讓該對象儲存null值.

    undefined表示缺少值, 即此處應該有值, 但還未定義.

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

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

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

    (4)函數沒有傳回值時,預設返回undefined。

    undeclared即為被汙染的命名, 訪問沒有被聲明的變數, 則會拋出異常, 終止執行. 即undeclared是一種語法錯誤

    參考: undefined與null的區別

    1. 事件冒泡機制:

    從目標元素開始,往頂層元素傳播。途中如果有節點綁定了相應的事件處理函數,這些函數都會被一次觸發。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)來組織事件的冒泡傳播。

    1. 解釋下為什麼接下來這段代碼不是 IIFE(立即調用的函數運算式):function foo(){ }();?

    而函數定義(語句以function關鍵字開始)是不能被立即執行的,這無疑會導致文法的錯誤(SyntaxError)。當函數定義程式碼片段包裹在括弧內,使解析器可以將之識別為函數運算式,然後調用。IIFE: (function foo(){})()

    區分 (function(){})(); 和 (function(){}()); 其實兩者實現效果一樣。

    函數字面量:首先聲明一個函數對象,然後執行它。(function () { alert(1); })();

    優先運算式:由於Javascript執行運算式是從圓括弧裡面到外面,所以可以用圓括弧強制執行聲明的函數。(function () { alert(2); }());

    1. "attribute" 和 "property" 的區別是什嗎?

    DOM元素的attribute和property兩者是不同的東西。attribute翻譯為“特性”,property翻譯為“屬性”。

    attribute是一個特性節點,每個DOM元素都有一個對應的attributes屬性來存放所有的attribute節點,attributes是一個類數組的容器,說得準確點就是NameNodeMap,不繼承於Array.prototype,不能直接調用Array的方法。attributes的每個數字索引以名值對(name=”value”)的形式存放了一個attribute節點。<div class="box" id="box" gameid="880">hello</div>

    property就是一個屬性,如果把DOM元素看成是一個普通的Object對象,那麼property就是一個以名值對(name=”value”)的形式存放在Object中的屬性。要添加和刪除property和普通的對象類似。

    很多attribute節點還有一個相對應的property屬性,比如上面的div元素的id和class既是attribute,也有對應的property,不管使用哪種方法都可以訪問和修改。

    總之,attribute節點都是在HTML代碼中可見的,而property只是一個普通的名值對屬性。

    1. 請指出 document load 和 document ready 兩個事件的區別。

    document.ready和onload的區別——JavaScript文檔載入完成事件。頁面載入完成有兩種事件:

    一是ready,表示文檔結構已經載入完成(不包含圖片等非文字媒體檔案)

    二是onload,指示頁麵包含圖片等檔案在內的所有元素都載入完成。

    jQuery中$(function(){});他的作用或者意義就是:在DOM載入完成後就可以可以對DOM進行操作。一般情況先一個頁面響應載入的順序是,網域名稱解析-載入html-載入js和css-載入圖片等其他資訊。

    1. 什麼是use strict? 其好處壞處分別是什麼?

    在所有的函數 (或者所有最外層函數) 的開始處加入 "use strict"; 指令啟動strict 模式。

    "strict 模式"有兩種調用方法

    1)將"use strict"放在指令檔的第一行,則整個指令碼都將以"strict 模式"運行。如果這行語句不在第一行,則無效,整個指令碼以"正常模式"運行。如果不同模式的代碼檔案合并成一個檔案,這一點需要特別注意。

    2)將整個指令檔放在一個立即執行的匿名函數之中。

    好處

    • 消除Javascript文法的一些不合理、不嚴謹之處,減少一些怪異行為;

    • 消除代碼啟動並執行一些不安全之處,保證代碼啟動並執行安全;

    • 提高編譯器效率,增加運行速度;

    • 為未來新版本的Javascript做好鋪墊。

    壞處

    同樣的代碼,在"strict 模式"中,可能會有不一樣的運行結果;一些在"正常模式"下可以啟動並執行語句,在"strict 模式"下將不能運行

    1. 瀏覽器端的js包括哪幾個部分?

    核心( ECMAScript) , 文件物件模型(DOM), 瀏覽器物件模型(BOM)

    1. DOM包括哪些對象?

    DOM是針對HTML和XML文檔的一個API(API). DOM描繪了一個層次化的節點樹, 允許開發人員添加, 移除和修改頁面的某一部分.

    常用的DOM方法:

    getElementById(id)

    getElementsByTagName()

    appendChild(node)

    removeChild(node)

    replaceChild()

    insertChild()

    createElement()

    createTextNode()

    getAttribute()

    setAttribute()

    常用的DOM屬性

    innerHTML 節點(元素)的文本值

    parentNode 節點(元素)的父節點

    childNodes

    attributes 節點(元素)的屬性節點

    參考: HTML DOM 方法

    1. js有哪些基本類型?

    Undefined, Null, Boolean, Number, String

    Object是複雜資料類型, 其本質是由一組無序的名值對組成的.

    1. 基本類型與參考型別有什麼區別?

    基本類型如上題所示. 參考型別則有: Object, Array, Date, RegExp, Function

    儲存

    基本類型值在記憶體中佔據固定大小的空間,因此被儲存在棧記憶體中

    參考型別的值是對象, 儲存在堆記憶體中. 包含參考型別的變數實際上包含的並不是對象本身, 而是一個指向改對象的指標

    複製

    從一個變數向另一個變數複製基本類型的值, 會建立這個值的一個副本

    從一個變數向另一個變數複製參考型別的值, 複製的其實是指標, 因此兩個變數最終都指向同一個對象

    檢測類型

    確定一個值是哪種基本類型可以用typeof操作符,

    而確定一個值是哪種參考型別可以使用instanceof操作符

    1. 關於js的垃圾收集常式

    js是一門具有自動記憶體回收機制的程式設計語言,開發人員不必關心記憶體配置和回收問題

    離開範圍的值將被自動標籤為可以回收, 因此將在垃圾收集期間被刪除

    "標記清除"是目前主流的垃圾收集演算法, 這種演算法的思路是給當前不使用的值加上標記, 然後再回收其記憶體

    另一種垃圾收集演算法是"引用計數", 這種演算法的思想是追蹤記錄所有值被引用的次數. js引擎目前都不再使用這種演算法, 但在IE中訪問非原生JS對象(如DOM元素)時, 這種演算法仍然可能會導致問題

    當代碼中存在循環參考現象時, "引用計數" 演算法就會導致問題

    解除變數的引用不僅有助於消除循環參考現象, 而且對垃圾收集也有好處. 為了確保有效地回收記憶體, 應該及時解除不再使用的全域對象, 全域對象屬性以及循環參考變數的引用

    1. ES5中, 除了函數,什麼能夠產生範圍?

    try-catch 和with延長範圍. 因為他們都會建立一個新的變數對象.

    這兩個語句都會在範圍鏈的前端添加一個變數對象. 對with語句來說, 會將指定的對象添加到範圍鏈中. 對catch語句來說, 會建立一個新的變數對象, 其中包含的是被拋出的錯誤對象的聲明.

    當try代碼塊中發生錯誤時,執行過程會跳轉到catch語句,然後把異常對象推入一個可變對象共置於範圍的頭部。在catch代碼塊內部,函數的所有局部變數將會被放在第二個範圍鏈對象中。請注意,一旦catch語句執行完畢,範圍鏈機會返回到之前的狀態。try-catch語句在代碼調試和異常處理中非常有用,因此不建議完全避免。你可以通過最佳化代碼來減少catch語句對效能的影響。一個很好的模式是將錯誤委託給一個函數處理

    with(object) {statement}。它的意思是把object添加到範圍鏈的頂端

    //程式碼片段

    function buildUrl(){

    var qs = "?debug=true";

    //with接收location對象, 因此其變數對象中就包含了location對象的所有屬性和方法, 而這個變數對象被添加到了範圍鏈的前端

    with(location){

    //這裡的href其實是location.href. 建立了一個名為url的變數, 就成了函數執行環境的一部分

    var url = href + qs;

    }

    return url;

    }

    參考: js try、catch、finally語句還有with語句 JavaScript 開發進階:理解 JavaScript 範圍和範圍鏈

    1. js有幾種函數調用方式?

    方法調用模型 var obj = { func : function(){};} obj.func()

    函數調用模式  var func = function(){} func();

    構造器調用模式

    apply/ call調用模式

    1. 描述事件模型?IE的事件模型是怎樣的?事件代理是什嗎?事件代理中怎麼定位實際事件產生的目標?

    捕獲->處於目標->冒泡,IE應該是只有冒泡沒有捕獲。

    事件代理就是在父元素上綁定事件來處理,通過event對象的target來定位。

    1. js動畫有哪些實現方法?

    用定時器 setTimeout和setInterval

    1. 還有什麼實現動畫的方法?

    js動畫:

    使用定時器 setTimeout和setInterval

    CSS : transition , animation

    transition 包含4種屬性:transition-delaytransition-durationtransition-propertytransition-timing-function,對應動畫的4種屬性: 延遲、期間、對應css屬性和easing 函式,

    transform 包含7種屬性:animation-nameanimation-durationanimation-timing-functionanimation-delayanimation-directionanimation-iteration-countanimation-fill-modeanimation-play-state,它們可以定義動畫名稱,期間,easing 函式,動畫延遲,動畫方向,重複次數,填充模式。

    HTML5 動畫

    canvas

    svg

    webgl

    參考:前端動畫效果實現的簡單比較

    1. 物件導向有哪幾個特點?

    封裝, 繼承, 多態

    1. 如何判斷屬性來自自身對象還是原型鏈?

    hasOwnPrototype

    1. ES6新特性

    1) 箭頭操作符 inputs=>outputs: 操作符左邊是輸入的參數,而右邊則是進行的操作以及返回的值

    2) 支援類, 引入了class關鍵字. ES6提供的類實際上就是JS原型模式的封裝

    3) 增強對象字面量.

    1. 可以在對象字面量中定義原型 proto: xxx //設定其原型為xxx,相當於繼承xxx

    2. 定義方法可以不用function關鍵字

    3. 直接調用父類方法

    4) 字串模板: ES6中允許使用反引號 ` 來建立字串,此種方法建立的字串裡面可以包含由貨幣符號加花括弧包裹的變數${vraible}。

    5) 自動解析數組或對象中的值。比如若一個函數要返回多個值,常規的做法是返回一個對象,將每個值做為這個對象的屬性返回。但在ES6中,利用解構這一特性,可以直接返回一個數組,然後數組中的值會自動被解析到對應接收該值的變數中。

    6) 預設參數值: 現在可以在定義函數的時候指定參數的預設值了,而不用像以前那樣通過邏輯或操作符來達到目的了。

    7) 不定參數是在函數中使用具名引數同時接收不定數量的未具名引數。在以前的JavaScript代碼中我們可以通過arguments變數來達到這一目的。不定參數的格式是三個句點後跟代表所有不定參數的變數名。比如下面這個例子中,…x代表了所有傳入add函數的參數。

    8) 拓展參數則是另一種形式的文法糖,它允許傳遞數組或者類數組直接做為函數的參數而不用通過apply。

    9) let和const關鍵字: 可以把let看成var,只是它定義的變數被限定在了特定範圍內才能使用,而離開這個範圍則無效。const則很直觀,用來定義常量,即無法被更改值的變數。

    10) for of值遍曆 每次迴圈它提供的不是序號而是值。

    11) iterator, generator

    12) 模組

    13) Map, Set, WeakMap, WeakSet

    14) Proxy可以監聽對象身上發生了什麼事情,並在這些事情發生後執行一些相應的操作。一下子讓我們對一個對象有了很強的追蹤能力,同時在資料繫結方面也很有用處。

    15) Symbols Symbol 通過調用symbol函數產生,它接收一個可選的名字參數,該函數返回的symbol是唯一的。之後就可以用這個傳回值做為對象的鍵了。Symbol還可以用來建立私人屬性,外部無法直接存取由symbol做為鍵的屬性值。

    16) Math, Number, String, Object的新API

    17) Promises是處理非同步作業的一種模式

    參考:ES6新特性概覽

    1. 如何擷取某個DOM節點,節點遍曆方式

    擷取節點: getElementById() getElementsByTagName()

    節點遍曆:先序遍曆DOM樹的5種方法

    1. 用LESS如何給某些屬性加瀏覽器首碼?

    可以自訂一個函數

    //程式碼片段

    .border-radius(@values) {

    -webkit-border-radius: @values;

    -moz-border-radius: @values;

    border-radius: @values;

    }

    div {

    .border-radius(10px);

    }

    1. js非同步模式如何??

    參考:JavaScript非同步編程的Promise模式

    1. 圖片預先載入的實現

    使用jQuery圖片預先載入外掛程式Lazy Load

    1.載入jQuery, 與jquery.lazyload.js

    2.設定圖片的預留位置為data-original, 給圖片一個特別的標籤,比如class=".lazy"

    3.然後消極式載入: $(‘img.lazy‘).lazyload();這個函數可以選擇一些參數:

    3.1.圖片積極式載入距離:threshold,通過設定這個值,在圖片未出現在可視地區的頂部距離這個值時載入。

    3.2.事件綁定載入的方式:event

    3.3.圖片限定在某個容器內:container

    使用js實現圖片載入: 就是new一個圖片對象, 綁定onload函數, 賦值url

    用CSS實現圖片的預先載入

    寫一個CSS樣式設定一批背景圖片,然後將其隱藏

    改進: 使用js來延遲預先載入時間, 防止與頁面其他內容一起載入

    用Ajax實現預先載入

    其實就是通過ajax請求請求圖片地址. 還可以用這種方式載入css,js檔案等

    1. 如果在同一個元素上綁定了兩個click事件, 一個在捕獲階段執行, 一個在冒泡階段執行. 那麼當觸發click條件時, 會執行幾個事件? 執行順序是什麼?

    我在回答這個題的時候說是兩個事件, 先執行捕獲的後執行冒泡的. 其實是不對的.

    綁定在目標元素上的事件是按照綁定的順序執行的!!!!

    即: 綁定在被點擊元素的事件是按照代碼順序發生,其他元素通過冒泡或者捕獲“感知”的事件,按照W3C的標準,先發生捕獲事件,後發生冒泡事件。所有事件的順序是:其他元素捕獲階段事件 -> 本元素代碼順序事件 -> 其他元素冒泡階段事件 。

    參考: JavaScript-父子dom同時綁定兩個點擊事件,一個用捕獲,一個用冒泡時執行順序

    1. js中怎麼實現塊級範圍?

    使用匿名函數, (立即執行函數)

    (function(){...})()

    使用es6

    塊級範圍引入了兩種新的聲明形式,可以用它們定義一個只存在於某個語句塊中的變數或常量.這兩種新的聲明關鍵字為:

    let: 文法上非常類似於var, 但定義的變數只存在於當前的語句塊中

    const: 和let類似,但聲明的是一個唯讀常量

    使用let代替var可以更容易的定義一個只在某個語句塊中存在的局部變數,而不用擔心它和函數體中其他部分的同名變數有衝突.在let語句內部用var聲明的變數和在let語句外部用var聲明的變數沒什麼差別,它們都擁有函數範圍,而不是塊級範圍.

    1. 建構函式裡定義function和使用prototype.func的區別?

    2. 直接調用function,每一個類的執行個體都會拷貝這個函數,弊端就是浪費記憶體(如上)。prototype方式定義的方式,函數不會拷貝到每一個執行個體中,所有的執行個體共用prototype中的定義,節省了記憶體。

    3. 但是如果prototype的屬性是對象的話,所有執行個體也會共用一個對象(這裡問的是函數應該不會出現這個情況),如果其中一個執行個體改變了對象的值,則所有執行個體的值都會被改變。同理的話,如果使用prototype調用的函數,一旦改變,所有執行個體的方法都會改變。——不可以對執行個體使用prototype屬性,只能對類和函數用。

    4. js實現對象的深複製

    因為js中資料類型分為基礎資料型別 (Elementary Data Type)(number, string, boolean, null, undefined)和參考型別值(對象, 數組, 函數). 這兩類對象在複製複製的時候是有很大區別的. 原始類型儲存的是對象的實際資料, 而物件類型儲存的是對象的引用地址(對象的實際內容單獨存放, 為了減少資料開銷通常放在記憶體中). 此外, 對象的原型也是引用對象, 它把原型的屬性和方法放在記憶體中, 通過原型鏈的方式來指向這個記憶體位址.

    於是複製也會分為兩類:

    淺度複製:

    原始類型為值傳遞, 物件類型仍為引用傳遞

    深度複製:

    所有元素或屬性均完全複製, 與原對象完全脫離, 也就是說所有對於新對象的修改都不會反映到原對象中

    深度複製實現:

    //程式碼片段

    function clone(obj){

    if(typeof(obj)== ‘object‘){

    var result = obj instanceof Array ? [] : {};

    for(var i in obj){

    var attr = obj[i];

    result[i] = arguments.callee(attr);

    }

    return result;

    } else {

    return obj;

    }

    };

    參考: JavaScript深複製 javascript中對象的深度複製

    37道WEB前端開發面試題之JavaScript篇章!

    相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.