前端面試整理—Javascipt問題(一)

image

本章節(jié)是前端開發(fā)者面試問題 - JS 部分的參考答案。 歡迎提出建議和指正默责!

  • 請解釋事件委托(event delegation)囱稽。

  • 請簡述JavaScript中的this惜索。

  • 請解釋原型繼承(prototypal inheritance)的工作原理派昧。

  • 說說你對 AMD 和 CommonJS 的了解黔姜。

  • 請解釋下面代碼為什么不能用作 IIFE:function foo(){ }();拢切,需要作出哪些修改才能使其成為 IIFE蒂萎?

  • nullundefined和未聲明變量之間有什么區(qū)別淮椰?如何檢查判斷這些狀態(tài)值五慈?

  • 什么是閉包(closure),為什么使用閉包主穗?

  • 請說明.forEach循環(huán)和.map()循環(huán)的主要區(qū)別泻拦,它們分別在什么情況下使用?

  • 匿名函數(shù)的典型應(yīng)用場景是什么忽媒?

  • 你如何組織自己的代碼争拐?(使用模塊模式(module pattern)還是經(jīng)典繼承(classical inheritance)?)

  • 宿主對象(host objects)和原生對象(native objects)的區(qū)別是什么晦雨?

  • 下列語句有什么區(qū)別:function Person(){}架曹、var person = Person()var person = newPerson()

  • .call.apply有什么區(qū)別闹瞧?

  • 請說明Function.prototype.bind的用法绑雄。

  • 什么時(shí)候會用到document.write()

  • 功能檢測(feature detection)奥邮、功能推斷(feature inference)和使用 UA 字符串之間有什么區(qū)別万牺?

  • 請盡可能詳細(xì)地解釋 Ajax。

  • 使用Ajax的優(yōu)缺點(diǎn)分別是什么洽腺?

  • 請說明 JSONP 的工作原理脚粟,它為什么不是真正的 Ajax?

  • 你使用過 JavaScript 模板嗎蘸朋?用過什么相關(guān)的庫核无?

  • 請解釋變量提升(hosting)。

  • 請描述事件冒泡度液。

  • “attribute” 和 “property” 之間有什么區(qū)別厕宗?

  • 為什么擴(kuò)展 JavaScript 內(nèi)置對象是不好的做法画舌?

  • document 中的load事件和DOMContentLoaded事件之間的區(qū)別是什么?

  • =====的區(qū)別是什么已慢?

  • 請解釋關(guān)于 JavaScript 的同源策略曲聂。

  • 請使下面的語句生效:

  • 請說明三元表達(dá)式中“三元”這個(gè)詞代表什么?

  • 什么是"use strict";佑惠?使用它有什么優(yōu)缺點(diǎn)朋腋?

  • 創(chuàng)建一個(gè)循環(huán),從1迭代到100膜楷,3的倍數(shù)時(shí)輸出 "fizz"旭咽,5的倍數(shù)時(shí)輸出 "buzz",同時(shí)為35的倍數(shù)時(shí)輸出"fizzbuzz"赌厅。

  • 為什么不要使用全局作用域穷绵?

  • 為什么要使用load事件?這個(gè)事件有什么缺點(diǎn)嗎特愿?你知道一些代替方案嗎仲墨,為什么使用它們?

  • 請解釋單頁應(yīng)用是什么揍障,如何使其對SEO友好目养。

  • 你對 Promises 及其 polyfill 的掌握程度如何?

  • Promise代替回調(diào)函數(shù)有什么優(yōu)缺點(diǎn)毒嫡?

  • 用轉(zhuǎn)譯成 JavaScript 的語言寫 JavaScript 有什么優(yōu)缺點(diǎn)癌蚁?

  • 你使用什么工具和技巧調(diào)試 JavaScript 代碼?

  • 你使用什么語句遍歷對象的屬性和數(shù)組的元素兜畸?

  • 請解釋可變對象和不可變對象之間的區(qū)別努释。

  • 請解釋同步和異步函數(shù)之間的區(qū)別。

  • 什么是事件循環(huán)膳叨?調(diào)用堆棧和任務(wù)隊(duì)列之間有什么區(qū)別洽洁?

  • 請解釋function foo() {}var foo = function() {}之間foo的用法上的區(qū)別。

  • 使用let菲嘴、varconst創(chuàng)建變量有什么區(qū)別饿自?

  • ES6 的類和 ES5 的構(gòu)造函數(shù)有什么區(qū)別?

  • 你能給出一個(gè)使用箭頭函數(shù)的例子嗎龄坪,箭頭函數(shù)與其他函數(shù)有什么不同昭雌?

  • 在構(gòu)造函數(shù)中使用箭頭函數(shù)有什么好處?

  • 高階函數(shù)(higher-order)的定義是什么健田?

  • 請給出一個(gè)解構(gòu)(destructuring)對象或數(shù)組的例子烛卧。

  • ES6 的模板字符串為生成字符串提供了很大的靈活性,你可以舉個(gè)例子嗎?

  • 你能舉出一個(gè)柯里化函數(shù)(curry function)的例子嗎总放?它有哪些好處呈宇?

  • 使用擴(kuò)展運(yùn)算符(spread)的好處是什么,它與使用剩余參數(shù)語句(rest)有什么區(qū)別局雄?

  • 如何在文件之間共用代碼甥啄?

  • 什么情況下會用到靜態(tài)類成員?

