最近在整理 JavaScript 的時候發(fā)現(xiàn)遇到了很多面試中常見的面試題,本部分主要是作者在 Github 等各大論壇收錄的 JavaScript 相關(guān)知識和一些相關(guān)面試題時所做的筆記,分享這份總結(jié)給大家,對大家對 JavaScript 的可以來一次全方位的檢漏和排查,感謝原作者 CavsZhouyou 的付出,原文鏈接放在文章最下方,如果出現(xiàn)錯誤,希望大家共同指出!
1. 介紹 js 的基本數(shù)據(jù)類型嗤谚。
js 一共有六種基本數(shù)據(jù)類型桦踊,分別是 Undefined、Null、Boolean鲸湃、Number、String,還有在 ES6 中新增的 Symbol 類型,
代表創(chuàng)建后獨(dú)一無二且不可變的數(shù)據(jù)類型,它的出現(xiàn)我認(rèn)為主要是為了解決可能出現(xiàn)的全局變量沖突的問題。
2. JavaScript 有幾種類型的值?你能畫一下他們的內(nèi)存圖嗎?
涉及知識點(diǎn):
- 棧:原始數(shù)據(jù)類型(Undefined、Null嫁审、Boolean、Number遏插、String)
- 堆:引用數(shù)據(jù)類型(對象、數(shù)組和函數(shù))
兩種類型的區(qū)別是:存儲位置不同了牛。
原始數(shù)據(jù)類型直接存儲在棧(stack)中的簡單數(shù)據(jù)段鹰祸,占據(jù)空間小蛙婴、大小固定浇衬,屬于被頻繁使用數(shù)據(jù)耘擂,所以放入棧中存儲醉冤。
引用數(shù)據(jù)類型存儲在堆(heap)中的對象,占據(jù)空間大韵吨、大小不固定归粉。
如果存儲在棧中糠悼,將會影響程序運(yùn)行的性能;引用數(shù)據(jù)類型在棧中存儲了指針席噩,該指針指向堆中該實體的起始地址悼枢。當(dāng)解釋器尋找引用值時馒索,會首先檢索其在棧中的地址旨怠,取得地址后從堆中獲得實體运吓。
回答:
js 可以分為兩種類型的值,一種是基本數(shù)據(jù)類型倦青,一種是復(fù)雜數(shù)據(jù)類型产镐。
基本數(shù)據(jù)類型....(參考1)
復(fù)雜數(shù)據(jù)類型指的是 Object 類型,所有其他的如 Array述雾、Date 等數(shù)據(jù)類型都可以理解為 Object 類型的子類玻孟。
兩種類型間的主要區(qū)別是它們的存儲位置不同,基本數(shù)據(jù)類型的值直接保存在棧中匣掸,而復(fù)雜數(shù)據(jù)類型的值保存在堆中旺聚,通過使用在棧中保存對應(yīng)的指針來獲取堆中的值唧躲。
3. 什么是堆?什么是棧嵌器?它們之間有什么區(qū)別和聯(lián)系?
堆和棧的概念存在于數(shù)據(jù)結(jié)構(gòu)中和操作系統(tǒng)內(nèi)存中讥珍。
在數(shù)據(jù)結(jié)構(gòu)中,棧中數(shù)據(jù)的存取方式為先進(jìn)后出氏义。而堆是一個優(yōu)先隊列惯悠,是按優(yōu)先級來進(jìn)行排序的,優(yōu)先級可以按照大小來規(guī)定鸠补。完全
二叉樹是堆的一種實現(xiàn)方式紫岩。
在操作系統(tǒng)中,內(nèi)存被分為棧區(qū)和堆區(qū)勋陪。
棧區(qū)內(nèi)存由編譯器自動分配釋放,存放函數(shù)的參數(shù)值违孝,局部變量的值等雌桑。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧拣技。
堆區(qū)內(nèi)存一般由程序員分配釋放,若程序員不釋放掸绞,程序結(jié)束時可能由垃圾回收機(jī)制回收衔掸。
4. 內(nèi)部屬性 [[Class]] 是什么?
所有 typeof 返回值為 "object" 的對象(如數(shù)組)都包含一個內(nèi)部屬性 [[Class]](我們可以把它看作一個內(nèi)部的分類振愿,而非傳統(tǒng)的面向?qū)ο笠饬x上的類)。這個屬性無法直接訪問档桃,一般通過 Object.prototype.toString(..) 來查看。例如:
Object.prototype.toString.call( [1,2,3] );
// "[object Array]"
Object.prototype.toString.call( /regex-literal/i );
// "[object RegExp]"
5. 介紹 js 有哪些內(nèi)置對象嘹屯?
涉及知識點(diǎn):
全局的對象( global objects )或稱標(biāo)準(zhǔn)內(nèi)置對象,不要和 "全局對象(global object)" 混淆呆馁。這里說的全局的對象是說在全局作用域里的對象。全局作用域中的其他對象可以由用戶的腳本創(chuàng)建或由宿主程序提供纺腊。
標(biāo)準(zhǔn)內(nèi)置對象的分類
(1)值屬性,這些全局屬性返回一個簡單值壹粟,這些值沒有自己的屬性和方法。
例如 Infinity雀费、NaN、undefined辕羽、null 字面量
(2)函數(shù)屬性,全局函數(shù)可以直接調(diào)用酌毡,不需要在調(diào)用時指定所屬對象,執(zhí)行結(jié)束后會將結(jié)果直接返回給調(diào)用者旭蠕。
例如 eval()佑稠、parseFloat()、parseInt() 等
(3)基本對象幔嫂,基本對象是定義或使用其他對象的基礎(chǔ)∏行模基本對象包括一般對象、函數(shù)對象和錯誤對象而涉。
例如 Object、Function季眷、Boolean、Symbol挺峡、Error 等
(4)數(shù)字和日期對象,用來表示數(shù)字宰啦、日期和執(zhí)行數(shù)學(xué)計算的對象赡模。
例如 Number师抄、Math漓柑、Date
(5)字符串,用來表示和操作字符串的對象叨吮。
例如 String欺缘、RegExp
(6)可索引的集合對象挤安,這些對象表示按照索引值來排序的數(shù)據(jù)集合,包括數(shù)組和類型數(shù)組丧鸯,以及類數(shù)組結(jié)構(gòu)的對象蛤铜。例如 Array
(7)使用鍵的集合對象,這些集合對象在存儲數(shù)據(jù)時會使用到鍵丛肢,支持按照插入順序來迭代元素围肥。
例如 Map、Set蜂怎、WeakMap穆刻、WeakSet
(8)矢量集合,SIMD 矢量集合中的數(shù)據(jù)會被組織為一個數(shù)據(jù)序列杠步。
例如 SIMD 等
(9)結(jié)構(gòu)化數(shù)據(jù)氢伟,這些對象用來表示和操作結(jié)構(gòu)化的緩沖區(qū)數(shù)據(jù),或使用 JSON 編碼的數(shù)據(jù)幽歼。
例如 JSON 等
(10)控制抽象對象
例如 Promise朵锣、Generator 等
(11)反射
例如 Reflect、Proxy
(12)國際化甸私,為了支持多語言處理而加入 ECMAScript 的對象诚些。
例如 Intl、Intl.Collator 等
(13)WebAssembly
(14)其他
例如 arguments
回答:
js 中的內(nèi)置對象主要指的是在程序執(zhí)行前存在全局作用域里的由 js 定義的一些全局值屬性皇型、函數(shù)和用來實例化其他對象的構(gòu)造函數(shù)對象诬烹。
一般我們經(jīng)常用到的如全局變量值 NaN、undefined弃鸦,全局函數(shù)如 parseInt()绞吁、parseFloat() 用來實例化對象的構(gòu)造函數(shù)如 Date、Object 等寡键,還有提供數(shù)學(xué)計算的單體內(nèi)置對象如 Math 對象坝辫。
6. undefined 與 undeclared 的區(qū)別?
已在作用域中聲明但還沒有賦值的變量莲蜘,是 undefined 的碗暗。相反,還沒有在作用域中聲明過的變量徘钥,是 undeclared 的。
對于 undeclared 變量的引用,瀏覽器會報引用錯誤庄拇,如 ReferenceError: b is not defined 。但是我們可以使用 typeof 的安全防范機(jī)制來避免報錯韭邓,因為對于 undeclared(或者 not defined )變量措近,typeof 會返回 "undefined"。
7. null 和 undefined 的區(qū)別女淑?
首先 Undefined 和 Null 都是基本數(shù)據(jù)類型瞭郑,這兩個基本數(shù)據(jù)類型分別都只有一個值,就是 undefined 和 null鸭你。
undefined 代表的含義是未定義屈张,null 代表的含義是空對象。一般變量聲明了但還沒有定義的時候會返回 undefined袱巨,null主要用于賦值給一些可能會返回對象的變量阁谆,作為初始化。
undefined 在 js 中不是一個保留字愉老,這意味著我們可以使用 undefined 來作為一個變量名场绿,這樣的做法是非常危險的,它會影響我們對 undefined 值的判斷嫉入。但是我們可以通過一些方法獲得安全的 undefined 值焰盗,比如說 void 0。
當(dāng)我們對兩種類型使用 typeof 進(jìn)行判斷的時候劝贸,Null 類型化會返回 “object”姨谷,這是一個歷史遺留的問題。當(dāng)我們使用雙等號對兩種類型的值進(jìn)行比較時會返回 true映九,使用三個等號時會返回 false梦湘。
8. 如何獲取安全的 undefined 值?
因為 undefined 是一個標(biāo)識符件甥,所以可以被當(dāng)作變量來使用和賦值捌议,但是這樣會影響 undefined 的正常判斷。
表達(dá)式void ___
沒有返回值引有,因此返回結(jié)果是 undefined瓣颅。void 并不改變表達(dá)式的結(jié)果,只是讓表達(dá)式不返回值譬正。
按慣例我們用 void 0 來獲得 undefined宫补。
9. 說幾條寫 JavaScript 的基本規(guī)范檬姥?
在平常項目開發(fā)中,我們遵守一些這樣的基本規(guī)范粉怕,比如說:
(1)一個函數(shù)作用域中所有的變量聲明應(yīng)該盡量提到函數(shù)首部健民,用一個 var 聲明,不允許出現(xiàn)兩個連續(xù)的 var 聲明贫贝,聲明時如果變量沒有值秉犹,應(yīng)該給該變量賦值對應(yīng)類型的初始值,便于他人閱讀代碼時稚晚,能夠一目了然的知道變量對應(yīng)的類型值崇堵。
(2)代碼中出現(xiàn)地址、時間等字符串時需要使用常量代替客燕。
(3)在進(jìn)行比較的時候吧鸳劳,盡量使用'===', '!=='代替'==', '!='。
(4)不要在內(nèi)置對象的原型上添加方法也搓,如 Array, Date棍辕。
(5)switch 語句必須帶有 default 分支。
(6)for 循環(huán)必須使用大括號还绘。
(7)if 語句必須使用大括號。
10. JavaScript 原型栖袋,原型鏈拍顷? 有什么特點(diǎn)?
在 js 中我們是使用構(gòu)造函數(shù)來新建一個對象的塘幅,每一個構(gòu)造函數(shù)的內(nèi)部都有一個 prototype 屬性值昔案,這個屬性值是一個對象,這個對象包含了可以由該構(gòu)造函數(shù)的所有實例共享的屬性和方法电媳。
當(dāng)我們使用構(gòu)造函數(shù)新建一個對象后踏揣,在這個對象的內(nèi)部將包含一個指針,這個指針指向構(gòu)造函數(shù)的 prototype 屬性對應(yīng)的值匾乓,在 ES5 中這個指針被稱為對象的原型捞稿。
一般來說我們是不應(yīng)該能夠獲取到這個值的,但是現(xiàn)在瀏覽器中都實現(xiàn)了 proto 屬性來讓我們訪問這個屬性拼缝,但是我們最好不要使用這個屬性娱局,因為它不是規(guī)范中規(guī)定的。
ES5 中新增了一個 Object.getPrototypeOf() 方法咧七,我們可以通過這個方法來獲取對象的原型衰齐。
當(dāng)我們訪問一個對象的屬性時,如果這個對象內(nèi)部不存在這個屬性继阻,那么它就會去它的原型對象里找這個屬性耻涛,這個原型對象又會有自己的原型废酷,于是就這樣一直找下去,也就是原型鏈的概念抹缕。原型鏈的盡頭一般來說都是 Object.prototype 所以這就是我們新建的對象為什么能夠使用 toString() 等方法的原因澈蟆。
特點(diǎn):
JavaScript 對象是通過引用來傳遞的,我們創(chuàng)建的每個新對象實體中并沒有一份屬于自己的原型副本歉嗓。當(dāng)我們修改原型時丰介,與之相關(guān)的對象也會繼承這一改變。
11. js 獲取原型的方法鉴分?
- p.proto
- p.constructor.prototype
- Object.getPrototypeOf(p)
12. 在 js 中不同進(jìn)制數(shù)字的表示方式
- 以 0X哮幢、0x 開頭的表示為十六進(jìn)制。
- 以 0志珍、0O橙垢、0o 開頭的表示為八進(jìn)制。
- 以 0B伦糯、0b 開頭的表示為二進(jìn)制格式柜某。
13. js 中整數(shù)的安全范圍是多少?
安全整數(shù)指的是敛纲,在這個范圍內(nèi)的整數(shù)轉(zhuǎn)化為二進(jìn)制存儲的時候不會出現(xiàn)精度丟失喂击,能夠被“安全”呈現(xiàn)的最大整數(shù)是 2^53 - 1,即9007199254740991淤翔,在 ES6 中被定義為 Number.MAX_SAFE_INTEGER翰绊。
最小整數(shù)是-9007199254740991,在 ES6 中被定義為 Number.MIN_SAFE_INTEGER旁壮。
如果某次計算的結(jié)果得到了一個超過 JavaScript 數(shù)值范圍的值监嗜,那么這個值會被自動轉(zhuǎn)換為特殊的 Infinity 值。如果某次計算返回了正或負(fù)的 Infinity 值抡谐,那么該值將無法參與下一次的計算裁奇。判斷一個數(shù)是不是有窮的,可以使用 isFinite 函數(shù)來判斷麦撵。
14. typeof NaN 的結(jié)果是什么刽肠?
NaN 意指“不是一個數(shù)字”(not a number),NaN 是一個“警戒值”(sentinel value免胃,有特殊用途的常規(guī)值)五垮,用于指出數(shù)字類型中的錯誤情況,即“執(zhí)行數(shù)學(xué)運(yùn)算沒有成功杜秸,這是失敗后返回的結(jié)果”放仗。
typeof NaN; // "number"
NaN 是一個特殊值,它和自身不相等撬碟,是唯一一個非自反(自反诞挨,reflexive莉撇,即 x === x 不成立)的值。而 NaN != NaN為 true惶傻。
15. isNaN 和 Number.isNaN 函數(shù)的區(qū)別棍郎?
函數(shù) isNaN 接收參數(shù)后,會嘗試將這個參數(shù)轉(zhuǎn)換為數(shù)值银室,任何不能被轉(zhuǎn)換為數(shù)值的的值都會返回 true涂佃,因此非數(shù)字值傳入也會返回 true ,會影響 NaN 的判斷蜈敢。
函數(shù) Number.isNaN 會首先判斷傳入?yún)?shù)是否為數(shù)字辜荠,如果是數(shù)字再繼續(xù)判斷是否為 NaN ,這種方法對于 NaN 的判斷更為準(zhǔn)確抓狭。
16. Array 構(gòu)造函數(shù)只有一個參數(shù)值時的表現(xiàn)伯病?
Array 構(gòu)造函數(shù)只帶一個數(shù)字參數(shù)的時候,該參數(shù)會被作為數(shù)組的預(yù)設(shè)長度(length)否过,而非只充當(dāng)數(shù)組中的一個元素午笛。這樣創(chuàng)建出來的只是一個空數(shù)組,只不過它的 length 屬性被設(shè)置成了指定的值苗桂。
構(gòu)造函數(shù) Array(..) 不要求必須帶 new 關(guān)鍵字药磺。不帶時,它會被自動補(bǔ)上煤伟。
17. 其他值到字符串的轉(zhuǎn)換規(guī)則与涡?
規(guī)范的 9.8 節(jié)中定義了抽象操作 ToString ,它負(fù)責(zé)處理非字符串到字符串的強(qiáng)制類型轉(zhuǎn)換持偏。
(1)Null 和 Undefined 類型 ,null 轉(zhuǎn)換為 "null"氨肌,undefined 轉(zhuǎn)換為 "undefined"鸿秆,
(2)Boolean 類型,true 轉(zhuǎn)換為 "true"蔓肯,false 轉(zhuǎn)換為 "false"螟够。
(3)Number 類型的值直接轉(zhuǎn)換蔓彩,不過那些極小和極大的數(shù)字會使用指數(shù)形式。
(4)Symbol 類型的值直接轉(zhuǎn)換考婴,但是只允許顯式強(qiáng)制類型轉(zhuǎn)換,使用隱式強(qiáng)制類型轉(zhuǎn)換會產(chǎn)生錯誤催烘。
(3)對普通對象來說沥阱,除非自行定義 toString() 方法,否則會調(diào)用toString()(Object.prototype.toString())
來返回內(nèi)部屬性 [[Class]] 的值伊群,如"[object Object]"考杉。
如果對象有自己的 toString() 方法策精,字符串化時就會調(diào)用該方法并使用其返回值。
18. 其他值到數(shù)字值的轉(zhuǎn)換規(guī)則崇棠?
有時我們需要將非數(shù)字值當(dāng)作數(shù)字來使用咽袜,比如數(shù)學(xué)運(yùn)算。為此 ES5 規(guī)范在 9.3 節(jié)定義了抽象操作 ToNumber枕稀。
(1)Undefined 類型的值轉(zhuǎn)換為 NaN询刹。
(2)Null 類型的值轉(zhuǎn)換為 0。
(3)Boolean 類型的值萎坷,true 轉(zhuǎn)換為 1凹联,false 轉(zhuǎn)換為 0。
(4)String 類型的值轉(zhuǎn)換如同使用 Number() 函數(shù)進(jìn)行轉(zhuǎn)換食铐,如果包含非數(shù)字值則轉(zhuǎn)換為 NaN匕垫,空字符串為 0。
(5)Symbol 類型的值不能轉(zhuǎn)換為數(shù)字虐呻,會報錯象泵。
(6)對象(包括數(shù)組)會首先被轉(zhuǎn)換為相應(yīng)的基本類型值,如果返回的是非數(shù)字的基本類型值斟叼,則再遵循以上規(guī)則將其強(qiáng)制轉(zhuǎn)換為數(shù)字偶惠。
為了將值轉(zhuǎn)換為相應(yīng)的基本類型值,抽象操作 ToPrimitive 會首先(通過內(nèi)部操作DefaultValue)檢查該值是否有valueOf() 方法朗涩。如果有并且返回基本類型值忽孽,就使用該值進(jìn)行強(qiáng)制類型轉(zhuǎn)換。如果沒有就使用 toString() 的返回值(如果存在)來進(jìn)行強(qiáng)制類型轉(zhuǎn)換谢床。
如果 valueOf() 和 toString() 均不返回基本類型值兄一,會產(chǎn)生 TypeError 錯誤。
19. 其他值到布爾類型的值的轉(zhuǎn)換規(guī)則识腿?
ES5 規(guī)范 9.2 節(jié)中定義了抽象操作 ToBoolean出革,列舉了布爾強(qiáng)制類型轉(zhuǎn)換所有可能出現(xiàn)的結(jié)果。
以下這些是假值:
- undefined
- null
- false
- +0渡讼、-0 和 NaN
- ""
假值的布爾強(qiáng)制類型轉(zhuǎn)換結(jié)果為 false骂束。從邏輯上說,假值列表以外的都應(yīng)該是真值成箫。
20. {} 和 [] 的 valueOf 和 toString 的結(jié)果是什么展箱?
{} 的 valueOf 結(jié)果為 {} ,toString 的結(jié)果為 "[object Object]"
[] 的 valueOf 結(jié)果為 [] 蹬昌,toString 的結(jié)果為 ""
21. 什么是假值對象混驰?
瀏覽器在某些特定情況下,在常規(guī) JavaScript 語法基礎(chǔ)上自己創(chuàng)建了一些外來值,這些就是“假值對象”账胧。
假值對象看起來和普通對象并無二致(都有屬性竞慢,等等),但將它們強(qiáng)制類型轉(zhuǎn)換為布爾值時治泥,結(jié)果為 false 最常見的例子是 document.all筹煮,它是一個類數(shù)組對象,包含了頁面上的所有元素居夹,由 DOM(而不是 JavaScript 引擎)提供給 JavaScript 程序使用败潦。
22. ~ 操作符的作用?
~ 返回 2 的補(bǔ)碼准脂,并且 ~ 會將數(shù)字轉(zhuǎn)換為 32 位整數(shù)劫扒,因此我們可以使用 ~ 來進(jìn)行取整操作。
~x 大致等同于 -(x+1)狸膏。
23. 解析字符串中的數(shù)字和將字符串強(qiáng)制類型轉(zhuǎn)換為數(shù)字的返回結(jié)果都是數(shù)字沟饥,它們之間的區(qū)別是什么?
解析允許字符串(如 parseInt() )中含有非數(shù)字字符湾戳,解析按從左到右的順序贤旷,如果遇到非數(shù)字字符就停止。而轉(zhuǎn)換(如 Number ())不允許出現(xiàn)非數(shù)字字符砾脑,否則會失敗并返回 NaN幼驶。
24. + 操作符什么時候用于字符串的拼接?
根據(jù) ES5 規(guī)范 11.6.1 節(jié)韧衣,如果某個操作數(shù)是字符串或者能夠通過以下步驟轉(zhuǎn)換為字符串的話盅藻,+ 將進(jìn)行拼接操作。
如果其中一個操作數(shù)是對象(包括數(shù)組)畅铭,則首先對其調(diào)用 ToPrimitive 抽象操作氏淑,該抽象操作再調(diào)用 [[DefaultValue]],以數(shù)字作為上下文硕噩。如果不能轉(zhuǎn)換為字符串假残,則會將其轉(zhuǎn)換為數(shù)字類型來進(jìn)行計算。
簡單來說就是榴徐,如果 + 的其中一個操作數(shù)是字符串(或者通過以上步驟最終得到字符串),則執(zhí)行字符串拼接匀归,否則執(zhí)行數(shù)字加法坑资。
那么對于除了加法的運(yùn)算符來說,只要其中一方是數(shù)字穆端,那么另一方就會被轉(zhuǎn)為數(shù)字袱贮。
25. 什么情況下會發(fā)生布爾值的隱式強(qiáng)制類型轉(zhuǎn)換?
(1) if (..) 語句中的條件判斷表達(dá)式体啰。
(2) for ( .. ; .. ; .. ) 語句中的條件判斷表達(dá)式(第二個)攒巍。
(3) while (..) 和 do..while(..) 循環(huán)中的條件判斷表達(dá)式嗽仪。
(4) ? : 中的條件判斷表達(dá)式。
(5) 邏輯運(yùn)算符 ||(邏輯或)和 &&(邏輯與)左邊的操作數(shù)(作為條件判斷表達(dá)式)柒莉。
26. || 和 && 操作符的返回值闻坚?
|| 和 && 首先會對第一個操作數(shù)執(zhí)行條件判斷,如果其不是布爾值就先進(jìn)行 ToBoolean 強(qiáng)制類型轉(zhuǎn)換兢孝,然后再執(zhí)行條件判斷窿凤。
對于 || 來說,如果條件判斷結(jié)果為 true 就返回第一個操作數(shù)的值跨蟹,如果為 false 就返回第二個操作數(shù)的值雳殊。
&& 則相反,如果條件判斷結(jié)果為 true 就返回第二個操作數(shù)的值窗轩,如果為 false 就返回第一個操作數(shù)的值夯秃。
|| 和 && 返回它們其中一個操作數(shù)的值,而非條件判斷的結(jié)果痢艺。
27. Symbol 值的強(qiáng)制類型轉(zhuǎn)換仓洼?
ES6 允許從符號到字符串的顯式強(qiáng)制類型轉(zhuǎn)換,然而隱式強(qiáng)制類型轉(zhuǎn)換會產(chǎn)生錯誤腹备。
Symbol 值不能夠被強(qiáng)制類型轉(zhuǎn)換為數(shù)字(顯式和隱式都會產(chǎn)生錯誤)衬潦,但可以被強(qiáng)制類型轉(zhuǎn)換為布爾值(顯式和隱式結(jié)果都是 true )。
28. == 操作符的強(qiáng)制類型轉(zhuǎn)換規(guī)則植酥?
(1)字符串和數(shù)字之間的相等比較镀岛,將字符串轉(zhuǎn)換為數(shù)字之后再進(jìn)行比較。
(2)其他類型和布爾類型之間的相等比較友驮,先將布爾值轉(zhuǎn)換為數(shù)字后漂羊,再應(yīng)用其他規(guī)則進(jìn)行比較。
(3)null 和 undefined 之間的相等比較卸留,結(jié)果為真走越。其他值和它們進(jìn)行比較都返回假值。
(4)對象和非對象之間的相等比較耻瑟,對象先調(diào)用 ToPrimitive 抽象操作后旨指,再進(jìn)行比較。
(5)如果一個操作值為 NaN 喳整,則相等比較返回 false( NaN 本身也不等于 NaN )谆构。
(6)如果兩個操作值都是對象,則比較它們是不是指向同一個對象框都。如果兩個操作數(shù)都指向同一個對象搬素,則相等操作符返回 true,否則,返回 false熬尺。
29. 如何將字符串轉(zhuǎn)化為數(shù)字摸屠,例如 '12.3b'?
(1)使用 Number() 方法,前提是所包含的字符串不包含不合法字符粱哼。
(2)使用 parseInt() 方法季二,parseInt() 函數(shù)可解析一個字符串,并返回一個整數(shù)皂吮。還可以設(shè)置要解析的數(shù)字的基數(shù)戒傻。當(dāng)基數(shù)的值為 0,或沒有設(shè)置該參數(shù)時蜂筹,parseInt() 會根據(jù) string 來判斷數(shù)字的基數(shù)需纳。
(3)使用 parseFloat() 方法,該函數(shù)解析一個字符串參數(shù)并返回一個浮點(diǎn)數(shù)艺挪。
(4)使用 + 操作符的隱式轉(zhuǎn)換不翩。
詳細(xì)資料可以參考:《詳解 JS 中 Number()、parseInt() 和 parseFloat() 的區(qū)別》
30. 如何將浮點(diǎn)數(shù)點(diǎn)左邊的數(shù)每三位添加一個逗號麻裳,如 12000000.11 轉(zhuǎn)化為『12,000,000.11』?
function format(number) {
return number && number.replace(/(?!^)(?=(\d{3})+\.)/g, ",");
}
31. 常用正則表達(dá)式
(1)匹配 16 進(jìn)制顏色值
var regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;
(2)匹配日期口蝠,如 yyyy-mm-dd 格式
var regex = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;
(3)匹配 qq 號
var regex = /^[1-9][0-9]{4,10}$/g;
(4)手機(jī)號碼正則
var regex = /^1[34578]\d{9}$/g;
(5)用戶名正則
var regex = /^[a-zA-Z\$][a-zA-Z0-9_\$]{4,16}$/;
32. 如何實現(xiàn)數(shù)組的隨機(jī)排序?
(1)使用數(shù)組 sort 方法對數(shù)組元素隨機(jī)排序津坑,讓 Math.random() 出來的數(shù)與 0.5 比較妙蔗,如果大于就返回 1 交換位置,如果小于就返回 -1疆瑰,不交換位置眉反。
function randomSort(a, b) {
return Math.random() > 0.5 ? -1 : 1;
}
缺點(diǎn):每個元素被派到新數(shù)組的位置不是隨機(jī)的,原因是 sort() 方法是依次比較的穆役。
(2)隨機(jī)從原數(shù)組抽取一個元素寸五,加入到新數(shù)組
function randomSort(arr) {
var result = [];
while (arr.length > 0) {
var randomIndex = Math.floor(Math.random() * arr.length);
result.push(arr[randomIndex]);
arr.splice(randomIndex, 1);
}
return result;
}
(3)隨機(jī)交換數(shù)組內(nèi)的元素(洗牌算法類似)
function randomSort(arr) {
var index,
randomIndex,
temp,
len = arr.length;
for (index = 0; index < len; index++) {
randomIndex = Math.floor(Math.random() * (len - index)) + index;
temp = arr[index];
arr[index] = arr[randomIndex];
arr[randomIndex] = temp;
}
return arr;
}
// es6
function randomSort(array) {
let length = array.length;
if (!Array.isArray(array) || length <= 1) return;
for (let index = 0; index < length - 1; index++) {
let randomIndex = Math.floor(Math.random() * (length - index)) + index;
[array[index], array[randomIndex]] = [array[randomIndex], array[index]];
}
return array;
}
34. javascript 創(chuàng)建對象的幾種方式?
我們一般使用字面量的形式直接創(chuàng)建對象耿币,但是這種創(chuàng)建方式對于創(chuàng)建大量相似對象的時候梳杏,會產(chǎn)生大量的重復(fù)代碼。但 js和一般的面向?qū)ο蟮恼Z言不同淹接,在 ES6 之前它沒有類的概念十性。
但是我們可以使用函數(shù)來進(jìn)行模擬,從而產(chǎn)生出可復(fù)用的對象創(chuàng)建方式塑悼,我了解到的方式有這么幾種:
(1)第一種是工廠模式劲适。
工廠模式的主要工作原理是用函數(shù)來封裝創(chuàng)建對象的細(xì)節(jié),從而通過調(diào)用函數(shù)來達(dá)到復(fù)用的目的拢肆。但是它有一個很大的問題就是創(chuàng)建出來的對象無法和某個類型聯(lián)系起來减响,它只是簡單的封裝了復(fù)用代碼,而沒有建立起對象和類型間的關(guān)系郭怪。
(2)第二種是構(gòu)造函數(shù)模式支示。
js 中每一個函數(shù)都可以作為構(gòu)造函數(shù),只要一個函數(shù)是通過 new 來調(diào)用的鄙才,那么我們就可以把它稱為構(gòu)造函數(shù)颂鸿。
執(zhí)行構(gòu)造函數(shù)首先會創(chuàng)建一個對象,然后將對象的原型指向構(gòu)造函數(shù)的 prototype 屬性攒庵,然后將執(zhí)行上下文中的 this 指向這個對象嘴纺,最后再執(zhí)行整個函數(shù),如果返回值不是對象浓冒,則返回新建的對象栽渴。
因為 this 的值指向了新建的對象,因此我們可以使用 this 給對象賦值稳懒。構(gòu)造函數(shù)模式相對于工廠模式的優(yōu)點(diǎn)是闲擦,所創(chuàng)建的對象和構(gòu)造函數(shù)建立起了聯(lián)系,因此我們可以通過原型來識別對象的類型场梆。
但是構(gòu)造函數(shù)存在一個缺點(diǎn)就是墅冷,造成了不必要的函數(shù)對象的創(chuàng)建,因為在 js 中函數(shù)也是一個對象或油,因此如果對象屬性中如果包含函數(shù)的話寞忿,那么每次我們都會新建一個函數(shù)對象,浪費(fèi)了不必要的內(nèi)存空間顶岸,因為函數(shù)是所有的實例都可以通用的腔彰。
(3)第三種模式是原型模式。
因為每一個函數(shù)都有一個 prototype 屬性蜕琴,這個屬性是一個對象萍桌,它包含了通過構(gòu)造函數(shù)創(chuàng)建的所有實例都能共享的屬性和方法。因此我們可以使用原型對象來添加公用屬性和方法凌简,從而實現(xiàn)代碼的復(fù)用上炎。這種方式相對于構(gòu)造函數(shù)模式來說,解決了函數(shù)對象的復(fù)用問題雏搂。
但是這種模式也存在一些問題藕施,一個是沒有辦法通過傳入?yún)?shù)來初始化值,另一個是如果存在一個引用類型如 Array 這樣的值凸郑,那么所有的實例將共享一個對象裳食,一個實例對引用類型值的改變會影響所有的實例。
(4)第四種模式是組合使用構(gòu)造函數(shù)模式和原型模式芙沥。
這是創(chuàng)建自定義類型的最常見方式诲祸。因為構(gòu)造函數(shù)模式和原型模式分開使用都存在一些問題浊吏,因此我們可以組合使用這兩種模式,通過構(gòu)造函數(shù)來初始化對象的屬性救氯,通過原型對象來實現(xiàn)函數(shù)方法的復(fù)用找田。
這種方法很好的解決了兩種模式單獨(dú)使用時的缺點(diǎn),但是有一點(diǎn)不足的就是着憨,因為使用了兩種不同的模式墩衙,所以對于代碼的封裝性不夠好。
(5)第五種模式是動態(tài)原型模式甲抖。
這一種模式將原型方法賦值的創(chuàng)建過程移動到了構(gòu)造函數(shù)的內(nèi)部漆改,通過對屬性是否存在的判斷,可以實現(xiàn)僅在第一次調(diào)用函數(shù)時對原型對象賦值一次的效果准谚。這一種方式很好地對上面的混合模式進(jìn)行了封裝挫剑。
(6)第六種模式是寄生構(gòu)造函數(shù)模式。
這一種模式和工廠模式的實現(xiàn)基本相同柱衔,我對這個模式的理解是暮顺,它主要是基于一個已有的類型,在實例化時對實例化的對象進(jìn)行擴(kuò)展秀存。這樣既不用修改原來的構(gòu)造函數(shù)捶码,也達(dá)到了擴(kuò)展對象的目的。它的一個缺點(diǎn)和工廠模式一樣或链,無法實現(xiàn)對象的識別惫恼。
嗯我目前了解到的就是這么幾種方式。
35. JavaScript 繼承的幾種實現(xiàn)方式澳盐?
我了解的 js 中實現(xiàn)繼承的幾種方式有:
(1)第一種是以原型鏈的方式來實現(xiàn)繼承祈纯,但是這種實現(xiàn)方式存在的缺點(diǎn)是,在包含有引用類型的數(shù)據(jù)時叼耙,會被所有的實例對象所共享腕窥,容易造成修改的混亂。還有就是在創(chuàng)建子類型的時候不能向超類型傳遞參數(shù)筛婉。
(2)第二種方式是使用借用構(gòu)造函數(shù)的方式簇爆,這種方式是通過在子類型的函數(shù)中調(diào)用超類型的構(gòu)造函數(shù)來實現(xiàn)的。
這一種方法解決了不能向超類型傳遞參數(shù)的缺點(diǎn)爽撒,但是它存在的一個問題就是無法實現(xiàn)函數(shù)方法的復(fù)用入蛆,并且超類型原型定義的方法子類型也沒有辦法訪問到。
(3)第三種方式是組合繼承硕勿,組合繼承是將原型鏈和借用構(gòu)造函數(shù)組合起來使用的一種方式哨毁。通過借用構(gòu)造函數(shù)的方式來實現(xiàn)類型的屬性的繼承,通過將子類型的原型設(shè)置為超類型的實例來實現(xiàn)方法的繼承源武。
這種方式解決了上面的兩種模式單獨(dú)使用時的問題扼褪,但是由于我們是以超類型的實例來作為子類型的原型想幻,所以調(diào)用了兩次超類的構(gòu)造函數(shù),造成了子類型的原型中多了很多不必要的屬性话浇。
(4)第四種方式是原型式繼承举畸,原型式繼承的主要思路就是基于已有的對象來創(chuàng)建新的對象,實現(xiàn)的原理是凳枝,向函數(shù)中傳入一個對象,然后返回一個以這個對象為原型的對象跋核。
這種繼承的思路主要不是為了實現(xiàn)創(chuàng)造一種新的類型岖瑰,只是對某個對象實現(xiàn)一種簡單繼承秃臣,ES5 中定義的 Object.create() 方法就是原型式繼承的實現(xiàn)阀坏。缺點(diǎn)與原型鏈方式相同。
(5)第五種方式是寄生式繼承琳拭,寄生式繼承的思路是創(chuàng)建一個用于封裝繼承過程的函數(shù)刻伊,通過傳入一個對象露戒,然后復(fù)制一個對象的副本,然后對象進(jìn)行擴(kuò)展捶箱,最后返回這個對象智什。這個擴(kuò)展的過程就可以理解是一種繼承。這種繼承的優(yōu)點(diǎn)就是對一個簡單對象實現(xiàn)繼承丁屎,如果這個對象不是我們的自定義類型時荠锭。缺點(diǎn)是沒有辦法實現(xiàn)函數(shù)的復(fù)用。
(6)第六種方式是寄生式組合繼承晨川,組合繼承的缺點(diǎn)就是使用超類型的實例做為子類型的原型证九,導(dǎo)致添加了不必要的原型屬性。寄生式組合繼承的方式是使用超類型的原型的副本來作為子類型的原型共虑,這樣就避免了創(chuàng)建不必要的屬性愧怜。
36. 寄生式組合繼承的實現(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);
Student.prototype.constructor = Student;
Student.prototype.sayMyGrade = function() {
console.log("My grade is " + this.grade + ".");
};
37. Javascript 的作用域鏈妈拌?
作用域鏈的作用是保證對執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問拥坛,通過作用域鏈,我們可以訪問到外層環(huán)境的變量和
函數(shù)尘分。
作用域鏈的本質(zhì)上是一個指向變量對象的指針列表渴逻。變量對象是一個包含了執(zhí)行環(huán)境中所有變量和函數(shù)的對象。作用域鏈的前端始終都是當(dāng)前執(zhí)行上下文的變量對象音诫。全局執(zhí)行上下文的變量對象(也就是全局對象)始終是作用域鏈的最后一個對象惨奕。
當(dāng)我們查找一個變量時,如果當(dāng)前執(zhí)行環(huán)境中沒有找到竭钝,我們可以沿著作用域鏈向后查找梨撞。
作用域鏈的創(chuàng)建過程跟執(zhí)行上下文的建立有關(guān)....
38. 談?wù)?This 對象的理解雹洗。
this 是執(zhí)行上下文中的一個屬性,它指向最后一次調(diào)用這個方法的對象卧波。在實際開發(fā)中时肿,this 的指向可以通過四種調(diào)用模式來判斷。
第一種是函數(shù)調(diào)用模式港粱,當(dāng)一個函數(shù)不是一個對象的屬性時螃成,直接作為函數(shù)來調(diào)用時,this 指向全局對象查坪。
第二種是方法調(diào)用模式寸宏,如果一個函數(shù)作為一個對象的方法來調(diào)用時,this 指向這個對象偿曙。
第三種是構(gòu)造器調(diào)用模式氮凝,如果一個函數(shù)用 new 調(diào)用時,函數(shù)執(zhí)行前會新創(chuàng)建一個對象望忆,this 指向這個新創(chuàng)建的對象罩阵。
第四種是 apply 、 call 和 bind 調(diào)用模式启摄,這三個方法都可以顯示的指定調(diào)用函數(shù)的 this 指向稿壁。
其中 apply 方法接收兩個參數(shù):一個是 this 綁定的對象,一個是參數(shù)數(shù)組歉备。call 方法接收的參數(shù)常摧,第一個是 this 綁定的對象,后面的其余參數(shù)是傳入函數(shù)執(zhí)行的參數(shù)威创。
也就是說落午,在使用 call() 方法時,傳遞給函數(shù)的參數(shù)必須逐個列舉出來肚豺。bind 方法通過傳入一個對象溃斋,返回一個 this 綁定了傳入對象的新函數(shù)。這個函數(shù)的 this 指向除了使用 new 時會被改變吸申,其他情況下都不會改變梗劫。
這四種方式,使用構(gòu)造器調(diào)用模式的優(yōu)先級最高截碴,然后是 apply 梳侨、 call 和 bind 調(diào)用模式,然后是方法調(diào)用模式日丹,然后是函數(shù)調(diào)用模式走哺。
39. eval 是做什么的?
它的功能是把對應(yīng)的字符串解析成 JS 代碼并運(yùn)行哲虾。
應(yīng)該避免使用 eval丙躏,不安全择示,非常耗性能(2次,一次解析成 js 語句晒旅,一次執(zhí)行)栅盲。
40. 什么是 DOM 和 BOM?
DOM 指的是文檔對象模型废恋,它指的是把文檔當(dāng)做一個對象來對待谈秫,這個對象主要定義了處理網(wǎng)頁內(nèi)容的方法和接口。
BOM 指的是瀏覽器對象模型鱼鼓,它指的是把瀏覽器當(dāng)做一個對象來對待拟烫,這個對象主要定義了與瀏覽器進(jìn)行交互的法和接口。
BOM的核心是 window蚓哩,而 window 對象具有雙重角色,它既是通過 js 訪問瀏覽器窗口的一個接口上渴,又是一個 Global(全局)對象岸梨。這意味著在網(wǎng)頁中定義的任何對象,變量和函數(shù)稠氮,都作為全局對象的一個屬性或者方法存在曹阔。
window 對象含有 location 對象、navigator 對象隔披、screen 對象等子對象赃份,并且 DOM 的最根本的對象 document 對象也是 BOM 的 window 對象的子對象。
41. 寫一個通用的事件偵聽器函數(shù)奢米。
const EventUtils = {
// 視能力分別使用dom0||dom2||IE方式 來綁定事件
// 添加事件
addEvent: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
// 移除事件
removeEvent: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
},
// 獲取事件目標(biāo)
getTarget: function(event) {
return event.target || event.srcElement;
},
// 獲取 event 對象的引用抓韩,取到事件的所有信息,確保隨時能使用 event
getEvent: function(event) {
return event || window.event;
},
// 阻止事件(主要是事件冒泡鬓长,因為 IE 不支持事件捕獲)
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
},
// 取消事件的默認(rèn)行為
preventDefault: function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
}
};
42. 事件是什么谒拴?IE 與火狐的事件機(jī)制有什么區(qū)別? 如何阻止冒泡涉波?
(1)事件是用戶操作網(wǎng)頁時發(fā)生的交互動作英上,比如 click/move, 事件除了用戶觸發(fā)的動作外啤覆,還可以是文檔加載苍日,窗口滾動和大小調(diào)整。事件被封裝成一個 event 對象窗声,包含了該事件發(fā)生時的所有相關(guān)信息( event 的屬性)以及可以對事件進(jìn)行的操作( event 的方法)相恃。
(2)事件處理機(jī)制:IE 支持事件冒泡、Firefox 同時支持兩種事件模型笨觅,也就是:事件冒泡和事件捕獲豆茫。
(3)event.stopPropagation() 或者 ie 下的方法 event.cancelBubble = true;
43. 三種事件模型是什么侨歉?
事件是用戶操作網(wǎng)頁時發(fā)生的交互動作或者網(wǎng)頁本身的一些操作,現(xiàn)代瀏覽器一共有三種事件模型揩魂。
第一種事件模型是最早的 DOM0 級模型幽邓,這種模型不會傳播,所以沒有事件流的概念火脉,但是現(xiàn)在有的瀏覽器支持以冒泡的方式實現(xiàn)牵舵,它可以在網(wǎng)頁中直接定義監(jiān)聽函數(shù),也可以通過 js 屬性來指定監(jiān)聽函數(shù)倦挂。這種方式是所有瀏覽器都兼容的畸颅。
第二種事件模型是 IE 事件模型,在該事件模型中方援,一次事件共有兩個過程没炒,事件處理階段,和事件冒泡階段犯戏。
事件處理階段會首先執(zhí)行目標(biāo)元素綁定的監(jiān)聽事件送火。然后是事件冒泡階段,冒泡指的是事件從目標(biāo)元素冒泡到 document先匪,依次檢查經(jīng)過的節(jié)點(diǎn)是否綁定了事件監(jiān)聽函數(shù)种吸,如果有則執(zhí)行。這種模型通過 attachEvent 來添加監(jiān)聽函數(shù)呀非,可以添加多個監(jiān)聽函數(shù)坚俗,會按順序依次執(zhí)行。
第三種是 DOM2 級事件模型岸裙,在該事件模型中猖败,一次事件共有三個過程,第一個過程是事件捕獲階段降允。
捕獲指的是事件從 document 一直向下傳播到目標(biāo)元素辙浑,依次檢查經(jīng)過的節(jié)點(diǎn)是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行拟糕。
后面兩個階段和 IE 事件模型的兩個階段相同判呕。這種事件模型,事件綁定的函數(shù)是 addEventListener送滞,其中第三個參數(shù)可以指定事件是否在捕獲階段執(zhí)行侠草。
44. 事件委托是什么?
事件委托本質(zhì)上是利用了瀏覽器事件冒泡的機(jī)制犁嗅。因為事件在冒泡過程中會上傳到父節(jié)點(diǎn)边涕,并且父節(jié)點(diǎn)可以通過事件對象獲取到目標(biāo)節(jié)點(diǎn),因此可以把子節(jié)點(diǎn)的監(jiān)聽函數(shù)定義在父節(jié)點(diǎn)上,由父節(jié)點(diǎn)的監(jiān)聽函數(shù)統(tǒng)一處理多個子元素的事件功蜓,這種方式稱為事件代理园爷。
使用事件代理我們可以不必要為每一個子元素都綁定一個監(jiān)聽事件,這樣減少了內(nèi)存上的消耗式撼。并且使用事件代理我們還可以實現(xiàn)事件的動態(tài)綁定童社,比如說新增了一個子節(jié)點(diǎn),我們并不需要單獨(dú)地為它添加一個監(jiān)聽事件著隆,它所發(fā)生的事件會交給父元素中的監(jiān)聽函數(shù)來處理扰楼。
45. ["1", "2", "3"].map(parseInt) 答案是多少?
parseInt() 函數(shù)能解析一個字符串美浦,并返回一個整數(shù)弦赖,需要兩個參數(shù) (val, radix),其中 radix 表示要解析的數(shù)字的基數(shù)浦辨。(該值介于 2 ~ 36 之間蹬竖,并且字符串中的數(shù)字不能大于 radix 才能正確返回數(shù)字結(jié)果值)。
此處 map 傳了 3 個參數(shù) (element, index, array)流酬,默認(rèn)第三個參數(shù)被忽略掉币厕,因此三次傳入的參數(shù)分別為 "1-0", "2-1", "3-2"
因為字符串的值不能大于基數(shù),因此后面兩次調(diào)用均失敗康吵,返回 NaN 劈榨,第一次基數(shù)為 0 访递,按十進(jìn)制解析返回 1晦嵌。
46. 什么是閉包,為什么要用它拷姿?
閉包是指有權(quán)訪問另一個函數(shù)作用域中變量的函數(shù)惭载,創(chuàng)建閉包的最常見的方式就是在一個函數(shù)內(nèi)創(chuàng)建另一個函數(shù),創(chuàng)建的函數(shù)可以訪問到當(dāng)前函數(shù)的局部變量响巢。
閉包有兩個常用的用途描滔。
閉包的第一個用途是使我們在函數(shù)外部能夠訪問到函數(shù)內(nèi)部的變量。通過使用閉包踪古,我們可以通過在外部調(diào)用閉包函數(shù)含长,從而在外部訪問到函數(shù)內(nèi)部的變量,可以使用這種方法來創(chuàng)建私有變量伏穆。
函數(shù)的另一個用途是使已經(jīng)運(yùn)行結(jié)束的函數(shù)上下文中的變量對象繼續(xù)留在內(nèi)存中拘泞,因為閉包函數(shù)保留了這個變量對象的引用,所以這個變量對象不會被回收枕扫。
其實閉包的本質(zhì)就是作用域鏈的一個特殊的應(yīng)用陪腌,只要了解了作用域鏈的創(chuàng)建過程,就能夠理解閉包的實現(xiàn)原理。
47. javascript 代碼中的 "use strict"; 是什么意思 ? 使用它區(qū)別是什么诗鸭?
相關(guān)知識點(diǎn):
use strict 是一種 ECMAscript5 添加的(嚴(yán)格)運(yùn)行模式染簇,這種模式使得 Javascript 在更嚴(yán)格的條件下運(yùn)行。
設(shè)立"嚴(yán)格模式"的目的强岸,主要有以下幾個:
- 消除 Javascript 語法的一些不合理锻弓、不嚴(yán)謹(jǐn)之處,減少一些怪異行為;
- 消除代碼運(yùn)行的一些不安全之處请唱,保證代碼運(yùn)行的安全弥咪;
- 提高編譯器效率,增加運(yùn)行速度十绑;
- 為未來新版本的 Javascript 做好鋪墊聚至。
區(qū)別:
- 禁止使用 with 語句。
- 禁止 this 關(guān)鍵字指向全局對象本橙。
- 對象不能有重名的屬性扳躬。
回答:
use strict 指的是嚴(yán)格運(yùn)行模式,在這種模式對 js 的使用添加了一些限制甚亭。比如說禁止 this 指向全局對象贷币,還有禁止使用 with 語句等。
設(shè)立嚴(yán)格模式的目的亏狰,主要是為了消除代碼使用中的一些不安全的使用方式役纹,也是為了消除 js 語法本身的一些不合理的地方,以此來減少一些運(yùn)行時的怪異的行為暇唾。同時使用嚴(yán)格運(yùn)行模式也能夠提高編譯的效率促脉,從而提高代碼的運(yùn)行速度。
我認(rèn)為嚴(yán)格模式代表了 js 一種更合理策州、更安全瘸味、更嚴(yán)謹(jǐn)?shù)陌l(fā)展方向。
48. 如何判斷一個對象是否屬于某個類够挂?
第一種方式是使用 instanceof 運(yùn)算符來判斷構(gòu)造函數(shù)的 prototype 屬性是否出現(xiàn)在對象的原型鏈中的任何位置旁仿。
第二種方式可以通過對象的 constructor 屬性來判斷,對象的 constructor 屬性指向該對象的構(gòu)造函數(shù)孽糖,但是這種方式不是很安全枯冈,因為 constructor 屬性可以被改寫。
第三種方式办悟,如果需要判斷的是某個內(nèi)置的引用類型的話尘奏,可以使用 Object.prototype.toString()
方法來打印對象的[[Class]]
屬性來進(jìn)行判斷。
49. instanceof 的作用誉尖?
instanceof 運(yùn)算符用于判斷構(gòu)造函數(shù)的 prototype 屬性是否出現(xiàn)在對象的原型鏈中的任何位置罪既。
實現(xiàn):
function myInstanceof(left, right) {
let proto = Object.getPrototypeOf(left), // 獲取對象的原型
prototype = right.prototype; // 獲取構(gòu)造函數(shù)的 prototype 對象
// 判斷構(gòu)造函數(shù)的 prototype 對象是否在對象的原型鏈上
while (true) {
if (!proto) return false;
if (proto === prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}
50. new 操作符具體干了什么呢?如何實現(xiàn)?
(1)首先創(chuàng)建了一個新的空對象
(2)設(shè)置原型琢感,將對象的原型設(shè)置為函數(shù)的 prototype 對象丢间。
(3)讓函數(shù)的 this 指向這個對象,執(zhí)行構(gòu)造函數(shù)的代碼(為這個新對象添加屬性)
(4)判斷函數(shù)的返回值類型驹针,如果是值類型烘挫,返回創(chuàng)建的對象。如果是引用類型柬甥,就返回這個引用類型的對象饮六。
實現(xiàn):
function objectFactory() {
let newObject = null,
constructor = Array.prototype.shift.call(arguments),
result = null;
// 參數(shù)判斷
if (typeof constructor !== "function") {
console.error("type error");
return;
}
// 新建一個空對象,對象的原型為構(gòu)造函數(shù)的 prototype 對象
newObject = Object.create(constructor.prototype);
// 將 this 指向新建對象苛蒲,并執(zhí)行函數(shù)
result = constructor.apply(newObject, arguments);
// 判斷返回對象
let flag =
result && (typeof result === "object" || typeof result === "function");
// 判斷返回結(jié)果
return flag ? result : newObject;
}
// 使用方法
// objectFactory(構(gòu)造函數(shù), 初始化參數(shù));
作者:CavsZhouyou
轉(zhuǎn)載鏈接:
https://github.com/CavsZhouyou/Front-End-Interview-Notebook
文源網(wǎng)絡(luò)卤橄,僅供學(xué)習(xí)之用,如有侵權(quán)請聯(lián)系刪除臂外。
我將面試題和答案都整理成了PDF文檔窟扑,還有一套學(xué)習(xí)資料,涵蓋Java虛擬機(jī)漏健、spring框架嚎货、Java線程、數(shù)據(jù)結(jié)構(gòu)蔫浆、設(shè)計模式等等殖属,但不僅限于此。
關(guān)注公眾號【java圈子】獲取資料瓦盛,還有優(yōu)質(zhì)文章每日送達(dá)洗显。
Java.png