1、 JQuery一個對象可以同時綁定多個事件,這是如何實現的?
jQuery可以給一個對象同時綁定多個事件,低層實現方式是使用addEventListner或attachEvent兼容不同的瀏覽器實現事件的綁定,這樣可以給同一個對象注冊多個事件。
2、 知道什么是webkit么? 知道怎么用瀏覽器的各種工具來調試和debug代碼么?
Webkit是瀏覽器引擎,包括html渲染和js解析功能,手機瀏覽器的主流內核,與之相對應的引擎有Gecko(Mozilla Firefox 等使用)和Trident(也稱MSHTML,IE 使用)。
對於瀏覽器的調試工具要熟練使用,主要是頁面結構分析,后台請求信息查看,js調試工具使用,熟練使用這些工具可以快速提高解決問題的效率
3、 如何測試前端代碼? 知道BDD, TDD, Unit Test么? 知道怎么測試你的前端工程么(mocha, sinon, jasmin, qUnit..)?
了解BDD行為驅動開發與TDD測試驅動開發已經單元測試相關概念,
4、前端templating(Mustache, underscore, handlebars)是干嘛的, 怎么用?
Web 模板引擎是為了使用戶界面與業務數據(內容)分離而產生的,
Mustache 是一個 logic-less (輕邏輯)模板解析引擎,它的優勢在於可以應用在 Javascript、PHP、Python、Perl 等多種編程語言中。
Underscore封裝了常用的JavaScript對象操作方法,用於提高開發效率。
Handlebars 是 JavaScript 一個語義模板庫,通過對view和data的分離來快速構建Web模板。
5、簡述一下 Handlebars 的基本用法?
沒有用過的話說出它是干什么的即可
參考:J:\代碼,PPT,筆記,電子書\面試題\handlebarDemo
6、簡述一下 Handlerbars 的對模板的基本處理流程, 如何編譯的?如何緩存的?
學習技術不僅要會用,還有熟悉它的實現機制,這樣在開發中遇到問題時才能更好的解決
7、用js實現千位分隔符?
原生js的熟練度,實踐經驗,實現思路
8、檢測瀏覽器版本版本有哪些方式?
IE與標准瀏覽器判斷,IE不同版本的判斷,userAgent var ie = /*@cc_on !@*/false;
9、我們給一個dom同時綁定兩個點擊事件,一個用捕獲,一個用冒泡,你來說下會執行幾次事件,然后會先執行冒泡還是捕獲
對兩種事件模型的理解
10、實現一個函數clone,可以對JavaScript中的5種主要的數據類型(包括Number、String、Object、Array、Boolean)進行值復制
- 考察點1:對於基本數據類型和引用數據類型在內存中存放的是值還是指針這一區別是否清楚
- 考察點2:是否知道如何判斷一個變量是什么類型的
- 考察點3:遞歸算法的設計
|
// 方法一: Object.prototype.clone = function(){ var o = this.constructor === Array ? [] : {}; for(var e in this){ o[e] = typeof this[e] === "object" ? this[e].clone() : this[e]; } return o; } //方法二: /** * 克隆一個對象 * @param Obj * @returns */ function clone(Obj) { var buf; if (Obj instanceof Array) { buf = [];//創建一個空的數組 var i = Obj.length; while (i--) { buf[i] = clone(Obj[i]); } return buf; }else if (Obj instanceof Object){ buf = {};//創建一個空對象 for (var k in Obj) { //為這個對象添加新的屬性 buf[k] = clone(Obj[k]); } return buf; }else{ //普通變量直接賦值 return Obj; } } |
11、如何消除一個數組里面重復的元素?
|
var arr=[1,2,3,3,4,4,5,5,6,1,9,3,25,4]; function deRepeat(){ var newArr=[]; var obj={}; var index=0; var l=arr.length; for(var i=0;i<l;i++){ if(obj[arr[i]]==undefined) { obj[arr[i]]=1; newArr[index++]=arr[i]; } else if(obj[arr[i]]==1) continue; } return newArr; } var newArr2=deRepeat(arr); alert(newArr2); //輸出1,2,3,4,5,6,9,25 |
12、小賢是一條可愛的小狗(Dog),它的叫聲很好聽(wow),每次看到主人的時候就會乖乖叫一聲(yelp)。從這段描述可以得到以下對象:
|
function Dog() { this.wow = function() { alert(’Wow’); } this.yelp = function() { this.wow(); } } |
小芒和小賢一樣,原來也是一條可愛的小狗,可是突然有一天瘋了(MadDog),一看到人就會每隔半秒叫一聲(wow)地不停叫喚(yelp)。請根據描述,按示例的形式用代碼來實。(繼承,原型,setInterval)
|
function MadDog() { this.yelp = function() { var self = this; setInterval(function() { self.wow(); }, 500); } } MadDog.prototype = new Dog(); //for test var dog = new Dog(); dog.yelp(); var madDog = new MadDog(); madDog.yelp(); |
13、下面這個ul,如何點擊每一列的時候alert其index?(閉包)
|
<ul id=”test”> <li>這是第一條</li> <li>這是第二條</li> <li>這是第三條</li> </ul> |
|
// 方法一: var lis=document.getElementById('2223').getElementsByTagName('li'); for(var i=0;i<3;i++) { lis[i].index=i; lis[i].onclick=function(){ alert(this.index); }; } //方法二: var lis=document.getElementById('2223').getElementsByTagName('li'); for(var i=0;i<3;i++){ lis[i].index=i; lis[i].onclick=(function(a){ return function() { alert(a); } })(i); } |
14、編寫一個JavaScript函數,輸入指定類型的選擇器(僅需支持id,class,tagName三種簡單CSS選擇器,無需兼容組合選擇器)可以返回匹配的DOM節點,需考慮瀏覽器兼容性和性能。
/*** @param selector {String} 傳入的CSS選擇器。* @return {Array}*/
|
var query = function(selector) { var reg = /^(#)?(\.)?(\w+)$/img; var regResult = reg.exec(selector); var result = []; //如果是id選擇器 if(regResult[1]) { if(regResult[3]) { if(typeof document.querySelector === "function") { result.push(document.querySelector(regResult[3])); }else { result.push(document.getElementById(regResult[3])); } } } //如果是class選擇器 else if(regResult[2]) { if(regResult[3]) { if(typeof document.getElementsByClassName === 'function') { var doms = document.getElementsByClassName(regResult[3]); if(doms) { result = converToArray(doms); } } //如果不支持getElementsByClassName函數 else { var allDoms = document.getElementsByTagName("*") ; for(var i = 0, len = allDoms.length; i < len; i++) { if(allDoms[i].className.search(new RegExp(regResult[2])) > -1) { result.push(allDoms[i]); } } } } } //如果是標簽選擇器 else if(regResult[3]) { var doms = document.getElementsByTagName(regResult[3].toLowerCase()); if(doms) { result = converToArray(doms); } } return result; } function converToArray(nodes){ var array = null; try{ array = Array.prototype.slice.call(nodes,0);//針對非IE瀏覽器 }catch(ex){ array = new Array(); for( var i = 0 ,len = nodes.length; i < len ; i++ ) { array.push(nodes[i]) } } return array; } |
15、請評價以下代碼並給出改進意見。
|
if(window.addEventListener){ var addListener = function(el,type,listener,useCapture){ el.addEventListener(type,listener,useCapture); }; } else if(document.all){ addListener = function(el,type,listener){ el.attachEvent("on"+type,function(){ listener.apply(el); }); } } |
- 不應該在if和else語句中聲明addListener函數,應該先聲明;
- 不需要使用window.addEventListener或document.all來進行檢測瀏覽器,應該使用能力檢測;
- 由於attachEvent在IE中有this指向問題,所以調用它時需要處理一下
改進如下:
function addEvent(elem, type, handler){ if(elem.addEventListener){ elem.addEventListener(type, handler, false); }else if(elem.attachEvent){ elem['temp' + type + handler] = handler; elem[type + handler] = function(){ elem['temp' + type + handler].apply(elem); }; elem.attachEvent('on' + type, elem[type + handler]); }else{ elem['on' + type] = handler; } } |
16、給String對象添加一個方法,傳入一個string類型的參數,然后將string的每個字符間價格空格返回,例如:
addSpace(“hello world”) // -> ‘h e l l o w o r l d’
|
String.prototype.spacify = function(){ return this.split('').join(' '); }; |
接着上述問題答案提問,1)直接在對象的原型上添加方法是否安全?尤其是在Object對象上。(這個我沒能答出?希望知道的說一下。) 2)函數聲明與函數表達式的區別?
答案:在js中,解析器在向執行環境中加載數據時,對函數聲明和函數表達式並非是一視同仁的,解析器會率先讀取函數聲明,並使其在執行任何代碼之前可用(可以訪問),至於函數表達式,則必須等到解析器執行到它所在的代碼行,才會真正被解析執行。
17、定義一個log方法,讓它可以代理console.log的方法。
可行的方法一:
function log(msg) { console.log(msg); } log("hello world!") // hello world! |
如果要傳入多個參數呢?顯然上面的方法不能滿足要求,所以更好的方法是:
function log(){ console.log.apply(console, arguments); }; |
到此,追問apply和call方法的異同。
對於apply和call兩者在作用上是相同的,即是調用一個對象的一個方法,以另一個對象替換當前對象。將一個函數的對象上下文從初始的上下文改變為由 thisObj 指定的新對象。
但兩者在參數上有區別的。對於第一個參數意義都一樣,但對第二個參數: apply傳入的是一個參數數組,也就是將多個參數組合成為一個數組傳入,而call則作為call的參數傳入(從第二個參數開始)。 如 func.call(func1,var1,var2,var3)對應的apply寫法為:func.apply(func1,[var1,var2,var3]) 。
18、在Javascript中什么是偽數組?如何將偽數組轉化為標准數組?
偽數組(類數組):無法直接調用數組方法或期望length屬性有什么特殊的行為,但仍可以對真正數組遍歷方法來遍歷它們。典型的是函數的argument參數,還有像調用getElementsByTagName,document.childNodes之類的,它們都返回NodeList對象都屬於偽數組。可以使用Array.prototype.slice.call(fakeArray)將數組轉化為真正的Array對象。
假設接第八題題干,我們要給每個log方法添加一個”(app)”前綴,比如’hello world!’ ->’(app)hello world!’。方法如下:
function log(){ var args = Array.prototype.slice.call(arguments); //為了使用unshift數組方法,將argument轉化為真正的數組 args.unshift('(app)'); console.log.apply(console, args); }; |
19、對作用域上下文和this的理解,看下列代碼:
var User = { count: 1, getCount: function() { return this.count; } }; console.log(User.getCount()); // what? var func = User.getCount; console.log(func()); // what? |
問兩處console輸出什么?為什么?
答案是1和undefined。
func是在winodw的上下文中被執行的,所以會訪問不到count屬性。
繼續追問,那么如何確保Uesr總是能訪問到func的上下文,即正確返回1。正確的方法是使用Function.prototype.bind。兼容各個瀏覽器完整代碼如下:
Function.prototype.bind = Function.prototype.bind || function(context){ var self = this; return function(){ return self.apply(context, arguments); }; } var func = User.getCount.bind(User); console.log(func()); |
20、原生JS的window.onload與Jquery的$(document).ready(function(){})有什么不同?如何用原生JS實現Jq的ready方法?
window.onload()方法是必須等到頁面內包括圖片的所有元素加載完畢后才能執行。
$(document).ready()是DOM結構繪制完畢后就執行,不必等到加載完畢。
/* * 傳遞函數給whenReady() * 當文檔解析完畢且為操作准備就緒時,函數作為document的方法調用 */ var whenReady = (function() { //這個函數返回whenReady()函數 var funcs = []; //當獲得事件時,要運行的函數 var ready = false; //當觸發事件處理程序時,切換為true //當文檔就緒時,調用事件處理程序 function handler(e) { if(ready) return; //確保事件處理程序只完整運行一次 //如果發生onreadystatechange事件,但其狀態不是complete的話,那么文檔尚未准備好 if(e.type === 'onreadystatechange' && document.readyState !== 'complete') { return; } //運行所有注冊函數 //注意每次都要計算funcs.length //以防這些函數的調用可能會導致注冊更多的函數 for(var i=0; i<funcs.length; i++) { funcs[i].call(document); } //事件處理函數完整執行,切換ready狀態, 並移除所有函數 ready = true; funcs = null; } //為接收到的任何事件注冊處理程序 if(document.addEventListener) { document.addEventListener('DOMContentLoaded', handler, false); document.addEventListener('readystatechange', handler, false); //IE9+ window.addEventListener('load', handler, false); }else if(document.attachEvent) { document.attachEvent('onreadystatechange', handler); window.attachEvent('onload', handler); } //返回whenReady()函數 return function whenReady(fn) { if(ready) { fn.call(document); } else { funcs.push(fn); } } })(); |
如果上述代碼十分難懂,下面這個簡化版:
function ready(fn){ if(document.addEventListener) {//標准瀏覽器 document.addEventListener('DOMContentLoaded', function() { //注銷事件, 避免反復觸發 document.removeEventListener('DOMContentLoaded',arguments.callee, false); fn();//執行函數 }, false); }else if(document.attachEvent) {//IE document.attachEvent('onreadystatechange', function() { if(document.readyState == 'complete') { document.detachEvent('onreadystatechange', arguments.callee); fn();//函數執行 } }); } }; |
21、(設計題)想實現一個對頁面某個節點的拖曳?如何做?(使用原生JS)
回答出概念即可,下面是幾個要點
1. 給需要拖拽的節點綁定mousedown, mousemove, mouseup事件
2. mousedown事件觸發后,開始拖拽
3. mousemove時,需要通過event.clientX和clientY獲取拖拽位置,並實時更新位置
4. mouseup時,拖拽結束
5. 需要注意瀏覽器邊界的情況
22、請實現如下功能
function setcookie(name,value,days){ //給cookie增加一個時間變量 var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); //設置過期時間為days天 document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString(); } function getCookie(name){ var result = ""; var myCookie = ""+document.cookie+";"; var searchName = "+name+"="; var startOfCookie = myCookie.indexOf(searchName); var endOfCookie; if(satrtOfCookie != -1){ startOfcookie += searchName.length; endOfCookie = myCookie.indexOf(";",startOfCookie); result = (myCookie.substring(startOfCookie,endOfCookie)); } return result; } (function(){ var oTips = document.getElementById('tips');//假設tips的id為tips var page = { check: function(){//檢查tips的cookie是否存在並且允許顯示 var tips = getCookie('tips'); if(!tips || tips == 'show') return true;//tips的cookie不存在 if(tips == "never_show_again") return false; }, hideTip: function(bNever){ if(bNever) setcookie('tips', 'never_show_again', 365); oTips.style.display = "none";//隱藏 }, showTip: function(){ oTips.style.display = "inline";//顯示,假設tips為行級元素 }, init: function(){ var _this = this; if(this.check()){ _this.showTip(); setcookie('tips', 'show', 1); } oTips.onclick = function(){ _this.hideTip(true); }; } }; page.init(); })(); |
23、說出以下函數的作用是?空白區域應該填寫什么?
//define (function(window){ function fn(str){ this.str=str; }
fn.prototype.format = function(){ var arg = ______; return this.str.replace(_____,function(a,b){ return arg[b]||""; }); } window.fn = fn; })(window);
//use (function(){ var t = new fn('<p><a href="{0}">{1}</a><span>{2}</span></p>'); console.log(t.format('http://www.alibaba.com','Alibaba','Welcome')); })(); |
答案:訪函數的作用是使用format函數將函數的參數替換掉{0}這樣的內容,返回一個格式化后的結果:
第一個空是:arguments
第二個空是:/\{(\d+)\}/ig
24、 Javascript作用域鏈?
理解變量和函數的訪問范圍和生命周期,全局作用域與局部作用域的區別,JavaScript中沒有塊作用域,函數的嵌套形成不同層次的作用域,嵌套的層次形成鏈式形式,通過作用域鏈查找屬性的規則需要深入理解。
25、 談談this對象的理解。
理解不同形式的函數調用方式下的this指向,理解事件函數、定時函數中的this指向,函數的調用形式決定了this的指向。
26、 eval是做什么的?
它的功能是把對應的字符串解析成JS代碼並運行;應該避免使用eval,不安全,非常耗性能(2個步驟,一次解析成js語句,一次執行)
27、 關於事件,IE與火狐的事件機制有什么區別? 如何阻止冒泡?
[1].在IE中,事件對象是作為一個全局變量來保存和維護的.所有的瀏覽器事件,不管是用戶觸發的,還是其他事件,都會更新window.event對象.所以在代碼中,只要調用window.event就可以獲取事件對象, 再event.srcElement就可以取得觸發事件的元素進行進一步處理.
[2].在FireFox中,事件對象卻不是全局對象,一般情況下,是現場發生,現場使用,FireFox把事件對象自動傳給事件處理程序.
關於事件的兼容性處理要熟練掌握,事件對象具體哪些屬性存在兼容性問題,IE與標准事件模型事件冒泡與事件捕獲的支持要理解
28、 什么是閉包(closure),為什么要用它?
簡單的理解是函數的嵌套形成閉包,閉包包括函數本身已經它的外部作用域
使用閉包可以形成獨立的空間,延長變量的生命周期,報存中間狀態值
29、javascript 代碼中的"use strict";是什么意思 ? 使用它區別是什么?
意思是使用嚴格模式,使用嚴格模式,一些不規范的語法將不再支持
嚴格模式
鏈接:http://www.ruanyifeng.com/blog/2013/01/javascript_strict_mode.html
全局變量顯式聲明
靜態綁定
禁止使用with語句
eval中定義的變量都是局部變量
禁止this關鍵字指向全局對象
禁止在函數內部遍歷調用棧
嚴格模式下無法刪除變量。只有configurable設置為true的對象屬性,才能被刪除
正常模式下,對一個對象的只讀屬性進行賦值,不會報錯,只會默默地失敗。嚴格模式下,將報錯。
嚴格模式下,對一個使用getter方法讀取的屬性進行賦值,會報錯。
嚴格模式下,對禁止擴展的對象添加新屬性,會報錯。
嚴格模式下,刪除一個不可刪除的屬性,會報錯。
正常模式下,如果對象有多個重名屬性,最后賦值的那個屬性會覆蓋前面的值。嚴格模式下,這屬於語法錯誤。
正常模式下,如果函數有多個重名的參數,可以用arguments[i]讀取。嚴格模式下,這屬於語法錯誤。
正常模式下,整數的第一位如果是0,表示這是八進制數,比如0100等於十進制的64。嚴格模式禁止這種表示法,整數第一位為0,將報錯。
不允許對arguments賦值
arguments不再追蹤參數的變化
禁止使用arguments.callee
嚴格模式只允許在全局作用域或函數作用域的頂層聲明函數。也就是說,不允許在非函數的代碼塊內聲明函數
嚴格模式新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield。
30、如何判斷一個對象是否屬於某個類(嚴格來說在ES6之前,js沒有類的概念)?
instanceof constructor
31、new操作符具體干了什么呢?
1、創建一個空對象,並且 this 變量引用該對象,同時還繼承了該函數的原型。
2、屬性和方法被加入到 this 引用的對象中。
3、新創建的對象由 this 所引用,並且最后隱式的返回 this 。
32、用原生JavaScript的實現過什么功能嗎?
主要考察原生js的實踐經驗
33、Javascript中,有一個函數,執行時對象查找時,永遠不會去查找原型,這個函數是?
HasOwnProperty
34、對JSON的了解?
輕量級數據交互格式,可以形成復雜的嵌套格式,解析非常方便
36、模塊化開發怎么做?
理解模塊化開發模式:瀏覽器端requirejs,seajs;服務器端nodejs;ES6模塊化;fis、webpack等前端整體模塊化解決方案;grunt、gulp等前端工作流的使用
37、AMD(Modules/Asynchronous-Definition)、CMD(Common Module Definition)規范區別?
理解這兩種規范的差異,主要通過requirejs與seajs的對比,理解模塊的定義與引用方式
的差異以及這兩種規范的設計原則
參考鏈接1:https://www.zhihu.com/question/20351507/answer/14859415
參考鏈接2:https://github.com/seajs/seajs/issues/277
1、對於依賴的模塊,AMD 是提前執行,CMD 是延遲執行。不過 RequireJS 從 2.0 開始,也改成可以延遲執行(根據寫法不同,處理方式不同)。CMD 推崇 as lazy as possible.
2、CMD 推崇依賴就近,AMD 推崇依賴前置。
3. AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啟動。CMD 里,每個 API 都簡單純粹。
38、requireJS的核心原理是什么?(如何動態加載的?如何避免多次加載的?如何 緩存的?)
核心是js的加載模塊,通過正則匹配模塊以及模塊的依賴關系,保證文件加載的先后順序,根據文件的路徑對加載過的文件做了緩存
39、讓你自己設計實現一個requireJS,你會怎么做?
核心是實現js的加載模塊,維護js的依賴關系,控制好文件加載的先后順序
40、談一談你對ECMAScript6的了解?
ES6新的語法糖,類,模塊化等新特性
關於ES6參考鏈接:http://es6.ruanyifeng.com/
- ECMAScript 6簡介
- let和const命令
- 變量的解構賦值
- 字符串的擴展
- 正則的擴展
- 數值的擴展
- 數組的擴展
- 函數的擴展
- 對象的擴展
- Symbol
- Proxy和Reflect
- 二進制數組
- Set和Map數據結構
- Iterator和for...of循環
- Generator函數
- Promise對象
- 異步操作和Async函數
- Class
- Decorator
- Module
41、ECMAScript6 怎么寫class么,為什么會出現class這種東西?
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '('+this.x+', '+this.y+')';
}
}
42、異步加載的方式有哪些?
方案一:<script>標簽的async="async"屬性(詳細參見:script標簽的async屬性)
方案二:<script>標簽的defer="defer"屬性
方案三:動態創建<script>標簽
方案四:AJAX eval(使用AJAX得到腳本內容,然后通過eval_r(xmlhttp.responseText)來運行腳本)
方案五:iframe方式
44、DOM操作——怎樣添加、移除、移動、復制、創建和查找節點?
(1)創建新節點
createDocumentFragment() //創建一個DOM片段
createElement_x() //創建一個具體的元素
createTextNode() //創建一個文本節點
(2)添加、移除、替換、插入
appendChild()
removeChild()
replaceChild()
insertBefore()
(3)查找
getElementsByTagName() //通過標簽名稱
getElementsByName() //通過元素的Name屬性的值
getElementById() //通過元素Id,唯一性
45、call() 和 apply() 的含義和區別?
apply的參數是數組形式,call的參數是單個的值,除此之外在使用上沒有差別,重點理解這兩個函數調用的this改變
46、數組和對象有哪些原生方法,列舉一下?
Array.concat( ) 連接數組
Array.join( ) 將數組元素連接起來以構建一個字符串
Array.length 數組的大小
Array.pop( ) 刪除並返回數組的最后一個元素
Array.push( ) 給數組添加元素
Array.reverse( ) 顛倒數組中元素的順序
Array.shift( ) 將元素移出數組
Array.slice( ) 返回數組的一部分
Array.sort( ) 對數組元素進行排序
Array.splice( ) 插入、刪除或替換數組的元素
Array.toLocaleString( ) 把數組轉換成局部字符串
Array.toString( ) 將數組轉換成一個字符串
Array.unshift( ) 在數組頭部插入一個元素
Object對象的常用方法
Object.hasOwnProperty( ) 檢查屬性是否被繼承
Object.isPrototypeOf( ) 一個對象是否是另一個對象的原型
Object.propertyIsEnumerable( ) 是否可以通過for/in循環看到屬性
Object.toLocaleString( ) 返回對象的本地字符串表示
Object.toString( ) 定義一個對象的字符串表示
Object.valueOf( ) 指定對象的原始值
47、JS 怎么實現一個類。怎么實例化這個類
嚴格來講js中並沒有類的概念,不過js中的函數可以作為構造函數來使用,通過new來實例化,其實函數本身也是一個對象。
48、JavaScript中的作用域與變量聲明提升?
理解JavaScript的預解析機制,js的運行主要分兩個階段:js的預解析和運行,預解析階段所有的變量聲明和函數定義都會提前,但是變量的賦值不會提前
49、如何編寫高性能的Javascript?
使用 DocumentFragment 優化多次 append
通過模板元素 clone ,替代 createElement
使用一次 innerHTML 賦值代替構建 dom 元素
使用 firstChild 和 nextSibling 代替 childNodes 遍歷 dom 元素
使用 Array 做為 StringBuffer ,代替字符串拼接的操作
將循環控制量保存到局部變量
順序無關的遍歷時,用 while 替代 for
將條件分支,按可能性順序從高到低排列
在同一條件子的多( >2 )條件分支時,使用 switch 優於 if
使用三目運算符替代條件分支
需要不斷執行的時候,優先考慮使用 setInterval
51、javascript對象的幾種創建方式?
1. 工廠模式
2. 構造函數模式
3. 原型模式
4. 混合構造函數和原型模式
5. 動態原型模式
6. 寄生構造函數模式
7. 穩妥構造函數模式
52、javascript繼承的 6 種方法?
1. 原型鏈繼承
2. 借用構造函數繼承
3. 組合繼承(原型+借用構造)
4. 原型式繼承
5. 寄生式繼承
6. 寄生組合式繼承
53、eval是做什么的?
1. 它的功能是把對應的字符串解析成JS代碼並運行
2. 應該避免使用eval,不安全,非常耗性能(2次,一次解析成js語句,一次執行)
54、JavaScript 原型,原型鏈 ? 有什么特點?
1. 原型對象也是普通的對象,是對象一個自帶隱式的 __proto__ 屬性,原型也有可能有自己的原型,如果一個原型對象的原型不為 null 的話,我們就稱之為原型鏈
2. 原型鏈是由一些用來繼承和共享屬性的對象組成的(有限的)對象鏈
56、簡述一下Sass、Less,且說明區別?
他們是動態的樣式語言,是CSS預處理器,CSS上的一種抽象層。他們是一種特殊的語法/語言而編譯成CSS。
變量符不一樣,less是@,而Sass是$;
Sass支持條件語句,可以使用if{}else{},for{}循環等等。而Less不支持;
Sass是基於Ruby的,是在服務端處理的,而Less是需要引入less.js來處理Less代碼輸出Css到瀏覽器
57、關於javascript中apply()和call()方法的區別?
相同點:兩個方法產生的作用是完全一樣的
不同點:方法傳遞的參數不同
Object.call(this,obj1,obj2,obj3)
Object.apply(this,arguments)
apply()接收兩個參數,一個是函數運行的作用域(this),另一個是參數數組。
call()方法第一個參數與apply()方法相同,但傳遞給函數的參數必須列舉出來。
58、簡述一下JS中的閉包?
閉包用的多的兩個作用:讀取函數內部的變量值;讓這些變量值始終保存着(在內存中)。
同時需要注意的是:閉包慎用,不濫用,不亂用,由於函數內部的變量都被保存在內存中,會導致內存消耗大。
59、說說你對this的理解?
在JavaScript中,this通常指向的是我們正在執行的函數本身,或者是,指向該函數所屬的對象。
全局的this → 指向的是Window
函數中的this → 指向的是函數所在的對象 錯誤答案
對象中的this → 指向其本身
事件中this → 指向事件對象
60、分別闡述split(),slice(),splice(),join()?
join()用於把數組中的所有元素拼接起來放入一個字符串。所帶的參數為分割字符串的分隔符,默認是以逗號分開。歸屬於Array
split()即把字符串分離開,以數組方式存儲。歸屬於Stringstring
slice() 方法可從已有的數組中返回選定的元素。該方法並不會修改數組,而是返回一個子數組。如果想刪除數組中的一段元素,應該使用方法 Array.splice()
splice() 方法向/從數組中添加/刪除項目,然后返回被刪除的項目。返回的是含有被刪除的元素的數組。
62、如何阻止事件冒泡和默認事件?
阻止瀏覽器的默認行為
window.event?window.event.returnValue=false:e.preventDefault();
停止事件冒泡
window.event?window.event.cancelBubble=true:e.stopPropagation();
原生JavaScript中,return false;只阻止默認行為,不阻止冒泡,jQuery中的return false;既阻止默認行為,又阻止冒泡
64、你用過require.js嗎?它有什么特性?
(1)實現js文件的異步加載,避免網頁失去響應;
(2)管理模塊之間的依賴性,便於代碼的編寫和維護。
65、談一下JS中的遞歸函數,並且用遞歸簡單實現階乘?
遞歸即是程序在執行過程中不斷調用自身的編程技巧,當然也必須要有一個明確的結束條件,不然就會陷入死循環。
66、請用正則表達式寫一個簡單的郵箱驗證。
/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
67、簡述一下你對web性能優化的方案?
1、盡量減少 HTTP 請求
2、使用瀏覽器緩存
3、使用壓縮組件
4、圖片、JS的預載入
5、將腳本放在底部
6、將樣式文件放在頁面頂部
7、使用外部的JS和CSS
8、精簡代碼
68、在JS中有哪些會被隱式轉換為false
Undefined、null、布爾值false、NaN、零、空字符串
69、定時器setInterval有一個有名函數fn1,setInterval(fn1,500)與setInterval(fn1(),500)有什么區別?
第一個是重復執行每500毫秒執行一次,后面一個只執行一次。
70、外部JS文件出現中文字符,會出現什么問題,怎么解決?
會出現亂碼,加charset=”GB2312”;
另一種解決方式:網頁文件和外部JS文件都是UTF8編碼
71、談談瀏覽器的內核,並且說一下什么是內核?
Trident (['traɪd(ə)nt])--IE,Gecko (['gekəʊ])--Firefox, Presto (['prestəʊ])--opera,webkit—谷歌和Safari
瀏覽器內核又可以分成兩部分:渲染引擎和 JS 引擎。它負責取得網頁的內容(HTML、XML、圖像等等)、整理訊息(例如加入 CSS 等),以及計算網頁的顯示方式,然后會輸出至顯示器或打印機。JS 引擎則是解析 Javascript 語言,執行 javascript 語言來實現網頁的動態效果。
72、JavaScript原型,原型鏈 ? 有什么特點?
* 原型對象也是普通的對象,是對象一個自帶隱式的 __proto__ 屬性,原型也有可能有自己的原型,如果一個原型對象的原型不為null的話,我們就稱之為原型鏈。
* 原型鏈是由一些用來繼承和共享屬性的對象組成的(有限的)對象鏈。
* JavaScript的數據對象有那些屬性值?
writable:這個屬性的值是否可以改。
configurable:這個屬性的配置是否可以刪除,修改。
enumerable:這個屬性是否能在for…in循環中遍歷出來或在Object.keys中列舉出來。
value:屬性值。
* 當我們需要一個屬性的時,Javascript引擎會先看當前對象中是否有這個屬性, 如果沒有的話,就會查找他的Prototype對象是否有這個屬性。
function clone(proto) {
function Dummy() { }
Dummy.prototype = proto;
Dummy.prototype.constructor = Dummy;
return new Dummy(); //等價於Object.create(Person);
}
function object(old) {
function F() {};
F.prototype = old;
return new F();
}
var newObj = object(oldObject);
73、寫一個通用的事件偵聽器函數
`// event(事件)工具集,來源:https://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();
};
}
},
// 視能力分別使用dom0||dom2||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.removeEnentListener) {
element.removeEnentListener(type, handler, false);
} else if (element.datachEvent) {
element.detachEvent('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.srcElement;
},
// 獲取event對象的引用,取到事件的所有信息,確保隨時能使用event;
getEvent : function(e) {
var ev = e || window.event;
if (!ev) {
var c = this.getEvent.caller;
while (c) {
ev = c.arguments[0];
if (ev && Event == ev.constructor) {
break;
}
c = c.caller;
}
}
return ev;
}
};
74、事件、IE與火狐的事件機制有什么區別? 如何阻止冒泡?
1. 我們在網頁中的某個操作(有的操作對應多個事件)。例如:當我們點擊一個按鈕就會產生一個事件。是可以被 JavaScript 偵測到的行為。
2. 事件處理機制:IE是事件冒泡、火狐是 事件捕獲;
3. ev.stopPropagation();
75、什么是閉包(closure),為什么要用?
執行say667()后,say667()閉包內部變量會存在,而閉包內部函數的內部變量不會存在.使得Javascript的垃圾回收機制GC不會收回say667()所占用的資源,因為say667()的內部函數的執行需要依賴say667()中的變量。這是對閉包作用的非常直白的描述.
function say667() {
// Local variable that ends up within closure
var num = 666;
var sayAlert = function() { alert(num); }
num++;
return sayAlert;
}
var sayAlert = say667();
sayAlert()//執行結果應該彈出的667
76、如何判斷一個對象是否屬於某個類?
使用instanceof (待完善)
if(a instanceof Person){
alert('yes');
}
77、new操作符具體干了什么呢?
1、創建一個空對象,並且 this 變量引用該對象,同時還繼承了該函數的原型。
2、屬性和方法被加入到 this 引用的對象中。
3、新創建的對象由 this 所引用,並且最后隱式的返回 this 。
var obj = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
78、JSON 的了解
JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。它是基於JavaScript的一個子集。數據格式簡單, 易於讀寫, 占用帶寬小
{'age':'12', 'name':'back'}
80、模塊化怎么做?
立即執行函數,不暴露私有成員
1、 使用字面量實現命名空間(YUI):
Itcast.common.dom={};
Itcast.common.css={};
Itcast.common.event={};
2、使用閉包
var module1 = (function(){
var _count = 0;
var m1 = function(){
//...
};
var m2 = function(){
//...
};
return {
m1 : m1,
m2 : m2
};
})();
81、異步加載的方式
(1) defer,只支持IE
(2) async:
(3) 創建script,插入到DOM中,加載完畢后callBack
documen.write和 innerHTML的區別
document.write只能重繪整個頁面
innerHTML可以重繪頁面的一部分
82、告訴我答案是多少?
(function(x){
delete x;
alert(x);
})(1+5);
函數參數無法delete刪除,delete只能刪除通過for in訪問的屬性。
當然,刪除失敗也不會報錯,所以代碼運行會彈出“1”。
83、JS中的call()和apply()方法的區別?
例子中用 add 來替換 sub,add.call(sub,3,1) == add(3,1) ,所以運行結果為:alert(4);
注意:js 中的函數其實是對象,函數名是對 Function 對象的引用。
function add(a,b){
alert(a+b);
}
function sub(a,b){
alert(a-b);
}
add.call(sub,3,1);
84、Jquery與jQuery UI 有啥區別?
*jQuery是一個js庫,主要提供的功能是選擇器,屬性修改和事件綁定等等。
*jQuery UI則是在jQuery的基礎上,利用jQuery的擴展性,設計的插件。
提供了一些常用的界面元素,諸如對話框、拖動行為、改變大小行為等等
85、jquery 中如何將數組轉化為json字符串,然后再轉化回來?
jQuery中沒有提供這個功能,所以你需要先編寫兩個jQuery的擴展:
$.fn.stringifyArray = function(array) {
return JSON.stringify(array)
}
$.fn.parseArray = function(array) {
return JSON.parse(array)
}
然后調用:
$("").stringifyArray(array)
86、JavaScript中的作用域與變量聲明提升?
其他部分
(HTTP、正則、優化、重構、響應式、移動端、團隊協作、SEO、UED、職業生涯)
*基於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++) {}
87、前端開發的優化問題(看雅虎14條性能優化原則)。
參考資料:J:\代碼,PPT,筆記,電子書\面試題\雅虎14條優化規則.docx
(1) 減少http請求次數:CSS Sprites, JS、CSS源碼壓縮、圖片大小控制合適;網頁Gzip,CDN托管,data緩存 ,圖片服務器。
(2) 前端模板 JS+數據,減少由於HTML標簽導致的帶寬浪費,前端用變量保存AJAX請求結果,每次操作本地變量,不用請求,減少請求次數
(3) 用innerHTML代替DOM操作,減少DOM操作次數,優化javascript性能。
(4) 當需要設置的樣式很多時設置className而不是直接操作style。
(5) 少用全局變量、緩存DOM節點查找的結果。減少IO讀取操作。
(6) 避免使用CSS Expression(css表達式)又稱Dynamic properties(動態屬性)。
(7) 圖片預加載,將樣式表放在頂部,將腳本放在底部 加上時間戳。
(8) 避免在頁面的主體布局中使用table,table要等其中的內容完全下載之后才會顯示出來,顯示比div+css布局慢。
88、http狀態碼有那些?分別代表是什么意思?
100-199 用於指定客戶端應相應的某些動作。
200-299 用於表示請求成功。
300-399 用於已經移動的文件並且常被包含在定位頭信息中指定新的地址信息。
400-499 用於指出客戶端的錯誤。
400 語義有誤,當前請求無法被服務器理解。
401 當前請求需要用戶驗證
403 服務器已經理解請求,但是拒絕執行它。
500-599 用於支持服務器錯誤。
503 – 服務不可用
89、一個頁面從輸入 URL 到頁面加載顯示完成,這個過程中都發生了什么?(流程說的越詳細越好)
要熟悉前后端的通信流程,最好把動態網站的背后細節也介紹一遍