請解釋事件委托(event delegation)炬搭。

事件委托是將事件監(jiān)聽器添加到父元素蜈漓,而不是每個(gè)子元素單獨(dú)設(shè)置事件監(jiān)聽器。當(dāng)觸發(fā)子元素時(shí)宫盔,事件會冒泡到父元素融虽,監(jiān)聽器就會觸發(fā)。這種技術(shù)的好處是:

  • 內(nèi)存占用減少灼芭,因?yàn)橹恍枰粋€(gè)父元素的事件處理程序有额,而不必為每個(gè)后代都添加事件處理程序。

  • 無需從已刪除的元素中解綁處理程序姿鸿,也無需將處理程序綁定到新元素上谆吴。

參考

請簡述JavaScript中的this

JS 中的this是一個(gè)相對復(fù)雜的概念苛预,不是簡單幾句能解釋清楚的。粗略地講笋熬,函數(shù)的調(diào)用方式?jīng)Q定了this的值热某。我閱讀了網(wǎng)上很多關(guān)于this的文章,Arnav Aggrawal 寫的比較清楚胳螟。this取值符合以下規(guī)則:

  1. 在調(diào)用函數(shù)時(shí)使用new關(guān)鍵字评也,函數(shù)內(nèi)的this是一個(gè)全新的對象粟焊。

  2. 如果applycallbind方法用于調(diào)用、創(chuàng)建一個(gè)函數(shù)胯府,函數(shù)內(nèi)的 this 就是作為參數(shù)傳入這些方法的對象。

  3. 當(dāng)函數(shù)作為對象里的方法被調(diào)用時(shí)渐尿,函數(shù)內(nèi)的this是調(diào)用該函數(shù)的對象诽凌。比如當(dāng)obj.method()被調(diào)用時(shí),函數(shù)內(nèi)的this將綁定到obj對象舍扰。

  4. 如果調(diào)用函數(shù)不符合上述規(guī)則倦蚪,那么this的值指向全局對象(global object)。瀏覽器環(huán)境下this的值指向window對象边苹,但是在嚴(yán)格模式下('use strict')陵且,this的值為undefined

  5. 如果符合上述多個(gè)規(guī)則个束,則較高的規(guī)則(1號最高慕购,4號最低)將決定this的值聊疲。

  6. 如果該函數(shù)是 ES2015 中的箭頭函數(shù),將忽略上面的所有規(guī)則沪悲,this被設(shè)置為它被創(chuàng)建時(shí)的上下文售睹。

想獲得更深入的解釋,請查看他在 Medium 上的文章可训。

參考

請解釋原型繼承(prototypal inheritance)的工作原理昌妹。

這是一個(gè)非常常見的 JavaScript 問題。所有 JS 對象都有一個(gè)prototype屬性握截,指向它的原型對象飞崖。當(dāng)試圖訪問一個(gè)對象的屬性時(shí),如果沒有在該對象上找到谨胞,它還會搜尋該對象的原型固歪,以及該對象的原型的原型,依次層層向上搜索胯努,直到找到一個(gè)名字匹配的屬性或到達(dá)原型鏈的末尾牢裳。這種行為是在模擬經(jīng)典的繼承,但是與其說是繼承叶沛,不如說是委托(delegation)蒲讯。

