前端開發面試題之 JavaScript
阿新 • • 發佈:2019-02-05
“每18至24個月,前端都會難一倍”
——赫門 “2015深JS大會《前端服務化之路》主題演講”
知識點
資料型別
、運算
、物件
、function
、繼承
、閉包
、作用域
、原型鏈
、事件
、RegExp
、JSON
、Ajax
、DOM
、BOM
、記憶體洩漏
、跨域
、非同步載入
、模板引擎
、前端MVC
、前端MVVM
、路由
、模組化
、Canvas
、jQuery
、ECMAScript
2015(ES6)
、Node.js
、AngularJS
、React
、CommonJS
、AMD
、CMD
......
題目&答案
- 介紹一下 JS 的基本資料型別。
Undefined、Null、Boolean、Number、String
- 介紹一下 JS 有哪些內建物件。
Object 是 JavaScript 中所有物件的父物件 資料封裝類物件:Object、Array、Boolean、Number、String 其他物件:Function、Argument、Math、Date、RegExp、Error
- 列舉幾條 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 有幾種型別的值?能否畫一下它們的記憶體圖?
棧:原始資料型別(Undefined,Null,Boolean,Number,String) 堆:引用資料型別(物件、陣列、函式) 兩種型別的區別:儲存位置不同 // 原始資料型別直接儲存在棧(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語言的下一代標準,已經在2015年6月正式釋出了。它的目標,是使得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"
- 談談你對 JavaScript 中的模組規範 CommonJS、AMD、CMD 的瞭解?
詳細文章:淺析JS中的模組規範(CommonJS,AMD,CMD)、關於 CommonJS AMD CMD UMD//個人拙見 | CommonJS | AMD | CMD | |--------------|---------|---------| | Node.js |RequireJS| SeaJS |
- 前端 MVC、MVVM
1、MVC
MVC
2、MVVM模型(Model):資料儲存 檢視(View):使用者介面 控制器(Controller):業務邏輯 (1)View 傳送指令到 Controller (2)Controller 完成業務邏輯後,要求 Model 改變狀態 (3)Model 將新的資料傳送到 View ,使用者得到反饋 所有通訊都是單向的。
MVVM模型(Model) 檢視(View) 檢視模型(ViewModel) (1)各部分間都是雙向通訊 (2)View 與 Model 不發生聯絡,都通過 ViewModel 傳遞 (3)View 非常薄,不部署任何業務邏輯,稱為“被動檢視”(Passive View),即沒有任何主動性;而 ViewModel 非常厚,所有邏輯都部署在那裡 採用雙向繫結(data-binding):View 的變動,自動反映在 ViewModel ,反之亦然。
文/曉鬆(簡書作者)
原文連結:http://www.jianshu.com/p/05d84b60a1dc
著作權歸作者所有,轉載請聯絡作者獲得授權,並標註“簡書作者”。