新聞中心
最近一直在找工作,今年是真的難啊,但再難茍且的生活還要繼續(xù),飯碗還是要繼續(xù)找的。在最近的面試中我一直在總結(jié),每次面試回來(lái)也都會(huì)復(fù)盤,面了有七八家,也有那么幾個(gè)offer,但終究不是很滿意,總想再試試大一點(diǎn)的平臺(tái)。下面是我這幾天遇到的面試知識(shí)點(diǎn)。但今天主題是標(biāo)題所寫(xiě)的66條JavaScript知識(shí)點(diǎn),由淺入深,整理了一周,每(zhěng)天(lǐ)整(bù)理( yì)10條( qiú)左(diǎn)右(zàn), 希望對(duì)正在找工作的小伙伴有點(diǎn)幫助,文中如有表述不對(duì),還請(qǐng)指出。

創(chuàng)新互聯(lián)于2013年創(chuàng)立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元慶陽(yáng)做網(wǎng)站,已為上家服務(wù),為慶陽(yáng)各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:18982081108
HTML&CSS:
- 瀏覽器內(nèi)核
- 盒模型、flex布局、兩/三欄布局、水平/垂直居中;
- BFC、清除浮動(dòng);
- css3動(dòng)畫(huà)、H5新特性。
JavaScript:
- 繼承、原型鏈、this指向、設(shè)計(jì)模式、call, apply, bind,;
- new實(shí)現(xiàn)、防抖節(jié)流、let, var, const 區(qū)別、暫時(shí)性死區(qū)、event、loop;
- promise使用及實(shí)現(xiàn)、promise并行執(zhí)行和順序執(zhí)行;
- async/await的優(yōu)缺點(diǎn);
- 閉包、垃圾回收和內(nèi)存泄漏、數(shù)組方法、數(shù)組亂序, 數(shù)組扁平化、事件委托、事件監(jiān)聽(tīng)、事件模型
Vue:
- vue數(shù)據(jù)雙向綁定原理;
- vue computed原理、computed和watch的區(qū)別;
- vue編譯器結(jié)構(gòu)圖、生命周期、vue組件通信;
- mvvm模式、mvc模式理解;
- vue dom diff、vuex、vue-router
網(wǎng)絡(luò):
- HTTP1, HTTP2, HTTPS、常見(jiàn)的http狀態(tài)碼;
- 瀏覽從輸入網(wǎng)址到回車發(fā)生了什么;
- 前端安全(CSRF、XSS)
- 前端跨域、瀏覽器緩存、cookie, session, token, localstorage, sessionstorage;
- TCP連接(三次握手, 四次揮手)
性能相關(guān)
- 圖片優(yōu)化的方式
- 500 張圖片,如何實(shí)現(xiàn)預(yù)加載優(yōu)化
- 懶加載具體實(shí)現(xiàn)
- 減少http請(qǐng)求的方式
另外更全面的面試題集我也在整理中,先給個(gè)預(yù)告圖:
下面進(jìn)入正題:
- 1. 介紹一下 js 的數(shù)據(jù)類型有哪些,值是如何存儲(chǔ)的
- 2. && 、 ||和!! 運(yùn)算符分別能做什么
- 3. js的數(shù)據(jù)類型的轉(zhuǎn)換
- 4. JS中數(shù)據(jù)類型的判斷( typeof,instanceof,constructor,Object.prototype.toString.call()
- 5. 介紹 js 有哪些內(nèi)置對(duì)象?
- 6. undefined 與 undeclared 的區(qū)別?
- 7. null 和 undefined 的區(qū)別?
- 8. {} 和 [] 的 valueOf 和 toString 的結(jié)果是什么?
- 9. Javascript 的作用域和作用域鏈?
- 10. javascript 創(chuàng)建對(duì)象的幾種方式?
- 11. JavaScript 繼承的幾種實(shí)現(xiàn)方式?
- 12. 寄生式組合繼承的實(shí)現(xiàn)?
- 13. 談?wù)勀銓?duì)this、call、apply和bind的理解
- 14. JavaScript 原型,原型鏈?有什么特點(diǎn)?
- 15. js 獲取原型的方法?
- 16. 什么是閉包,為什么要用它?
- 17. 什么是 DOM 和 BOM?
- 18. 三種事件模型是什么?
- 19. 事件委托是什么?
- 20. 什么是事件傳播?
- 21. 什么是事件捕獲?
- 22. 什么是事件冒泡?
- 23. DOM 操作——怎樣添加、移除、移動(dòng)、復(fù)制、創(chuàng)建和查找節(jié)點(diǎn)?
- 24. js數(shù)組和對(duì)象有哪些原生方法,列舉一下
- 25. 常用的正則表達(dá)式
- 26. Ajax 是什么? 如何創(chuàng)建一個(gè) Ajax?
- 27. js 延遲加載的方式有哪些?
- 28. 談?wù)勀銓?duì)模塊化開(kāi)發(fā)的理解?
- 29. js 的幾種模塊規(guī)范?
- 30. AMD和CMD 規(guī)范的區(qū)別?
- 31. ES6 模塊與 CommonJS 模塊、AMD、CMD 的差異。
- 32. requireJS的核心原理是什么?
- 33. 談?wù)凧S的運(yùn)行機(jī)制
- 34. arguments 的對(duì)象是什么?
- 35. 為什么在調(diào)用這個(gè)函數(shù)時(shí),代碼中的`b`會(huì)變成一個(gè)全局變量?
- 36.簡(jiǎn)單介紹一下V8引擎的垃圾回收機(jī)制
- 37. 哪些操作會(huì)造成內(nèi)存泄漏?
- 38. ECMAScript 是什么?
- 39. ECMAScript 2015(ES6)有哪些新特性?
- 40. `var`,`let`和`const`的區(qū)別是什么?
- 41. 什么是箭頭函數(shù)?
- 42. 什么是類?
- 43. 什么是模板字符串?
- 44. 什么是對(duì)象解構(gòu)?
- 45 什么是`Set`對(duì)象,它是如何工作的?
- 46. 什么是Proxy?
————
高能預(yù)警分割線—————
- 47. 寫(xiě)一個(gè)通用的事件偵聽(tīng)器函數(shù),為什么要用它?
- 48. 什么是函數(shù)式編程? JavaScript的哪些特性使其成為函數(shù)式語(yǔ)言的候選語(yǔ)言?
- 49. 什么是高階函數(shù)?
- 50. 為什么函數(shù)被稱為一等公民?
- 51. 手動(dòng)實(shí)現(xiàn)`Array.prototype.map 方法`
- 52. 手動(dòng)實(shí)現(xiàn)`Array.prototype.filter`方法
- 53. 手動(dòng)實(shí)現(xiàn)`Array.prototype.reduce`方法
- 54. js的深淺拷貝
- 55. 手寫(xiě)call、apply及bind函數(shù)
- 56. 函數(shù)柯里化的實(shí)現(xiàn)
- 57. js模擬new操作符的實(shí)現(xiàn)
- 58. 什么是回調(diào)函數(shù)?回調(diào)函數(shù)有什么缺點(diǎn)
- 59. Promise是什么,可以手寫(xiě)實(shí)現(xiàn)一下嗎?
- 60. `Iterator`是什么,有什么作用?
- 61. `Generator`函數(shù)是什么,有什么作用?
- 62. 什么是 `async/await`及其如何工作,有什么優(yōu)缺點(diǎn)?
- 63. instanceof的原理是什么,如何實(shí)現(xiàn)
- 64. js的節(jié)流與防抖
- 65. 什么是設(shè)計(jì)模式?
- 66. 9種前端常見(jiàn)的設(shè)計(jì)模式
1. 介紹一下 js 的數(shù)據(jù)類型有哪些,值是如何存儲(chǔ)的
具體可看我之前的文章:「前端料包」可能是最透徹的JavaScript數(shù)據(jù)類型詳解
JavaScript一共有8種數(shù)據(jù)類型,其中有7種基本數(shù)據(jù)類型:Undefined、Null、Boolean、Number、String、Symbol(es6新增,表示獨(dú)一無(wú)二的值)和BigInt(es10新增);
1種引用數(shù)據(jù)類型——Object(Object本質(zhì)上是由一組無(wú)序的名值對(duì)組成的)。里面包含 function、Array、Date等。JavaScript不支持任何創(chuàng)建自定義類型的機(jī)制,而所有值最終都將是上述 8 種數(shù)據(jù)類型之一。
原始數(shù)據(jù)類型:直接存儲(chǔ)在棧(stack)中,占據(jù)空間小、大小固定,屬于被頻繁使用數(shù)據(jù),所以放入棧中存儲(chǔ)。
引用數(shù)據(jù)類型:同時(shí)存儲(chǔ)在棧(stack)和堆(heap)中,占據(jù)空間大、大小不固定。引用數(shù)據(jù)類型在棧中存儲(chǔ)了指針,該指針指向堆中該實(shí)體的起始地址。當(dāng)解釋器尋找引用值時(shí),會(huì)首先檢索其在棧中的地址,取得地址后從堆中獲得實(shí)體。
2. && 、 ||和!! 運(yùn)算符分別能做什么
- && 叫邏輯與,在其操作數(shù)中找到第一個(gè)虛值表達(dá)式并返回它,如果沒(méi)有找到任何虛值表達(dá)式,則返回最后一個(gè)真值表達(dá)式。它采用短路來(lái)防止不必要的工作。
- || 叫邏輯或,在其操作數(shù)中找到第一個(gè)真值表達(dá)式并返回它。這也使用了短路來(lái)防止不必要的工作。在支持 ES6 默認(rèn)函數(shù)參數(shù)之前,它用于初始化函數(shù)中的默認(rèn)參數(shù)值。
- !! 運(yùn)算符可以將右側(cè)的值強(qiáng)制轉(zhuǎn)換為布爾值,這也是將值轉(zhuǎn)換為布爾值的一種簡(jiǎn)單方法。
3. js的數(shù)據(jù)類型的轉(zhuǎn)換
在 JS 中類型轉(zhuǎn)換只有三種情況,分別是:
- 轉(zhuǎn)換為布爾值(調(diào)用Boolean()方法)
- 轉(zhuǎn)換為數(shù)字(調(diào)用Number()、parseInt()和parseFloat()方法)
- 轉(zhuǎn)換為字符串(調(diào)用.toString()或者String()方法)
- null和underfined沒(méi)有.toString方法
此外還有一些操作符會(huì)存在隱式轉(zhuǎn)換,此處不做展開(kāi),可自行百度00
4. JS中數(shù)據(jù)類型的判斷( typeof,instanceof,constructor,Object.prototype.toString.call()
(1)typeof
typeof 對(duì)于原始類型來(lái)說(shuō),除了 null 都可以顯示正確的類型
- console.log(typeof 2); // number
- console.log(typeof true); // boolean
- console.log(typeof 'str'); // string
- console.log(typeof []); // object []數(shù)組的數(shù)據(jù)類型在 typeof 中被解釋為 object
- console.log(typeof function(){}); // function
- console.log(typeof {}); // object
- console.log(typeof undefined); // undefined
- console.log(typeof null); // object null 的數(shù)據(jù)類型被 typeof 解釋為 object
typeof 對(duì)于對(duì)象來(lái)說(shuō),除了函數(shù)都會(huì)顯示 object,所以說(shuō) typeof 并不能準(zhǔn)確判斷變量到底是什么類型,所以想判斷一個(gè)對(duì)象的正確類型,這時(shí)候可以考慮使用 instanceof
(2)instanceof
instanceof 可以正確的判斷對(duì)象的類型,因?yàn)閮?nèi)部機(jī)制是通過(guò)判斷對(duì)象的原型鏈中是不是能找到類型的 prototype。
- console.log(2 instanceof Number); // false
- console.log(true instanceof Boolean); // false
- console.log('str' instanceof String); // false
- console.log([] instanceof Array); // true
- console.log(function(){} instanceof Function); // true
- console.log({} instanceof Object); // true
- // console.log(undefined instanceof Undefined);
- // console.log(null instanceof Null);
可以看出直接的字面量值判斷數(shù)據(jù)類型,instanceof可以精準(zhǔn)判斷引用數(shù)據(jù)類型(Array,F(xiàn)unction,Object),而基本數(shù)據(jù)類型不能被instanceof精準(zhǔn)判斷。
我們來(lái)看一下 instanceof 在MDN中的解釋:instanceof 運(yùn)算符用來(lái)測(cè)試一個(gè)對(duì)象在其原型鏈中是否存在一個(gè)構(gòu)造函數(shù)的 prototype 屬性。其意思就是判斷對(duì)象是否是某一數(shù)據(jù)類型(如Array)的實(shí)例,請(qǐng)重點(diǎn)關(guān)注一下是判斷一個(gè)對(duì)象是否是數(shù)據(jù)類型的實(shí)例。在這里字面量值,2, true ,'str'不是實(shí)例,所以判斷值為false。
(3)constructor
- console.log((2).constructor === Number); // true
- console.log((true).constructor === Boolean); // true
- console.log(('str').constructor === String); // true
- console.log(([]).constructor === Array); // true
- console.log((function() {}).constructor === Function); // true
- console.log(({}).constructor === Object); // true
- 這里有一個(gè)坑,如果我創(chuàng)建一個(gè)對(duì)象,更改它的原型,constructor就會(huì)變得不可靠了
- function Fn(){};
- Fn.prototype=new Array();
- var f=new Fn();
- console.log(f.constructor===Fn); // false
- console.log(f.constructor===Array); // true
(4)Object.prototype.toString.call()
使用 Object 對(duì)象的原型方法 toString ,使用 call 進(jìn)行貍貓換太子,借用Object的 toString 方法
- var a = Object.prototype.toString;
- console.log(a.call(2));
- console.log(a.call(true));
- console.log(a.call('str'));
- console.log(a.call([]));
- console.log(a.call(function(){}));
- console.log(a.call({}));
- console.log(a.call(undefined));
- console.log(a.call(null));
5. 介紹 js 有哪些內(nèi)置對(duì)象?
涉及知識(shí)點(diǎn):
- 全局的對(duì)象( global objects )或稱標(biāo)準(zhǔn)內(nèi)置對(duì)象,不要和 "全局對(duì)象(global object)" 混淆。這里說(shuō)的全局的對(duì)象是說(shuō)在
- 全局作用域里的對(duì)象。全局作用域中的其他對(duì)象可以由用戶的腳本創(chuàng)建或由宿主程序提供。
- 標(biāo)準(zhǔn)內(nèi)置對(duì)象的分類
- (1)值屬性,這些全局屬性返回一個(gè)簡(jiǎn)單值,這些值沒(méi)有自己的屬性和方法。
- 例如 Infinity、NaN、undefined、null 字面量
- (2)函數(shù)屬性,全局函數(shù)可以直接調(diào)用,不需要在調(diào)用時(shí)指定所屬對(duì)象,執(zhí)行結(jié)束后會(huì)將結(jié)果直接返回給調(diào)用者。
- 例如 eval()、parseFloat()、parseInt() 等
- (3)基本對(duì)象,基本對(duì)象是定義或使用其他對(duì)象的基礎(chǔ)?;緦?duì)象包括一般對(duì)象、函數(shù)對(duì)象和錯(cuò)誤對(duì)象。
- 例如 Object、Function、Boolean、Symbol、Error 等
- (4)數(shù)字和日期對(duì)象,用來(lái)表示數(shù)字、日期和執(zhí)行數(shù)學(xué)計(jì)算的對(duì)象。
- 例如 Number、Math、Date
- (5)字符串,用來(lái)表示和操作字符串的對(duì)象。
- 例如 String、RegExp
- (6)可索引的集合對(duì)象,這些對(duì)象表示按照索引值來(lái)排序的數(shù)據(jù)集合,包括數(shù)組和類型數(shù)組,以及類數(shù)組結(jié)構(gòu)的對(duì)象。例如 Array
- (7)使用鍵的集合對(duì)象,這些集合對(duì)象在存儲(chǔ)數(shù)據(jù)時(shí)會(huì)使用到鍵,支持按照插入順序來(lái)迭代元素。
- 例如 Map、Set、WeakMap、WeakSet
- (8)矢量集合,SIMD 矢量集合中的數(shù)據(jù)會(huì)被組織為一個(gè)數(shù)據(jù)序列。
- 例如 SIMD 等
- (9)結(jié)構(gòu)化數(shù)據(jù),這些對(duì)象用來(lái)表示和操作結(jié)構(gòu)化的緩沖區(qū)數(shù)據(jù),或使用 JSON 編碼的數(shù)據(jù)。
- 例如 JSON 等
- (10)控制抽象對(duì)象
- 例如 Promise、Generator 等
- (11)反射
- 例如 Reflect、Proxy
- (12)國(guó)際化,為了支持多語(yǔ)言處理而加入 ECMAScript 的對(duì)象。
- 例如 Intl、Intl.Collator 等
- (13)WebAssembly
- (14)其他
- 例如 arguments
js 中的內(nèi)置對(duì)象主要指的是在程序執(zhí)行前存在全局作用域里的由 js
定義的一些全局值屬性、函數(shù)和用來(lái)實(shí)例化其他對(duì)象的構(gòu)造函
數(shù)對(duì)象。一般我們經(jīng)常用到的如全局變量值 NaN、undefined,全局函數(shù)如 parseInt()、parseFloat() 用來(lái)實(shí)例化對(duì)象的構(gòu)
造函數(shù)如 Date、Object 等,還有提供數(shù)學(xué)計(jì)算的單體內(nèi)置對(duì)象如 Math 對(duì)象。
詳細(xì)資料可以參考:
《標(biāo)準(zhǔn)內(nèi)置對(duì)象的分類》
《JS 所有內(nèi)置對(duì)象屬性和方法匯總》
6. undefined 與 undeclared 的區(qū)別?
已在作用域中聲明但還沒(méi)有賦值的變量,是 undefined 的。相反,還沒(méi)有在作用域中聲明過(guò)的變量,是 undeclared 的。
對(duì)于 undeclared 變量的引用,瀏覽器會(huì)報(bào)引用錯(cuò)誤,如 ReferenceError: b is not defined 。但是我們可以使用 typ
eof 的安全防范機(jī)制來(lái)避免報(bào)錯(cuò),因?yàn)閷?duì)于 undeclared(或者 not defined )變量,typeof 會(huì)返回 "undefined"。
7. null 和 undefined 的區(qū)別?
首先 Undefined 和 Null 都是基本數(shù)據(jù)類型,這兩個(gè)基本數(shù)據(jù)類型分別都只有一個(gè)值,就是 undefined 和 null。
undefined 代表的含義是未定義,
null 代表的含義是空對(duì)象。一般變量聲明了但還沒(méi)有定義的時(shí)候會(huì)返回 undefined,null
主要用于賦值給一些可能會(huì)返回對(duì)象的變量,作為初始化。
undefined 在 js 中不是一個(gè)保留字,這意味著我們可以使用 undefined 來(lái)作為一個(gè)變量名,這樣的做法是非常危險(xiǎn)的,它
會(huì)影響我們對(duì) undefined 值的判斷。但是我們可以通過(guò)一些方法獲得安全的 undefined 值,比如說(shuō) void 0。
當(dāng)我們對(duì)兩種類型使用 typeof 進(jìn)行判斷的時(shí)候,Null 類型化會(huì)返回 “object”,這是一個(gè)歷史遺留的問(wèn)題。當(dāng)我們使用雙等
號(hào)對(duì)兩種類型的值進(jìn)行比較時(shí)會(huì)返回 true,使用三個(gè)等號(hào)時(shí)會(huì)返回 false。
詳細(xì)資料可以參考:
《JavaScript 深入理解之 undefined 與 null》
8. {} 和 [] 的 valueOf 和 toString 的結(jié)果是什么?
- {} 的 valueOf 結(jié)果為 {} ,toString 的結(jié)果為 "[object Object]"
- [] 的 valueOf 結(jié)果為 [] ,toString 的結(jié)果為 ""
9. Javascript 的作用域和作用域鏈
作用域: 作用域是定義變量的區(qū)域,它有一套訪問(wèn)變量的規(guī)則,這套規(guī)則來(lái)管理瀏覽器引擎如何在當(dāng)前作用域以及嵌套的作用域中根據(jù)變量(標(biāo)識(shí)符)進(jìn)行變量查找。
作用域鏈: 作用域鏈的作用是保證對(duì)執(zhí)行環(huán)境有權(quán)訪問(wèn)的所有變量和函數(shù)的有序訪問(wèn),通過(guò)作用域鏈,我們可以訪問(wèn)到外層環(huán)境的變量和
函數(shù)。
作用域鏈的本質(zhì)上是一個(gè)指向變量對(duì)象的指針列表。變量對(duì)象是一個(gè)包含了執(zhí)行環(huán)境中所有變量和函數(shù)的對(duì)象。作用域鏈的前
端始終都是當(dāng)前執(zhí)行上下文的變量對(duì)象。全局執(zhí)行上下文的變量對(duì)象(也就是全局對(duì)象)始終是作用域鏈的最后一個(gè)對(duì)象。
當(dāng)我們查找一個(gè)變量時(shí),如果當(dāng)前執(zhí)行環(huán)境中沒(méi)有找到,我們可以沿著作用域鏈向后查找。
作用域鏈的創(chuàng)建過(guò)程跟執(zhí)行上下文的建立有關(guān)….
詳細(xì)資料可以參考:
《JavaScript 深入理解之作用域鏈》
也可以看看我的文章:「前端料包」深究JavaScript作用域(鏈)知識(shí)點(diǎn)和閉包
10. javascript 創(chuàng)建對(duì)象的幾種方式?
- 我們一般使用字面量的形式直接創(chuàng)建對(duì)象,但是這種創(chuàng)建方式對(duì)于創(chuàng)建大量相似對(duì)象的時(shí)候,會(huì)產(chǎn)生大量的重復(fù)代碼。但 js
- 和一般的面向?qū)ο蟮恼Z(yǔ)言不同,在 ES6 之前它沒(méi)有類的概念。但是我們可以使用函數(shù)來(lái)進(jìn)行模擬,從而產(chǎn)生出可復(fù)用的對(duì)象
- 創(chuàng)建方式,我了解到的方式有這么幾種:
- (1)第一種是工廠模式,工廠模式的主要工作原理是用函數(shù)來(lái)封裝創(chuàng)建對(duì)象的細(xì)節(jié),從而通過(guò)調(diào)用函數(shù)來(lái)達(dá)到復(fù)用的目的。但是它有一個(gè)很大的問(wèn)題就是創(chuàng)建出來(lái)的對(duì)象無(wú)法和某個(gè)類型聯(lián)系起來(lái),它只是簡(jiǎn)單的封裝了復(fù)用代碼,而沒(méi)有建立起對(duì)象和類型間的關(guān)系。
- (2)第二種是構(gòu)造函數(shù)模式。js 中每一個(gè)函數(shù)都可以作為構(gòu)造函數(shù),只要一個(gè)函數(shù)是通過(guò) new 來(lái)調(diào)用的,那么我們就可以把它稱為構(gòu)造函數(shù)。執(zhí)行構(gòu)造函數(shù)首先會(huì)創(chuàng)建一個(gè)對(duì)象,然后將對(duì)象的原型指向構(gòu)造函數(shù)的 prototype 屬性,然后將執(zhí)行上下文中的 this 指向這個(gè)對(duì)象,最后再執(zhí)行整個(gè)函數(shù),如果返回值不是對(duì)象,則返回新建的對(duì)象。因?yàn)?nbsp;this 的值指向了新建的對(duì)象,因此我們可以使用 this 給對(duì)象賦值。構(gòu)造函數(shù)模式相對(duì)于工廠模式的優(yōu)點(diǎn)是,所創(chuàng)建的對(duì)象和構(gòu)造函數(shù)建立起了聯(lián)系,因此我們可以通過(guò)原型來(lái)識(shí)別對(duì)象的類型。但是構(gòu)造函數(shù)存在一個(gè)缺點(diǎn)就是,造成了不必要的函數(shù)對(duì)象的創(chuàng)建,因?yàn)樵?nbsp;js 中函數(shù)也是一個(gè)對(duì)象,因此如果對(duì)象屬性中如果包含函數(shù)的話,那么每次我們都會(huì)新建一個(gè)函數(shù)對(duì)象,浪費(fèi)了不必要的內(nèi)存空間,因?yàn)楹瘮?shù)是所有的實(shí)例都可以通用的。
- (3)第三種模式是原型模式,因?yàn)槊恳粋€(gè)函數(shù)都有一個(gè) prototype 屬性,這個(gè)屬性是一個(gè)對(duì)象,它包含了通過(guò)構(gòu)造函數(shù)創(chuàng)建的所有實(shí)例都能共享的屬性和方法。因此我們可以使用原型對(duì)象來(lái)添加公用屬性和方法,從而實(shí)現(xiàn)代碼的復(fù)用。這種方式相對(duì)于構(gòu)造函數(shù)模式來(lái)說(shuō),解決了函數(shù)對(duì)象的復(fù)用問(wèn)題。但是這種模式也存在一些問(wèn)題,一個(gè)是沒(méi)有辦法通過(guò)傳入?yún)?shù)來(lái)初始化值,另一個(gè)是如果存在一個(gè)引用類型如 Array 這樣的值,那么所有的實(shí)例將共享一個(gè)對(duì)象,一個(gè)實(shí)例對(duì)引用類型值的改變會(huì)影響所有的實(shí)例。
- (4)第四種模式是組合使用構(gòu)造函數(shù)模式和原型模式,這是創(chuàng)建自定義類型的最常見(jiàn)方式。因?yàn)闃?gòu)造函數(shù)模式和原型模式分開(kāi)使用都存在一些問(wèn)題,因此我們可以組合使用這兩種模式,通過(guò)構(gòu)造函數(shù)來(lái)初始化對(duì)象的屬性,通過(guò)原型對(duì)象來(lái)實(shí)現(xiàn)函數(shù)方法的復(fù)用。這種方法很好的解決了兩種模式單獨(dú)使用時(shí)的缺點(diǎn),但是有一點(diǎn)不足的就是,因?yàn)槭褂昧藘煞N不同的模式,所以對(duì)于代碼的封裝性不夠好。
- (5)第五種模式是動(dòng)態(tài)原型模式,這一種模式將原型方法賦值的創(chuàng)建過(guò)程移動(dòng)到了構(gòu)造函數(shù)的內(nèi)部,通過(guò)對(duì)屬性是否存在的判斷,可以實(shí)現(xiàn)僅在第一次調(diào)用函數(shù)時(shí)對(duì)原型對(duì)象賦值一次的效果。這一種方式很好地對(duì)上面的混合模式進(jìn)行了封裝。
- (6)第六種模式是寄生構(gòu)造函數(shù)模式,這一種模式和工廠模式的實(shí)現(xiàn)基本相同,我對(duì)這個(gè)模式的理解是,它主要是基于一個(gè)已有的類型,在實(shí)例化時(shí)對(duì)實(shí)例化的對(duì)象進(jìn)行擴(kuò)展。這樣既不用修改原來(lái)的構(gòu)造函數(shù),也達(dá)到了擴(kuò)展對(duì)象的目的。它的一個(gè)缺點(diǎn)和工廠模式一樣,無(wú)法實(shí)現(xiàn)對(duì)象的識(shí)別。
- 嗯我目前了解到的就是這么幾種方式。
詳細(xì)資料可以參考:
《JavaScript 深入理解之對(duì)象創(chuàng)建》
11. JavaScript 繼承的幾種實(shí)現(xiàn)方式?
- 我了解的 js 中實(shí)現(xiàn)繼承的幾種方式有:
- (1)第一種是以原型鏈的方式來(lái)實(shí)現(xiàn)繼承,但是這種實(shí)現(xiàn)方式存在的缺點(diǎn)是,在包含有引用類型的數(shù)據(jù)時(shí),會(huì)被所有的實(shí)例對(duì)象所共享,容易造成修改的混亂。還有就是在創(chuàng)建子類型的時(shí)候不能向超類型傳遞參數(shù)。
- (2)第二種方式是使用借用構(gòu)造函數(shù)的方式,這種方式是通過(guò)在子類型的函數(shù)中調(diào)用超類型的構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)的,這一種方法解決了不能向超類型傳遞參數(shù)的缺點(diǎn),但是它存在的一個(gè)問(wèn)題就是無(wú)法實(shí)現(xiàn)函數(shù)方法的復(fù)用,并且超類型原型定義的方法子類型也沒(méi)有辦法訪問(wèn)到。
- (3)第三種方式是組合繼承,組合繼承是將原型鏈和借用構(gòu)造函數(shù)組合起來(lái)使用的一種方式。通過(guò)借用構(gòu)造函數(shù)的方式來(lái)實(shí)現(xiàn)類型的屬性的繼承,通過(guò)將子類型的原型設(shè)置為超類型的實(shí)例來(lái)實(shí)現(xiàn)方法的繼承。這種方式解決了上面的兩種模式單獨(dú)使用時(shí)的問(wèn)題,但是由于我們是以超類型的實(shí)例來(lái)作為子類型的原型,所以調(diào)用了兩次超類的構(gòu)造函數(shù),造成了子類型的原型中多了很多不必要的屬性。
- (4)第四種方式是原型式繼承,原型式繼承的主要思路就是基于已有的對(duì)象來(lái)創(chuàng)建新的對(duì)象,實(shí)現(xiàn)的原理是,向函數(shù)中傳入一個(gè)對(duì)象,然后返回一個(gè)以這個(gè)對(duì)象為原型的對(duì)象。這種繼承的思路主要不是為了實(shí)現(xiàn)創(chuàng)造一種新的類型,只是對(duì)某個(gè)對(duì)象實(shí)現(xiàn)一種簡(jiǎn)單繼承,ES5 中定義的 Object.create() 方法就是原型式繼承的實(shí)現(xiàn)。缺點(diǎn)與原型鏈方式相同。
- (5)第五種方式是寄生式繼承,寄生式繼承的思路是創(chuàng)建一個(gè)用于封裝繼承過(guò)程的函數(shù),通過(guò)傳入一個(gè)對(duì)象,然后復(fù)制一個(gè)對(duì)象的副本,然后對(duì)象進(jìn)行擴(kuò)展,最后返回這個(gè)對(duì)象。這個(gè)擴(kuò)展的過(guò)程就可以理解是一種繼承。這種繼承的優(yōu)點(diǎn)就是對(duì)一個(gè)簡(jiǎn)單對(duì)象實(shí)現(xiàn)繼承,如果這個(gè)對(duì)象不是我們的自定義類型時(shí)。缺點(diǎn)是沒(méi)有辦法實(shí)現(xiàn)函數(shù)的復(fù)用。
- (6)第六種方式是寄生式組合繼承,組合繼承的缺點(diǎn)就是使用超類型的實(shí)例做為子類型的原型,導(dǎo)致添加了不必要的原型屬性。寄生式組合繼承的方式是使用超類型的原型的副本來(lái)作為子類型的原型,這樣就避免了創(chuàng)建不必要的屬性。
詳細(xì)資料可以參考:
《JavaScript 深入理解之繼承》
12. 寄生式組合繼承的實(shí)現(xiàn)?
- function Person(name) {
- this.name = name;
- }
- Person.prototype.sayName = function() {
- console.log("My name is " + this.name + ".");
- };
- function Student(name, grade) {
- Person.call(this, name);
- this.grade = grade;
- }
- Student.prototype = Object.create(Person.prototype);
- StudentStudent.prototype.constructor = Student;
- Student.prototype.sayMyGrade = function() {
- console.log("My grade is " + this.grade + ".");
- };
13. 談?wù)勀銓?duì)this、call、apply和bind的理解
詳情可看我之前的文章:「前端料包」一文徹底搞懂JavaScript中的this、call、apply和bind
- 在瀏覽器里,在全局范圍內(nèi)this 指向window對(duì)象;
- 在函數(shù)中,this永遠(yuǎn)指向最后調(diào)用他的那個(gè)對(duì)象;
- 構(gòu)造函數(shù)中,this指向new出來(lái)的那個(gè)新的對(duì)象;
- call、apply、bind中的this被強(qiáng)綁定在指定的那個(gè)對(duì)象上;
- 箭頭函數(shù)中this比較特殊,箭頭函數(shù)this為父作用域的this,不是調(diào)用時(shí)的this.要知道前四種方式,都是調(diào)用時(shí)確定,也就是動(dòng)態(tài)的,而箭頭函數(shù)的this指向是靜態(tài)的,聲明的時(shí)候就確定了下來(lái);
- apply、call、bind都是js給函數(shù)內(nèi)置的一些API,調(diào)用他們可以為函數(shù)指定this的執(zhí)行,同時(shí)也可以傳參。
14. JavaScript 原型,原型鏈?有什么特點(diǎn)?
在 js 中我們是使用構(gòu)造函數(shù)來(lái)新建一個(gè)對(duì)象的,每一個(gè)構(gòu)造函數(shù)的內(nèi)部都有一個(gè) prototype 屬性值,這個(gè)屬性值是一個(gè)對(duì)
象,這個(gè)對(duì)象包含了可以由該構(gòu)造函數(shù)的所有實(shí)例共享的屬性和方法。當(dāng)我們使用構(gòu)造函數(shù)新建一個(gè)對(duì)象后,在這個(gè)對(duì)象的內(nèi)部
將包含一個(gè)指針,這個(gè)指針指向構(gòu)造函數(shù)的 prototype 屬性對(duì)應(yīng)的值,在 ES5 中這個(gè)指針被稱為對(duì)象的原型。一般來(lái)說(shuō)我們
是不應(yīng)該能夠獲取到這個(gè)值的,但是現(xiàn)在瀏覽器中都實(shí)現(xiàn)了 proto 屬性來(lái)讓我們?cè)L問(wèn)這個(gè)屬性,但是我們最好不要使用這
個(gè)屬性,因?yàn)樗皇且?guī)范中規(guī)定的。ES5 中新增了一個(gè) Object.getPrototypeOf() 方法,我們可以通過(guò)這個(gè)方法來(lái)獲取對(duì)
象的原型。
當(dāng)我們?cè)L問(wèn)一個(gè)對(duì)象的屬性時(shí),如果這個(gè)對(duì)象內(nèi)部不存在這個(gè)屬性,那么它就會(huì)去它的原型對(duì)象里找這個(gè)屬性,這個(gè)原型對(duì)象又
會(huì)有自己的原型,于是就這樣一直找下去,也就是原型鏈的概念。原型鏈的盡頭一般來(lái)說(shuō)都是 Object.prototype 所以這就
是我們新建的對(duì)象為什么能夠使用 toString() 等方法的原因。
特點(diǎn):
JavaScript 對(duì)象是通過(guò)引用來(lái)傳遞的,我們創(chuàng)建的每個(gè)新對(duì)象實(shí)體中并沒(méi)有一份屬于自己的原型副本。當(dāng)我們修改原型時(shí),與
之相關(guān)的對(duì)象也會(huì)繼承這一改變。
參考文章:
《JavaScript 深入理解之原型與原型鏈》
也可以看看我寫(xiě)的:「前端料包」深入理解JavaScript原型和原型鏈
15. js 獲取原型的方法?
- p.proto
- p.constructor.prototype
- Object.getPrototypeOf(p)
16. 什么是閉包,為什么要用它?
閉包是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域內(nèi)變量的函數(shù),創(chuàng)建閉包的最常見(jiàn)的方式就是在一個(gè)函數(shù)內(nèi)創(chuàng)建另一個(gè)函數(shù),創(chuàng)建的函數(shù)可以
訪問(wèn)到當(dāng)前函數(shù)的局部變量。
閉包有兩個(gè)常用的用途。
- 閉包的第一個(gè)用途是使我們?cè)诤瘮?shù)外部能夠訪問(wèn)到函數(shù)內(nèi)部的變量。通過(guò)使用閉包,我們可以通過(guò)在外部調(diào)用閉包函數(shù),從而在外部訪問(wèn)到函數(shù)內(nèi)部的變量,可以使用這種方法來(lái)創(chuàng)建私有變量。
- 函數(shù)的另一個(gè)用途是使已經(jīng)運(yùn)行結(jié)束的函數(shù)上下文中的變量對(duì)象繼續(xù)留在內(nèi)存中,因?yàn)殚]包函數(shù)保留了這個(gè)變量對(duì)象的引用,所以這個(gè)變量對(duì)象不會(huì)被回收。
- function a(){
- var n = 0;
- function add(){
- n++;
- console.log(n);
- }
- return add;
- }
- var aa1 = a(); //注意,函數(shù)名只是一個(gè)標(biāo)識(shí)(指向函數(shù)的指針),而()才是執(zhí)行函數(shù);
- a1(); //1
- a1(); //2 第二次調(diào)用n變量還在內(nèi)存中
其實(shí)閉包的本質(zhì)就是作用域鏈的一個(gè)特殊的應(yīng)用,只要了解了作用域鏈的創(chuàng)建過(guò)程,就能夠理解閉包的實(shí)現(xiàn)原理。
17. 什么是 DOM 和 BOM?
DOM 指的是文檔對(duì)象模型,它指的是把文檔當(dāng)做一個(gè)對(duì)象來(lái)對(duì)待,這個(gè)對(duì)象主要定義了處理網(wǎng)頁(yè)內(nèi)容的方法和接口。
BOM 指的是瀏覽器對(duì)象模型,它指的是把瀏覽器當(dāng)做一個(gè)對(duì)象來(lái)對(duì)待,這個(gè)對(duì)象主要定義了與瀏覽器進(jìn)行交互的法和接口。BOM
的核心是 window,而 window 對(duì)象具有雙重角色,它既是通過(guò) js 訪問(wèn)瀏覽器窗口的一個(gè)接口,又是一個(gè) Global(全局)
對(duì)象。這意味著在網(wǎng)頁(yè)中定義的任何對(duì)象,變量和函數(shù),都作為全局對(duì)象的一個(gè)屬性或者方法存在。window 對(duì)象含有 locati
on 對(duì)象、navigator 對(duì)象、screen 對(duì)象等子對(duì)象,并且 DOM 的最根本的對(duì)象 document 對(duì)象也是 BOM 的 window 對(duì)
象的子對(duì)象。
相關(guān)資料:
《DOM, DOCUMENT, BOM, WINDOW 有什么區(qū)別?》
《Window 對(duì)象》
《DOM 與 BOM 分別是什么,有何關(guān)聯(lián)?》
《JavaScript 學(xué)習(xí)總結(jié)(三)BOM 和 DOM 詳解》
18. 三種事件模型是什么?
事件 是用戶操作網(wǎng)頁(yè)時(shí)發(fā)生的交互動(dòng)作或者網(wǎng)頁(yè)本身的一些操作,現(xiàn)代瀏覽器一共有三種事件模型。
- DOM0級(jí)模型: ,這種模型不會(huì)傳播,所以沒(méi)有事件流的概念,但是現(xiàn)在有的瀏覽器支持以冒泡的方式實(shí)現(xiàn),它可以在網(wǎng)頁(yè)中直接定義監(jiān)聽(tīng)函數(shù),也可以通過(guò) js屬性來(lái)指定監(jiān)聽(tīng)函數(shù)。這種方式是所有瀏覽器都兼容的。
2. IE 事件模型: 在該事件模型中,一次事件共有兩個(gè)過(guò)程,事件處理階段,和事件冒泡階段。事件處理階段會(huì)首先執(zhí)行目標(biāo)元素綁定的監(jiān)聽(tīng)事件。然后是事件冒泡階段,冒泡指的是事件從目標(biāo)元素冒泡到 document,依次檢查經(jīng)過(guò)的節(jié)點(diǎn)是否綁定了事件監(jiān)聽(tīng)函數(shù),如果有則執(zhí)行。這種模型通過(guò) attachEvent 來(lái)添加監(jiān)聽(tīng)函數(shù),可以添加多個(gè)監(jiān)聽(tīng)函數(shù),會(huì)按順序依次執(zhí)行。
3. DOM2 級(jí)事件模型: 在該事件模型中,一次事件共有三個(gè)過(guò)程,第一個(gè)過(guò)程是事件捕獲階段。捕獲指的是事件從 document 一直向下傳播到目標(biāo)元素,依次檢查經(jīng)過(guò)的節(jié)點(diǎn)是否綁定了事件監(jiān)聽(tīng)函數(shù),如果有則執(zhí)行。后面兩個(gè)階段和 IE 事件模型的兩個(gè)階段相同。這種事件模型,事件綁定的函數(shù)是 addEventListener,其中第三個(gè)參數(shù)可以指定事件是否在捕獲階段執(zhí)行。
相關(guān)資料:
《一個(gè) DOM 元素綁定多個(gè)事件時(shí),先執(zhí)行冒泡還是捕獲》
19. 事件委托是什么?
事件委托 本質(zhì)上是利用了瀏覽器事件冒泡的機(jī)制。因?yàn)槭录诿芭葸^(guò)程中會(huì)上傳到父節(jié)點(diǎn),并且父節(jié)點(diǎn)可以通過(guò)事件對(duì)象獲取到
目標(biāo)節(jié)點(diǎn),因此可以把子節(jié)點(diǎn)的監(jiān)聽(tīng)函數(shù)定義在父節(jié)點(diǎn)上,由父節(jié)點(diǎn)的監(jiān)聽(tīng)函數(shù)統(tǒng)一處理多個(gè)子元素的事件,這種方式稱為事件代理。
使用事件代理我們可以不必要為每一個(gè)子元素都綁定一個(gè)監(jiān)聽(tīng)事件,這樣減少了內(nèi)存上的消耗。并且使用事件代理我們還可以實(shí)現(xiàn)事件的動(dòng)態(tài)綁定,比如說(shuō)新增了一個(gè)子節(jié)點(diǎn),我們并不需要單獨(dú)地為它添加一個(gè)監(jiān)聽(tīng)事件,它所發(fā)生的事件會(huì)交給父元素中的監(jiān)聽(tīng)函數(shù)來(lái)處理。
相關(guān)資料:
《JavaScript 事件委托詳解》
20. 什么是事件傳播?
當(dāng)事件發(fā)生在DOM元素上時(shí),該事件并不完全發(fā)生在那個(gè)元素上。在“當(dāng)事件發(fā)生在DOM元素上時(shí),該事件并不完全發(fā)生在那個(gè)元素上。在“冒泡階段”中,事件冒泡或向上傳播至父級(jí),祖父母,祖父母或父級(jí),直到到達(dá)window為止;而在“捕獲階段”中,事件從window開(kāi)始向下觸發(fā)元素 事件或event.target。
事件傳播有三個(gè)階段:”中,事件冒泡或向上傳播至父級(jí),祖父母,祖父母或父級(jí),直到到達(dá)window為止;而在“捕獲階段”中,事件從window開(kāi)始向下觸發(fā)元素 事件或event.target。
事件傳播有三個(gè)階段:
- 捕獲階段–事件從 window 開(kāi)始,然后向下到每個(gè)元素,直到到達(dá)目標(biāo)元素。
- 目標(biāo)階段–事件已達(dá)到目標(biāo)元素。
- 冒泡階段–事件從目標(biāo)元素冒泡,然后上升到每個(gè)元素,直到到達(dá) window。
21. 什么是事件捕獲?
當(dāng)事件發(fā)生在 DOM 元素上時(shí),該事件并不完全發(fā)生在那個(gè)元素上。在捕獲階段,事件從window開(kāi)始,一直到觸發(fā)事件的元素。window----> document----> html----> body ---->目標(biāo)元素
假設(shè)有如下的 HTML 結(jié)構(gòu):
1
對(duì)應(yīng)的 JS 代碼:
- function addEvent(el, event, callback, isCapture = false) {
- if (!el || !event || !callback || typeof callback !== 'function') return;
- if (typeof el === 'string') {
- el = document.querySelector(el);
- };
- el.addEventListener(event, callback, isCapture);
- }
- addEvent(document, 'DOMContentLoaded', () => {
- const child = document.querySelector('.child');
- const parent = document.querySelector('.parent');
- const grandparent = document.querySelector('.grandparent');
- addEvent(child, 'click', function (e) {
- console.log('child');
- });
- addEvent(parent, 'click', function (e) {
- console.log('parent');
- });
- addEvent(grandparent, 'click', function (e) {
- console.log('grandparent');
- });
- addEvent(document, 'click', function (e) {
- console.log('document');
- });
- addEvent('html', 'click', function (e) {
- console.log('html');
- })
- addEvent(window, 'click', function (e) {
- console.log('window');
- })
- });
addEventListener方法具有第三個(gè)可選參數(shù)useCapture,其默認(rèn)值為false,事件將在冒泡階段中發(fā)生,如果為true,則事件將在捕獲階段中發(fā)生。如果單擊child元素,它將分別在控制臺(tái)上打印window,document,html,grandparent和parent,這就是事件捕獲。
22. 什么是事件冒泡?
事件冒泡剛好與事件捕獲相反,當(dāng)前元素---->body ----> html---->document ---->window。當(dāng)事件發(fā)生在DOM元素上時(shí),該事件并不完全發(fā)生在那個(gè)元素上。在冒泡階段,事件冒泡,或者事件發(fā)生在它的父代,祖父母,祖父母的父代,直到到達(dá)window為止。
假設(shè)有如下的 HTML 結(jié)構(gòu):
1
對(duì)應(yīng)的JS代碼:
- function addEvent(el, event, callback, isCapture = false) {
- if (!el || !event || !callback || typeof callback !== 'function') return;
- if (typeof el === 'string') {
- el = document.querySelector(el);
- };
- el.addEventListener(event, callback, isCapture);
- }
- addEvent(document, 'DOMContentLoaded', () => {
- const child = document.querySelector('.child');
- const parent = document.querySelector('.parent');
- const grandparent = document.querySelector('.grandparent');
- addEvent(child, 'click', function (e) {
- console.log('child');
- });
- addEvent(parent, 'click', function (e) {
- console.log('parent');
- });
- addEvent(grandparent, 'click', function (e) {
- console.log('grandparent');
- });
- addEvent(document, 'click', function (e) {
- console.log('document');
- });
- addEvent('html', 'click', function (e) {
- console.log('html');
- })
- addEvent(window, 'click', function (e) {
- console.log('window');
- })
- });
addEventListener方法具有第三個(gè)可選參數(shù)useCapture,其默認(rèn)值為false,事件將在冒泡階段中發(fā)生,如果為true,則事件將在捕獲階段中發(fā)生。如果單擊child元素,它將分別在控制臺(tái)上打印child,parent,grandparent,html,document和window,這就是事件冒泡。
23. DOM 操作——怎樣添加、移除、移動(dòng)、復(fù)制、創(chuàng)建和查找節(jié)點(diǎn)?
(1)創(chuàng)建新節(jié)點(diǎn)
- createDocumentFragment() //創(chuàng)建一個(gè)DOM片段
- createElement() //創(chuàng)建一個(gè)具體的元素
- createTextNode() //創(chuàng)建一個(gè)文本節(jié)點(diǎn)
(2)添加、移除、替換、插入
- appendChild(node)
- removeChild(node)
- replaceChild(new,old)
- insertBefore(new,old)
(3)查找
- getElementById();
- getElementsByName();
- getElementsByTagName();
- getElementsByClassName();
- querySelector();
- querySelectorAll();
(4)屬性操作
- getAttribute(key);
- setAttribute(key, value);
- hasAttribute(key);
- removeAttribute(key);
相關(guān)資料:
《DOM 概述》
《原生 JavaScript 的 DOM 操作匯總》
《原生 JS 中 DOM 節(jié)點(diǎn)相關(guān) API 合集》
24. js數(shù)組和對(duì)象有哪些原生方法,列舉一下
25. 常用的正則表達(dá)式
- //(1)匹配 16 進(jìn)制顏色值
- var color = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;
- //(2)匹配日期,如 yyyy-mm-dd 格式
- var date = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;
- //(3)匹配 qq 號(hào)
- var qq = /^[1-9][0-9]{4,10}$/g;
- //(4)手機(jī)號(hào)碼正則
- var phone = /^1[34578]\d{9}$/g;
- //(5)用戶名正則
- var username = /^[a-zA-Z\$][a-zA-Z0-9_\$]{4,16}$/;
- //(6)Email正則
- var email = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
- //(7)身份證號(hào)(18位)正則
- var cP = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
- //(8)URL正則
- var urlP= /^((https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/;
- // (9)ipv4地址正則
- var ipP = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
- // (10)//車牌號(hào)正則
- var cPattern = /^[京津滬渝冀豫云遼黑湘皖魯新蘇浙贛鄂桂甘晉蒙陜吉閩貴粵青藏川寧瓊使領(lǐng)A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9掛學(xué)警港澳]{1}$/;
- // (11)強(qiáng)密碼(必須包含大小寫(xiě)字母和數(shù)字的組合,不能使用特殊字符,長(zhǎng)度在8-10之間):var pwd = /^(?=.\d)(?=.[a-z])(?=.[A-Z]).{8,10}$/
26. Ajax 是什么? 如何創(chuàng)建一個(gè) Ajax?
我對(duì) ajax 的理解是,它是一種異步通信的方法,通過(guò)直接由 js 腳本向服務(wù)器發(fā)起 http 通信,然后根據(jù)服務(wù)器返回的數(shù)據(jù),更新網(wǎng)頁(yè)的相應(yīng)部分,而不用刷新整個(gè)頁(yè)面的一種方法。
創(chuàng)建步驟:
面試手寫(xiě)(原生):
- //1:創(chuàng)建Ajax對(duì)象
- var xhr = window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');// 兼容IE6及以下版本
- //2:配置 Ajax請(qǐng)求地址
- xhr.open('get','index.xml',true);
- //3:發(fā)送請(qǐng)求
- xhr.send(null); // 嚴(yán)謹(jǐn)寫(xiě)法
- //4:監(jiān)聽(tīng)請(qǐng)求,接受響應(yīng)
- xhr.onreadysatechange=function(){
- if(xhr.readySates==4&&xhr.status==200 || xhr.status==304 )
- console.log(xhr.responsetXML)
- }
jQuery寫(xiě)法
- $.ajax({
- type:'post',
- url:'',
- async:ture,//async 異步 sync 同步
- data:data,//針對(duì)post請(qǐng)求
- dataType:'jsonp',
- success:function (msg) {
- },
- error:function (error) {
- }
- })
promise 封裝實(shí)現(xiàn):
- // promise 封裝實(shí)現(xiàn):
- function getJSON(url) {
- // 創(chuàng)建一個(gè) promise 對(duì)象
- let promise = new Promise(function(resolve, reject) {
- let xhr = new XMLHttpRequest();
- // 新建一個(gè) http 請(qǐng)求
- xhr.open("GET", url, true);
- // 設(shè)置狀態(tài)的監(jiān)聽(tīng)函數(shù)
- xhr.onreadystatechange = function() {
- if (this.readyState !== 4) return;
- // 當(dāng)請(qǐng)求成功或失敗時(shí),改變 promise 的狀態(tài)
- if (this.status === 200) {
- resolve(this.response);
- } else {
- reject(new Error(this.statusText));
- }
- };
- // 設(shè)置錯(cuò)誤監(jiān)聽(tīng)函數(shù)
- xhr.onerror = function() {
- reject(new Error(this.statusText));
- };
- // 設(shè)置響應(yīng)的數(shù)據(jù)類型
- xhr.responseType = "json";
- // 設(shè)置請(qǐng)求頭信息
- xhr.setRequestHeader("Accept", "application/json");
- // 發(fā)送 http 請(qǐng)求
- xhr.send(null);
- });
- return promise;
- }
27. js 延遲加載的方式有哪些?
js 的加載、解析和執(zhí)行會(huì)阻塞頁(yè)面的渲染過(guò)程,因此我們希望 js 腳本能夠盡可能的延遲加載,提高頁(yè)面的渲染速度。
我了解到的幾種方式是:
- 將 js 腳本放在文檔的底部,來(lái)使 js 腳本盡可能的在最后來(lái)加載執(zhí)行。
- 給 js 腳本添加 defer屬性,這個(gè)屬性會(huì)讓腳本的加載與文檔的解析同步解析,然后在文檔解析完成后再執(zhí)行這個(gè)腳本文件,這樣的話就能使頁(yè)面的渲染不被阻塞。多個(gè)設(shè)置了 defer 屬性的腳本按規(guī)范來(lái)說(shuō)最后是順序執(zhí)行的,但是在一些瀏覽器中可能不是這樣。
3. 給 js 腳本添加 async屬性,這個(gè)屬性會(huì)使腳本異步加載,不會(huì)阻塞頁(yè)面的解析過(guò)程,但是當(dāng)腳本加載完成后立即執(zhí)行 js腳本,這個(gè)時(shí)候如果文檔沒(méi)有解析完成的話同樣會(huì)阻塞。多個(gè) async 屬性的腳本的執(zhí)行順序是不可預(yù)測(cè)的,一般不會(huì)按照代碼的順序依次執(zhí)行。
4. 動(dòng)態(tài)創(chuàng)建 DOM 標(biāo)簽的方式,我們可以對(duì)文檔的加載事件進(jìn)行監(jiān)聽(tīng),當(dāng)文檔加載完成后再動(dòng)態(tài)的創(chuàng)建 script 標(biāo)簽來(lái)引入 js 腳本。
相關(guān)資料:
《JS 延遲加載的幾種方式》
《HTML 5


咨詢
建站咨詢