參考

說說你對 AMD 和 CommonJS 的了解。

它們都是實(shí)現(xiàn)模塊體系的方式灰署,直到 ES2015 出現(xiàn)之前判帮,JavaScript 一直沒有模塊體系。CommonJS 是同步的溉箕,而AMD(Asynchronous Module Definition)從全稱中可以明顯看出是異步的晦墙。CommonJS 的設(shè)計(jì)是為服務(wù)器端開發(fā)考慮的,而 AMD 支持異步加載模塊肴茄,更適合瀏覽器晌畅。

我發(fā)現(xiàn) AMD 的語法非常冗長,CommonJS 更接近其他語言 import 聲明語句的用法習(xí)慣寡痰。大多數(shù)情況下抗楔,我認(rèn)為AMD 沒有使用的必要,因?yàn)槿绻阉?JavaScript 都捆綁進(jìn)一個(gè)文件中氓癌,將無法得到異步加載的好處谓谦。此外,CommonJS 語法上更接近 Node 編寫模塊的風(fēng)格贪婉,在前后端都使用 JavaScript 開發(fā)之間進(jìn)行切換時(shí)反粥,語境的切換開銷較小。

我很高興看到 ES2015 的模塊加載方案同時(shí)支持同步和異步,我們終于可以只使用一種方案了才顿。雖然它尚未在瀏覽器和Node 中完全推出莫湘,但是我們可以使用代碼轉(zhuǎn)換工具進(jìn)行轉(zhuǎn)換。

參考

請解釋下面代碼為什么不能用作 IIFE:function foo(){ }();郑气,需要作出哪些修改才能使其成為 IIFE幅垮?

IIFE(Immediately Invoked Function Expressions)代表立即執(zhí)行函數(shù)。 JavaScript 解析器將 function foo(){ }();解析成function foo(){ }();尾组。其中忙芒,前者是函數(shù)聲明;后者(一對括號)是試圖調(diào)用一個(gè)函數(shù)讳侨,卻沒有指定名稱呵萨,因此它會拋出Uncaught SyntaxError: Unexpected token )的錯(cuò)誤。

修改方法是:再添加一對括號跨跨,形式上有兩種:(function foo(){ })()(function foo(){ }())潮峦。以上函數(shù)不會暴露到全局作用域,如果不需要在函數(shù)內(nèi)部引用自身勇婴,可以省略函數(shù)的名稱忱嘹。

你可能會用到 void 操作符:void function foo(){ }();。但是耕渴,這種做法是有問題的拘悦。表達(dá)式的值是undefined,所以如果你的 IIFE 有返回值萨螺,不要用這種做法窄做。例如:

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">const foo = void function bar() { return 'foo'; }();console.log(foo); // undefined</pre>

參考

nullundefined和未聲明變量之間有什么區(qū)別慰技?如何檢查判斷這些狀態(tài)值?

當(dāng)你沒有提前使用var组砚、letconst聲明變量吻商,就為一個(gè)變量賦值時(shí),該變量是未聲明變量(undeclaredvariables)糟红。未聲明變量會脫離當(dāng)前作用域艾帐,成為全局作用域下定義的變量。在嚴(yán)格模式下盆偿,給未聲明的變量賦值柒爸,會拋出ReferenceError錯(cuò)誤。和使用全局變量一樣事扭,使用未聲明變量也是非常不好的做法捎稚,應(yīng)當(dāng)盡可能避免。要檢查判斷它們,需要將用到它們的代碼放在try/catch語句中今野。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">function foo() { x = 1; // 在嚴(yán)格模式下葡公,拋出 ReferenceError 錯(cuò)誤}foo();console.log(x); // 1</pre>

當(dāng)一個(gè)變量已經(jīng)聲明,但沒有賦值時(shí)条霜,該變量的值是undefined催什。如果一個(gè)函數(shù)的執(zhí)行結(jié)果被賦值給一個(gè)變量,但是這個(gè)函數(shù)卻沒有返回任何值宰睡,那么該變量的值是undefined蒲凶。要檢查它,需要使用嚴(yán)格相等(===)拆内;或者使用typeof旋圆,它會返回'undefined'字符串。請注意矛纹,不能使用非嚴(yán)格相等(==)來檢查臂聋,因?yàn)槿绻兞恐禐?code>null,使用非嚴(yán)格相等也會返回true或南。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">var foo;console.log(foo); // undefinedconsole.log(foo === undefined); // trueconsole.log(typeof foo === 'undefined'); // trueconsole.log(foo == null); // true. 錯(cuò)誤孩等,不要使用非嚴(yán)格相等!function bar() {}var baz = bar();console.log(baz); // undefined</pre>

