1. 程式人生 > >前端開發面試題之 JavaScript

前端開發面試題之 JavaScript


“每18至24個月,前端都會難一倍”

——赫門 “2015深JS大會《前端服務化之路》主題演講”

知識點

資料型別運算物件function繼承閉包作用域原型鏈事件RegExpJSONAjaxDOMBOM記憶體洩漏跨域非同步載入模板引擎前端MVC前端MVVM路由模組化CanvasjQueryECMAScript 2015(ES6)Node.jsAngularJSReactCommonJSAMDCMD ......

題目&答案

  • 介紹一下 JS 的基本資料型別。
    UndefinedNull、Boolean、NumberString
  • 介紹一下 JS 有哪些內建物件。
    Object 是 JavaScript 中所有物件的父物件
    資料封裝類物件:ObjectArrayBooleanNumberString
    其他物件:Function、Argument、MathDateRegExpError
  • 列舉幾條 JavaScript 的基本程式碼規範。
    1)不要在同一行宣告多個變數
    (2)如果你不知道陣列的長度,使用 push
    (3)請使用 ===/!== 來比較 true/false 或者數值
    (4)對字串使用單引號 ''(因為大多時候我們的字串。特別html會出現")
    (5)使用物件字面量替代 new Array 這種形式
    (6)絕對不要在一個非函式塊裡宣告一個函式,把那個函式賦給一個變數。瀏覽器允許你這麼做,但是它們解析不同
    (7)不要使用全域性函式
    (8)總是使用 var 來宣告變數,如果不這麼做將導致產生全域性變數,我們要避免汙染全域性名稱空間
    (9)Switch 語句必須帶有 default 分支
    (10)使用 /**...*/ 進行多行註釋,包括描述,指定型別以及引數值和返回值
    (11)函式不應該有時候有返回值,有時候沒有返回值
    (12)語句結束一定要加分號
    (13)for 迴圈必須使用大括號
    (14)if 語句必須使用大括號
    (15)for-in 迴圈中的變數應該使用 var 關鍵字明確限定作用域,從而避免作用域汙染
    (16)避免單個字元名,讓你的變數名有描述意義
    (17)當命名物件、函式和例項時使用駝峰命名規則
    (18)給物件原型分配方法,而不是用一個新的物件覆蓋原型,覆蓋原型會使繼承出現問題
    (19)當給事件附加資料時,傳入一個雜湊而不是原始值,這可以讓後面的貢獻者加入更多資料到事件資料裡,而不用找出並更新那個事件的事件處理器
  • 介紹一下 JavaScript 原型,原型鏈,它們有何特點?
    每個物件都會在其內部初始化一個屬性,就是prototype(原型),當我們訪問一個物件的屬性時,如果這個物件內部不存在這個屬性,那麼他就會去prototype裡找這個屬性,這個prototype又會有自己的prototype,
    於是就這樣一直找下去,也就是我們平時所說的原型鏈的概念。
    關係:instance.constructor.prototype = instance.__proto__
    //
    特點:JavaScript物件是通過引用來傳遞的,我們建立的每個新物件實體中並沒有一份屬於自己的原型副本,當我們修改原型時,與之相關的物件也會繼承這一改變。
    //
    當我們需要一個屬性時,JavaScript引擎會先看當前物件中是否有這個屬性,如果沒有的話,就會查詢它的prototype物件是否有這個屬性,如此遞推下去,一致檢索到Object內建物件。 function Func(){} Func.prototype.name = "Xiaosong"; Func.prototype.getInfo = function() { return this.name; } var person = new Func(); console.log(person.getInfo()); //"Xiaosong" console.log(Func.prototype); //Func { name = "Xiaosong", getInfo = function() }
  • JavaScript 有幾種型別的值?能否畫一下它們的記憶體圖?
    棧:原始資料型別(UndefinedNull,Boolean,NumberString)
    堆:引用資料型別(物件、陣列、函式)
    兩種型別的區別:儲存位置不同
    //
    原始資料型別直接儲存在棧(stack)中的簡單資料段,佔據空間小、大小固定,屬於被頻繁使用資料,所以放入棧中儲存;
    引用資料型別儲存在堆(heap)中的物件,佔據空間大、大小不固定,如果儲存在棧中,將會影響程式執行的效能;引用資料型別在棧中儲存了指標,該指標指向堆中該實體的起始地址。當直譯器尋找引用值時,會首先檢索其在棧中的地址,取得地址後從堆中獲得實體。
  • JavaScript 如何實現繼承?
    (1)構造繼承
    (2)原型繼承
    (3)例項繼承
    (4)拷貝繼承
    //
    原型prototype機制或apply和call方法去實現較簡單,建議使用建構函式與原型混合方式。
    function Parent() {
      this.name = 'song';
    }
    function Child() {
      this.age = 28;
    }
    Child.prototype = new Parent(); //通過原型,繼承了Parent
    //
    var demo = new Child()l;
    alert(demo.age);
    alert(demo.name); //得到被繼承的屬性
  • JavaScript 有哪幾種建立物件的方式?
    javascript建立物件簡單的說,無非就是使用內建物件或各種自定義物件,當然還可以用JSON;但寫法有很多種,也能混合使用。
    //
    (1)物件字面量的方式
    person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};
    (2)用function來模擬無參的建構函式
    function Person(){}
    var person = new Person(); //定義一個function,如果使用new"例項化",該function可以看作是一個Class
    person.name = "Xiaosong";
    person.age = "23";
    person.work = function() {
      alert("Hello " + person.name);
    }
    person.work();
    (3)用function來模擬參建構函式來實現(用this關鍵字定義構造的上下文屬性)
    function Person(name,age,hobby) {
      this.name = name; //this作用域:當前物件
      this.age = age;
      this.work = work;
      this.info = function() {
          alert("我叫" + this.name + ",今年" + this.age + "歲,是個" + this.work);
      }
    }
    var Xiaosong = new Person("WooKong",23,"程式猿"); //例項化、建立物件
    Xiaosong.info(); //呼叫info()方法
    (4)用工廠方式來建立(內建物件)
    var jsCreater = new Object();
    jsCreater.name = "Brendan Eich"; //JavaScript的發明者
    jsCreater.work = "JavaScript";
    jsCreater.info = function() {
      alert("我是"+this.work+"的發明者"+this.name);
    }
    jsCreater.info();
    (5)用原型方式來建立
    function Standard(){}
    Standard.prototype.name = "ECMAScript";
    Standard.prototype.event = function() {
      alert(this.name+"是指令碼語言標準規範");
    }
    var jiaoben = new Standard();
    jiaoben.event();
    (6)用混合方式來建立
    function iPhone(name,event) {
      this.name = name;
      this.event = event;
    }
    iPhone.prototype.sell = function() {
      alert("我是"+this.name+",我是iPhone5s的"+this.event+"~ haha!");
    }
    var SE = new iPhone("iPhone SE","官方翻新機");
    SE.sell();
  • eval 是做什麼的?
    它的功能是把對應的字串解析成JS程式碼並執行;
    應該避免使用eval,因為不安全,非常耗效能(2次,一次解析成js語句,一次執行)。
  • 什麼是 document 物件?什麼是 window 物件?
  • null 和 undefined 有何區別?
    null        表示一個物件被定義了,值為“空值”;
    undefined   表示不存在這個值。
    //
    typeof undefined
      //"undefined"
      undefined :是一個表示"無"的原始值或者說表示"缺少值",就是此處應該有一個值,但是還沒有定義。當嘗試讀取時會返回 undefined; 
      例如變數被聲明瞭,但沒有賦值時,就等於undefined//
    typeof null
      //"object"
      null : 是一個物件(空物件, 沒有任何屬性和方法);
      例如作為函式的引數,表示該函式的引數不是物件;
    //
    注意:
      在驗證null時,一定要使用 === ,因為 == 無法分別 null 和 undefined
  • 能否寫一個通用的事件偵聽器函式?
    //Event工具集,from:github.com/markyun
    markyun.Event = {
      //頁面載入完成後
      readyEvent: function(fn) {
          if (fn == null) {
              fn = document;
          }
          var oldonload = window.onload;
          if (typeof window.onload != 'function') {
              window.onload = fn;
          }else{
              window.onload = function() {
                  oldonload();
                  fn();
              };
          }
      },
      //視能力分別使用 demo0 || demo1 || IE 方式來繫結事件
      //引數:操作的元素,事件名稱,事件處理程式
      addEvent: function(element,type,handler) {
          if (element.addEventListener) {
              //事件型別、需要執行的函式、是否捕捉
              element.addEventListener(type,handler,false);
          }else if (element.attachEvent) {
              element.attachEvent('on' + type, function() {
                  handler.call(element);
              });
          }else {
              element['on' + type] = handler;
          }
      },
      //移除事件
      removeEvent: function(element,type,handler) {
          if (element.removeEventListener) {
              element.removeEventListener(type,handler,false);
          }else if (element.datachEvent) {
              element.datachEvent('on' + type,handler);
          }else{
              element['on' + type] = null;
          }
      },
      //阻止事件(主要是事件冒泡,因為IE不支援事件捕獲)
      stopPropagation: function(ev) {
          if (ev.stopPropagation) {
              ev.stopPropagation();
          }else {
              ev.cancelBubble = true;
          }
      },
      //取消事件的預設行為
      preventDefault: function(event) {
          if (event.preventDefault) {
              event.preventDefault();
          }else{
              event.returnValue = false;
          }
      },
      //獲取事件目標
      getTarget: function(event) {
          return event.target || event.srcElemnt;
      },
      //獲取event物件的引用,取到事件的所有資訊,確保隨時能使用event;
      getEvent: function(e) {
          var ev = e || window.event;
          if (!ev) {
              var c = this.getEvent.caller;
              while(c) {
                  ev = c.argument[0];
                  if (ev && Event == ev.constructor) {
                      break;
                  }
                  c = c.caller;
              }
          }
          retrun ev;
      }
    };
  • ["1","2","3"].map(parseInt) 的答案是多少?
    [1,NaN,NaN]
    因為 parseInt 需要兩個引數(val,radix),其中 radix 表示解析時用的基數。
    map 傳了3個(element,index,array),對應的 radix 不合法導致解析失敗。
  • 事件是什麼?IE與火狐的事件機制有何區別?如何阻止冒泡?
    (1)我們在網頁中的某個操作(有的操作對應多個事件)。例如:當我們點選一個按鈕就會產生一個事件。是可以被 JavaScript 偵測到的行為。
    (2)事件處理機制:IE是事件冒泡、Firefox同時支援兩種事件模型,也就是:捕獲型事件和冒泡型事件;
    (3)ev.stopPropagation();(舊ie的方法 ev.cancelBubble = true;)
  • 什麼是閉包(closure),為什麼要用它?
    閉包是指有權訪問另一個函式作用域中變數的函式,建立閉包的最常見的方式就是在一個函式內建立另一個函式,通過另一個函式訪問這個函式的區域性變數,利用閉包可以突破作用鏈域,將函式內部的變數和方法傳遞到外部。
    //
    閉包特性:
    (1)函式內再巢狀函式
    (2)內部函式可以引用外層的引數和變數
    (3)引數和變數不會被垃圾回收機制回收
    //li節點的onclick事件都能正確的彈出當前被點選的li索引
    <ul>
      <li> index = 0 </li>
      <li> index = 1 </li>
      <li> index = 2 </li>
      <li> index = 3 </li>
    </ul>
    <script type="text/javascript">
      var nodes = document.getElementsByTagName('li');
      for(i = 0;i<nodes.length;i+=1) {
          nodes[i].onclick = function() {
              console.log(i+1); //不使用閉包的話,值每次都是4
          }(4);
      }
    </script>
  • JavaScript 程式碼中的 "use strict"; 是什麼意思?使用它的區別是什麼?
    use strict是一種ECMAscript 5 新增的(嚴格)執行模式,這種模式使得 Javascript 在更嚴格的條件下執行,使JS編碼更加規範化的模式,消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行為。
    預設支援的糟糕特性都會被禁用,比如不能用with,也不能在意外的情況下給全域性變數賦值;
    全域性變數的顯示宣告,函式必須宣告在頂層,不允許在非函式程式碼塊內宣告函式,arguments.callee也不允許使用;
    消除程式碼執行的一些不安全之處,保證程式碼執行的安全,限制函式中的arguments修改,嚴格模式下的eval函式的行為和非嚴格模式的也不相同;
    提高編譯器效率,增加執行速度;
    為未來新版本的Javascript標準化做鋪墊。
  • new 操作符具體幹了什麼呢?
    (1)建立一個空物件,並且 this 變數引用該物件,同時還繼承了該函式的原型。
    (2)屬性和方法被加入到 this 引用的物件中。
    (3)新建立的物件由 this 所引用,並且最後隱式的返回 this//
    var obj = {};
    obj.__proto__ = Base.prototype;
    Base.call(obj);
  • 用原生的 JavaScript 實現過什麼功能嗎?
  • JavaScript 中,有一個函式,執行物件查詢時,永遠不會去查詢原型,這個函式是哪個?
    hasOwnProperty
    //
    JavaScript 中 hasOwnProperty 函式方法是返回一個布林值,指出一個物件是否具有指定名稱的屬性。此方法無法檢查該物件的原型鏈中是否具有該屬性;該屬性必須是物件本身的一個成員。
    //
    使用方法:
    object.hasOwnProperty(proName)
    其中引數object是必選項,一個物件的例項。
    proName是必選項,一個屬性名稱的字串值。
    //
    如果 object 具有指定名稱的屬性,那麼JavaScript中hasOwnProperty函式方法返回 true,反之則返回 false。
  • 你對 JSON 瞭解嗎?
    JSON(JavaScript Object Notation)是一種輕量級的資料交換格式。
    它是基於JavaScript的一個子集。資料格式簡單,易於讀寫,佔用頻寬小。
    如:
    {"age":"12", "name":"back"}
  • js延遲載入的方式有哪些?
    defer和async、動態建立DOM方式(用得最多)、按需非同步載入js
  • Ajax 是什麼?如何建立一個 Ajax ?
    ajax的全稱:Asynchronous Javascript And XML。
    非同步傳輸+js+xml。
    所謂非同步,在這裡簡單地解釋就是:向伺服器傳送請求的時候,我們不必等待結果,而是可以同時做其他的事情,等到有了結果它自己會根據設定進行後續操作,與此同時,頁面是不會發生整頁重新整理的,提高了使用者體驗。
    //
    (1)建立XMLHttpRequest物件,也就是建立一個非同步呼叫物件
    (2)建立一個新的HTTP請求,並指定該HTTP請求的方法、URL及驗證資訊
    (3)設定響應HTTP請求狀態變化的函式
    (4)傳送HTTP請求
    (5)獲取非同步呼叫返回的資料
    (6)使用JavaScript和DOM實現區域性重新整理
  • 同步和非同步的區別?
    同步的概念應該是來自於作業系統中關於同步的概念:
    不同程序為協同完成某項工作而在先後次序上調整(通過阻塞,喚醒等方式)。同步強調的是順序性,誰先誰後;非同步則不存在這種順序性。
    //
    同步:瀏覽器訪問伺服器請求,使用者看得到頁面重新整理,重新發請求,等請求完,頁面重新整理,新內容出現,使用者看到新內容,進行下一步操作。
    //
    非同步:瀏覽器訪問伺服器請求,使用者正常操作,瀏覽器後端進行請求。等請求完,頁面不重新整理,新內容也會出現,使用者看到新內容。
  • 如何解決跨域問題?
    jsonp、iframe、window.name、window.postMessage、伺服器上設定代理頁面
  • 頁面編碼和被請求的資源編碼如果不一致如何處理?
  • 談一談你對 ECMAScript6 的瞭解?
    ECMAScript 6 是JavaScript語言的下一代標準,已經在20156月正式釋出了。它的目標,是使得JavaScript語言可以用來編寫複雜的大型應用程式,成為企業級開發語言。
    標準的制定者有計劃,以後每年釋出一次標準,使用年份作為標準的版本。因為當前版本的ES6是在2015年釋出的,所以又稱ECMAScript 2015。也就是說,ES6就是ES2015
  • ECMAScript 6 怎麼寫 class ,為何會出現 class?
    ES6的class可以看作只是一個語法糖,它的絕大部分功能,ES5都可以做到,新的class寫法只是讓物件原型的寫法更加清晰、更像面向物件程式設計的語法而已。
    //定義類
    class Point {
      constructor(x,y) {  //構造方法
          this.x = x;  //this關鍵字代表例項物件
          this.y = y;
      }
      toString() {
          return '(' + this.x + ',' + this.y + ')';
      }
    }
  • 非同步載入 JS 的方式有哪些?
    (1)defer,只支援 IE
    (2)async:
    (3)建立 script,插入到 DOM 中,載入完畢後 callBack
  • document.write 和 innerHTML 有何區別?
    document.write 只能重繪整個頁面
    innerHTML 可以重繪頁面的一部分
  • DOM 操作——怎樣新增、移除、移動、複製、建立和查詢節點?
    (1)建立新節點
    createDocumentFragment()    //建立一個DOM片段
    createElement()   //建立一個具體的元素
    createTextNode()   //建立一個文字節點
    (2)新增、移除、替換、插入
    appendChild()
    removeChild()
    replaceChild()
    insertBefore() //在已有的子節點前插入一個新的子節點
    (3)查詢
    getElementsByTagName()    //通過標籤名稱
    getElementsByName()    //通過元素的Name屬性的值(IE容錯能力較強,會得到一個數組,其中包括id等於name值的)
    getElementById()    //通過元素Id,唯一性
  • 陣列和物件有哪些原生方法?能否列舉一下?
  • 哪些操作會造成記憶體洩漏?
    記憶體洩漏是指任何物件在您不再擁有或需要它之後任然存在。
    垃圾回收器定期掃描物件,並計算引用了每個物件的其他物件的數量,如果一個物件的引用數量為0(沒有其他物件引用過該物件),或對該物件的惟一引用是迴圈的,那麼該物件的記憶體即可回收。
    //
    setTimeout 的第一個引數使用字串而非函式的話,會引發記憶體洩漏。
    閉包、控制檯日誌、迴圈(在兩個物件彼此引用且彼此保留時,就會產生一個迴圈)
  • 是否看過 jQuery 的原始碼?能否簡單概括一下它的實現原理?
  • jQuery.fn 的 init 方法返回的 this 指的是什麼物件?為什麼要返回 this ?
  • jQuery 中如何將陣列轉化為 json 字串,然後再轉化回來?
    jQuery 中沒有提供這個功能,所以需要先編寫兩個 jQuery 的擴充套件:
    $.fn.stringifyArray = function(array) {
      return JSON.stringify(array)
    }
    $.fn.parseArray = function(array) {
      return JSON.parse(array)
    }
    //
    然後呼叫:
    $("").stringifyArray(array)
  • jQuery 的屬性拷貝(extend)的實現原理是什麼?如何實現深拷貝?
  • jQuery.extend 與 jQuery.fn.extend 有何區別?
  • jQuery 的佇列是如何實現的?佇列可以用在哪些地方?
  • jQuery 中一個物件可以同時繫結多個事件,這是如何實現的?
  • 是否瞭解針對 jQuery 效能的優化方法?
    基於Class的選擇性的效能相對於Id選擇器開銷很大,因為需遍歷所有DOM元素。
    //
    頻繁操作的DOM,先快取起來再操作。用Jquery的鏈式呼叫更好。
    比如:var str=$("a").attr("href");
    //
    for (var i = size; i < arr.length; i++) {}
    for 迴圈每一次迴圈都查找了陣列 (arr) 的.length 屬性,在開始迴圈的時候設定一個變數來儲存這個數字,可以讓迴圈跑得更快:
    for (var i = size, length = arr.length; i < length; i++) {}
  • jQuery 與 jQuery UI 有何區別?
    `jQuery`是一個js庫,主要提供的功能是選擇器,屬性修改和事件繫結等等。
    `jQuery UI`則是在jQuery的基礎上,利用jQuery的擴充套件性,設計的外掛。提供了一些常用的介面元素,諸如對話方塊、拖動行為、改變大小行為等等
  • jQuery UI 如何自定義元件?
  • 如何判斷當前指令碼執行在瀏覽器還是 node 環境中?(阿里)
    通過判斷 Global 物件是否為 window ,如果不為 window ,當前指令碼沒有執行在瀏覽器中
  • 什麼是“前端路由”?什麼時候適合使用“前端路由”?“前端路由”有哪些優點和缺點?
  • 怎樣用js實現千位分隔符?
    正則 + replace
    function commafy(num) {
      num = num + '';
      var reg = /(-?d+)(d{3})/;
      if (reg.test(num)) {
          num = num.replace(reg, '$1,$2');
      }
      return num;
    }
  • 檢測瀏覽器版本有哪些方式?
    功能檢測、userAgent 特徵檢測
    比如:navigator.userAgent
    //"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36"
  • 前端 MVC、MVVM
    1、MVC

    MVC
    模型(Model):資料儲存
    檢視(View):使用者介面
    控制器(Controller):業務邏輯
    (1)View 傳送指令到 Controller
    (2)Controller 完成業務邏輯後,要求 Model 改變狀態
    (3)Model 將新的資料傳送到 View ,使用者得到反饋
    所有通訊都是單向的。
    2、MVVM

    MVVM
    模型(Model)
    檢視(View)
    檢視模型(ViewModel)
    (1)各部分間都是雙向通訊
    (2)View 與 Model 不發生聯絡,都通過 ViewModel 傳遞
    (3)View 非常薄,不部署任何業務邏輯,稱為“被動檢視”(Passive View),即沒有任何主動性;而 ViewModel 非常厚,所有邏輯都部署在那裡
    採用雙向繫結(data-binding):View 的變動,自動反映在 ViewModel ,反之亦然。


文/曉鬆(簡書作者)
原文連結:http://www.jianshu.com/p/05d84b60a1dc
著作權歸作者所有,轉載請聯絡作者獲得授權,並標註“簡書作者”。