null只能被顯式賦值給變量采够。它表示空值肄方,與被顯式賦值 undefined 的意義不同。要檢查判斷null值蹬癌,需要使用嚴(yán)格相等運(yùn)算符权她。請注意,和前面一樣逝薪,不能使用非嚴(yán)格相等(==)來檢查隅要,因?yàn)槿绻兞恐禐?code>undefined,使用非嚴(yán)格相等也會返回true董济。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">var foo = null;console.log(foo === null); // trueconsole.log(foo == undefined); // true. 錯(cuò)誤步清,不要使用非嚴(yán)格相等!</pre>

作為一種個(gè)人習(xí)慣虏肾,我從不使用未聲明變量廓啊。如果定義了暫時(shí)沒有用到的變量,我會在聲明后明確地給它們賦值為null封豪。

參考

什么是閉包(closure)谴轮,為什么使用閉包?

閉包是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合吹埠。詞法作用域中使用的域第步,是變量在代碼中聲明的位置所決定的疮装。閉包是即使被外部函數(shù)返回,依然可以訪問到外部(封閉)函數(shù)作用域的函數(shù)雌续。

為什么使用閉包斩个?

  • 利用閉包實(shí)現(xiàn)數(shù)據(jù)私有化或模擬私有方法。這個(gè)方式也稱為模塊模式(module pattern)驯杜。

  • 部分參數(shù)函數(shù)(partial applications)柯里化(currying).

參考

請說明.forEach循環(huán)和.map()循環(huán)的主要區(qū)別受啥,它們分別在什么情況下使用?

為了理解兩者的區(qū)別鸽心,我們看看它們分別是做什么的滚局。

forEach

  • 遍歷數(shù)組中的元素。

  • 為每個(gè)元素執(zhí)行回調(diào)顽频。

  • 無返回值藤肢。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">const a = [1, 2, 3];const doubled = a.forEach((num, index) => { // 執(zhí)行與 num、index 相關(guān)的代碼});// doubled = undefined</pre>

map

  • 遍歷數(shù)組中的元素

  • 通過對每個(gè)元素調(diào)用函數(shù)糯景,將每個(gè)元素“映射(map)”到一個(gè)新元素嘁圈,從而創(chuàng)建一個(gè)新數(shù)組。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">const a = [1, 2, 3];const doubled = a.map(num => { return num * 2; });// doubled = [2, 4, 6]</pre>

.forEach.map()的主要區(qū)別在于.map()返回一個(gè)新的數(shù)組蟀淮。如果你想得到一個(gè)結(jié)果最住,但不想改變原始數(shù)組,用.map()怠惶。如果你只需要在數(shù)組上做迭代修改涨缚,用forEach

參考

匿名函數(shù)的典型應(yīng)用場景是什么策治?

匿名函數(shù)可以在IIFE中使用脓魏,來封裝局部作用域內(nèi)的代碼,以便其聲明的變量不會暴露到全局作用域通惫。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">(function() { // 一些代碼茂翔。})();</pre>

匿名函數(shù)可以作為只用一次,不需要在其他地方使用的回調(diào)函數(shù)履腋。當(dāng)處理函數(shù)在調(diào)用它們的程序內(nèi)部被定義時(shí)檩电,代碼具有更好地自閉性和可讀性,可以省去尋找該處理函數(shù)的函數(shù)體位置的麻煩府树。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">setTimeout(function() { console.log('Hello world!'); }, 1000);</pre>

匿名函數(shù)可以用于函數(shù)式編程或 Lodash(類似于回調(diào)函數(shù))。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">const arr = [1, 2, 3];const double = arr.map(function(el) { return el * 2; });console.log(double); // [2, 4, 6]</pre>

參考

你如何組織自己的代碼料按?(使用模塊模式(module pattern)還是經(jīng)典繼承(classicalinheritance)奄侠?)

我以前使用 Backbone 組織我的模型(model),Backbone 鼓勵(lì)采用面向?qū)ο蟮姆椒ā獎?chuàng)建 Backbone 模型载矿,并為其添加方法垄潮。

模塊模式仍然是很好的方式烹卒,但是現(xiàn)在我使用基于 React/Redux 的 Flux 體系結(jié)構(gòu),它鼓勵(lì)使用單向函數(shù)編程的方法弯洗。我用普通對象(plain object)表示我的 app 模型旅急,編寫實(shí)用純函數(shù)去操作這些對象。使用動作(actions)和化簡器(reducers)來處理狀態(tài)牡整,就像其他 Redux 應(yīng)用一樣藐吮。

我盡可能避免使用經(jīng)典繼承。如果非要這么做逃贝,我會堅(jiān)持這些原則谣辞。

宿主對象(host objects)和原生對象(native objects)的區(qū)別是什么?

原生對象是由 ECMAScript 規(guī)范定義的 JavaScript 內(nèi)置對象沐扳,比如String泥从、MathRegExp沪摄、Object躯嫉、Function等等。

宿主對象是由運(yùn)行時(shí)環(huán)境(瀏覽器或 Node)提供杨拐,比如window祈餐、XMLHTTPRequest等等。

參考

下列語句有什么區(qū)別:function Person(){}戏阅、var person = Person()varperson = new Person()昼弟?

這個(gè)問題問得很含糊。我猜這是在考察 JavaScript 中的構(gòu)造函數(shù)(constructor)奕筐。從技術(shù)上講舱痘,functionPerson(){}只是一個(gè)普通的函數(shù)聲明。使用 PascalCase 方式命名函數(shù)作為構(gòu)造函數(shù)离赫,是一個(gè)慣例芭逝。

var person = Person()Person以普通函數(shù)調(diào)用,而不是構(gòu)造函數(shù)渊胸。如果該函數(shù)是用作構(gòu)造函數(shù)的旬盯,那么這種調(diào)用方式是一種常見錯(cuò)誤。通常情況下翎猛,構(gòu)造函數(shù)不會返回任何東西胖翰,因此,像普通函數(shù)一樣調(diào)用構(gòu)造函數(shù)切厘,只會返回undefined賦給用作實(shí)例的變量萨咳。

var person = new Person()使用new操作符,創(chuàng)建Person對象的實(shí)例疫稿,該實(shí)例繼承自Person.prototype培他。另外一種方式是使用Object.create鹃两,例如:Object.create(Person.prototype)`。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">function Person(name) { this.name = name; }var person = Person('John');console.log(person); // undefinedconsole.log(person.name); // Uncaught TypeError: Cannot read property 'name' of undefinedvar person = new Person('John');console.log(person); // Person { name: "John" }console.log(person.name); // "john"</pre>

參考

.call.apply有什么區(qū)別舀凛?

.call.apply都用于調(diào)用函數(shù)俊扳,第一個(gè)參數(shù)將用作函數(shù)內(nèi)this的值。然而猛遍,.call接受逗號分隔的參數(shù)作為后面的參數(shù)馋记,而.apply接受一個(gè)參數(shù)數(shù)組作為后面的參數(shù)。一個(gè)簡單的記憶方法是螃壤,從call中的 C 聯(lián)想到逗號分隔(comma-separated)抗果,從apply中的 A 聯(lián)想到數(shù)組(array)。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">function add(a, b) { return a + b; }console.log(add.call(null, 1, 2)); // 3console.log(add.apply(null, [1, 2])); // 3</pre>

請說明Function.prototype.bind的用法奸晴。

摘自MDN:

bind()方法創(chuàng)建一個(gè)新的函數(shù), 當(dāng)被調(diào)用時(shí)冤馏,將其this關(guān)鍵字設(shè)置為提供的值,在調(diào)用新函數(shù)時(shí)寄啼,在任何提供之前提供一個(gè)給定的參數(shù)序列逮光。

根據(jù)我的經(jīng)驗(yàn),將this的值綁定到想要傳遞給其他函數(shù)的類的方法中是非常有用的墩划。在React組件中經(jīng)常這樣做涕刚。

參考

什么時(shí)候會用到document.write()

document.write()用來將一串文本寫入由document.open()打開的文檔流中乙帮。當(dāng)頁面加載后執(zhí)行document.write()時(shí)杜漠,它將調(diào)用document.open,會清除整個(gè)文檔(<head><body>會被移除2炀弧)驾茴,并將文檔內(nèi)容替換成給定的字符串參數(shù)。因此它通常被認(rèn)為是危險(xiǎn)的并且容易被誤用氢卡。

網(wǎng)上有一些答案坪蚁,解釋了document.write()被用于分析代碼中晚树,或者當(dāng)你想包含只有在啟用了 JavaScript 的情況下才能工作的樣式想邦。它甚至在HTML5樣板代碼中用于并行加載腳本并保持執(zhí)行順序劣纲!但是,我懷疑這些使用原因是過時(shí)的筑悴,現(xiàn)在可以在不使用document.write()的情況下實(shí)現(xiàn)们拙。如果我的觀點(diǎn)有錯(cuò),請糾正我阁吝。

參考

功能檢測(feature detection)睛竣、功能推斷(feature inference)和使用 UA 字符串之間有什么區(qū)別?

功能檢測(feature detection)

功能檢測包括確定瀏覽器是否支持某段代碼求摇,以及是否運(yùn)行不同的代碼(取決于它是否執(zhí)行)射沟,以便瀏覽器始終能夠正常運(yùn)行代碼功能,而不會在某些瀏覽器中出現(xiàn)崩潰和錯(cuò)誤与境。例如:

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">if ('geolocation' in navigator) { // 可以使用 navigator.geolocation} else { // 處理 navigator.geolocation 功能缺失}</pre>

Modernizr是處理功能檢測的優(yōu)秀工具验夯。

功能推斷(feature inference)

功能推斷與功能檢測一樣,會對功能可用性進(jìn)行檢查摔刁,但是在判斷通過后挥转,還會使用其他功能,因?yàn)樗僭O(shè)其他功能也可用共屈,例如:

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">if (document.getElementsByTagName) { element = document.getElementById(id); }</pre>

非常不推薦這種方式绑谣。功能檢測更能保證萬無一失。

UA 字符串

這是一個(gè)瀏覽器報(bào)告的字符串拗引,它允許網(wǎng)絡(luò)協(xié)議對等方(network protocol peers)識別請求用戶代理的應(yīng)用類型借宵、操作系統(tǒng)、應(yīng)用供應(yīng)商和應(yīng)用版本矾削。它可以通過navigator.userAgent訪問壤玫。 然而,這個(gè)字符串很難解析并且很可能存在欺騙性哼凯。例如欲间,Chrome 會同時(shí)作為 Chrome 和 Safari 進(jìn)行報(bào)告。因此断部,要檢測 Safari猎贴,除了檢查 Safari 字符串,還要檢查是否存在 Chrome 字符串蝴光。不要使用這種方式她渴。

參考

請盡可能詳細(xì)地解釋 Ajax。

Ajax(asynchronous JavaScript and XML)是使用客戶端上的許多Web技術(shù)虱疏,創(chuàng)建異步Web應(yīng)用的一種Web開發(fā)技術(shù)惹骂。借助Ajax,Web應(yīng)用可以異步(在后臺)向服務(wù)器發(fā)送數(shù)據(jù)和從服務(wù)器檢索數(shù)據(jù)做瞪,而不會干擾現(xiàn)有頁面的顯示和行為对粪。通過將數(shù)據(jù)交換層與表示層分離,Ajax允許網(wǎng)頁和擴(kuò)展Web應(yīng)用程序動態(tài)更改內(nèi)容装蓬,而無需重新加載整個(gè)頁面著拭。實(shí)際上,現(xiàn)在通常將JSON替換為XML牍帚,因?yàn)?JavaScript 對 JSON 有原生支持優(yōu)勢儡遮。

XMLHttpRequest API經(jīng)常用于異步通信。此外還有最近流行的fetch API暗赶。

參考

使用Ajax的優(yōu)缺點(diǎn)分別是什么鄙币?

優(yōu)點(diǎn)

  • 交互性更好肃叶。來自服務(wù)器的新內(nèi)容可以動態(tài)更改,無需重新加載整個(gè)頁面十嘿。

  • 減少與服務(wù)器的連接因惭,因?yàn)槟_本和樣式只需要被請求一次。

  • 狀態(tài)可以維護(hù)在一個(gè)頁面上绩衷。JavaScript 變量和 DOM 狀態(tài)將得到保持蹦魔,因?yàn)橹魅萜黜撁嫖幢恢匦录虞d。

  • 基本上包括大部分 SPA 的優(yōu)點(diǎn)咳燕。

缺點(diǎn)

  • 動態(tài)網(wǎng)頁很難收藏勿决。

  • 如果 JavaScript 已在瀏覽器中被禁用,則不起作用招盲。

  • 有些網(wǎng)絡(luò)爬蟲不執(zhí)行 JavaScript低缩,也不會看到 JavaScript 加載的內(nèi)容。

  • 基本上包括大部分 SPA 的缺點(diǎn)宪肖。

請說明 JSONP 的工作原理表制,它為什么不是真正的 Ajax?

JSONP(帶填充的JSON)是一種通常用于繞過Web瀏覽器中的跨域限制的方法控乾,因?yàn)?Ajax 不允許跨域請求么介。

JSONP 通過<script>標(biāo)簽發(fā)送跨域請求,通常使用callback查詢參數(shù)蜕衡,例如:https://example.com?callback=printData壤短。 然后服務(wù)器將數(shù)據(jù)包裝在一個(gè)名為printData的函數(shù)中并將其返回給客戶端。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;"><script>function printData(data) { console.log(My name is ${data.name}!);}</script> <script src="https://example.com?callback=printData"></script></pre>

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">// 文件加載自 https://example.com?callback=printDataprintData({ name: 'Yang Shun' });</pre>

客戶端必須在其全局范圍內(nèi)具有printData函數(shù)慨仿,并且在收到來自跨域的響應(yīng)時(shí)久脯,該函數(shù)將由客戶端執(zhí)行。

JSONP 可能具有一些安全隱患镰吆。由于 JSONP 是純 JavaScript 實(shí)現(xiàn)帘撰,它可以完成 JavaScript 所能做的一切,因此需要信任 JSONP 數(shù)據(jù)的提供者万皿。

現(xiàn)如今摧找,跨來源資源共享(CORS) 是推薦的主流方式,JSONP 已被視為一種比較 hack 的方式牢硅。

參考

你使用過 JavaScript 模板嗎蹬耘?用過什么相關(guān)的庫?

使用過减余。Handlebars综苔、Underscore、Lodash、AngularJS和JSX如筛。我不喜歡 AngularJS 中的模板堡牡,因?yàn)樗谥噶钪写罅渴褂昧俗址⑶視鴮戝e(cuò)誤會被忽略妙黍。JSX是我的新寵悴侵,因?yàn)樗咏?JavaScript,幾乎沒有什么學(xué)習(xí)成本∈眉蓿現(xiàn)在,可以使用 ES2015 模板字符串快速創(chuàng)建模板抓于,而不需依賴第三方代碼做粤。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">const template = <div>My name is: ${name}</div>;</pre>

但是,請注意上述方法中可能存在的 XSS捉撮,因?yàn)閮?nèi)容不會被轉(zhuǎn)義怕品,與模板庫不同。

請解釋變量提升(hosting)巾遭。

變量提升(hoisting)是用于解釋代碼中變量聲明行為的術(shù)語肉康。使用var關(guān)鍵字聲明或初始化的變量,會將聲明語句“提升”到當(dāng)前作用域的頂部灼舍。 但是吼和,只有聲明才會觸發(fā)提升,賦值語句(如果有的話)將保持原樣骑素。我們用幾個(gè)例子來解釋一下炫乓。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">// 用 var 聲明得到提升console.log(foo); // undefinedvar foo = 1;console.log(foo); // 1// 用 let/const 聲明不會提升console.log(bar); // ReferenceError: bar is not definedlet bar = 2;console.log(bar); // 2</pre>

函數(shù)聲明會使函數(shù)體提升,但函數(shù)表達(dá)式(以聲明變量的形式書寫)只有變量聲明會被提升献丑。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">// 函數(shù)聲明console.log(foo); // [Function: foo]foo(); // 'FOOOOO'function foo() { console.log('FOOOOO'); }console.log(foo); // [Function: foo]// 函數(shù)表達(dá)式console.log(bar); // undefinedbar(); // Uncaught TypeError: bar is not a functionvar bar = function() { console.log('BARRRR'); };console.log(bar); // [Function: bar]</pre>

請描述事件冒泡末捣。

當(dāng)一個(gè)事件在DOM元素上觸發(fā)時(shí),如果有事件監(jiān)聽器创橄,它將嘗試處理該事件箩做,然后事件冒泡到其父級元素,并發(fā)生同樣的事情妥畏。最后直到事件到達(dá)祖先元素邦邦。事件冒泡是實(shí)現(xiàn)事件委托的原理(event delegation)。

“attribute” 和 “property” 之間有什么區(qū)別咖熟?

“Attribute” 是在 HTML 中定義的圃酵,而 “property” 是在 DOM 上定義的。為了說明區(qū)別馍管,假設(shè)我們在 HTML 中有一個(gè)文本框:<input type="text" value="Hello">郭赐。

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">const input = document.querySelector('input');console.log(input.getAttribute('value')); // Helloconsole.log(input.value); // Hello</pre>

但是在文本框中鍵入“ World!”后:

<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">console.log(input.getAttribute('value')); // Helloconsole.log(input.value); // Hello World!</pre>

參考

為什么擴(kuò)展 JavaScript 內(nèi)置對象是不好的做法?

擴(kuò)展 JavaScript 內(nèi)置(原生)對象意味著將屬性或方法添加到其prototype中。雖然聽起來很不錯(cuò)捌锭,但事實(shí)上這樣做很危險(xiǎn)俘陷。想象一下,你的代碼使用了一些庫观谦,它們通過添加相同的 contains 方法來擴(kuò)展Array.prototype拉盾,如果這兩個(gè)方法的行為不相同,那么這些實(shí)現(xiàn)將會相互覆蓋豁状,你的代碼將不能正常運(yùn)行捉偏。

擴(kuò)展內(nèi)置對象的唯一使用場景是創(chuàng)建 polyfill,本質(zhì)上為老版本瀏覽器缺失的方法提供自己的實(shí)現(xiàn)泻红,該方法是由JavaScript 規(guī)范定義的夭禽。

參考

document 中的load事件和DOMContentLoaded事件之間的區(qū)別是什么?

當(dāng)初始的 HTML 文檔被完全加載和解析完成之后谊路,DOMContentLoaded事件被觸發(fā)讹躯,而無需等待樣式表、圖像和子框架的完成加載缠劝。

windowload事件僅在DOM和所有相關(guān)資源全部完成加載后才會觸發(fā)潮梯。

參考

未完,請繼續(xù)閱讀 前端面試整理-Javascipt問題(二)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末惨恭,一起剝皮案震驚了整個(gè)濱河市秉馏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌喉恋,老刑警劉巖沃饶,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異轻黑,居然都是意外死亡糊肤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門氓鄙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來馆揉,“玉大人,你說我怎么就攤上這事抖拦∩ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵态罪,是天一觀的道長噩茄。 經(jīng)常有香客問我,道長复颈,這世上最難降的妖魔是什么绩聘? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上凿菩,老公的妹妹穿的比我還像新娘机杜。我一直安慰自己,他們只是感情好衅谷,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布椒拗。 她就那樣靜靜地躺著,像睡著了一般获黔。 火紅的嫁衣襯著肌膚如雪蚀苛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天玷氏,我揣著相機(jī)與錄音枉阵,去河邊找鬼。 笑死预茄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的侦厚。 我是一名探鬼主播耻陕,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼刨沦!你這毒婦竟也來了诗宣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤想诅,失蹤者是張志新(化名)和其女友劉穎召庞,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體来破,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡篮灼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了徘禁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诅诱。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖送朱,靈堂內(nèi)的尸體忽然破棺而出娘荡,到底是詐尸還是另有隱情,我是刑警寧澤驶沼,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布炮沐,位于F島的核電站,受9級特大地震影響回怜,放射性物質(zhì)發(fā)生泄漏大年。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鲜戒。 院中可真熱鬧专控,春花似錦、人聲如沸遏餐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽失都。三九已至柏蘑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粹庞,已是汗流浹背咳焚。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留庞溜,地道東北人革半。 一個(gè)月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像流码,于是被迫代替她去往敵國和親又官。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容