久以前看過一個(gè)老外寫的帖子,JavaScript Puzzlers!,直譯就是JavaScript難題,里面列舉了44道JavaScript選擇題,大部分都是讓人摸不著頭腦的題目,需要仔細(xì)琢磨一番才能得到正確答案。也有一些作者也沒有解釋清除,直接通過實(shí)驗(yàn)給出答案了。
這44個(gè)問題是在ECMA 262(5.1)環(huán)境下,瀏覽器中試驗(yàn)的,如果是node環(huán)境下可能不同。這是因?yàn)槎攮h(huán)境差異,比如node環(huán)境下頂層變量是global,瀏覽器環(huán)境下則是windows。
本文部分內(nèi)容也參考了文章Javascript 變態(tài)題解析。
["1", "2", "3"].map(parseInt)結(jié)果是什么?
map方法指定一個(gè)回調(diào)函數(shù),重新創(chuàng)建一個(gè)由回調(diào)函數(shù)返回值組成的新數(shù)組。該方法的原型是:
var new_array=arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
map接受2個(gè)參數(shù),一個(gè)是回調(diào)函數(shù)callback,一個(gè)是回調(diào)函數(shù)的this值。
解釋如下:
Number.parseInt接受兩個(gè)參數(shù),原型Number.parseInt(string[, radix]),一個(gè)是要解析的值,一般是字符串,如果不是的話,使用toString方法將它轉(zhuǎn)化為字符串。參數(shù)radix,是一個(gè)介于2到36之間的整數(shù),如果省略該值或者為0,則按照10進(jìn)制來解析,也就是說默認(rèn)值是10,如果是“0x”或者“0X”開頭,則以16進(jìn)制為基數(shù)。如果小于2或者大于36,則parseInt返回NaN。
也就是說[].map(parseInt)這種寫法根本就是想當(dāng)然的,本題相當(dāng)于下面的三句:
parseInt('1', 0);parseInt('2', 1);parseInt('3', 2);
這三句只有第一句會把第二個(gè)參數(shù)0默認(rèn)為10,剩下兩句都不滿足radix參數(shù)介于2到36之間,所有返回[1, NaN, NaN]。另外,如果想得到正確的結(jié)果,應(yīng)該這樣寫["1", "2", "2"].map(i=> parseInt(i))。
運(yùn)行[typeof null, null instanceof Object]這個(gè)表達(dá)式結(jié)果是什么?,這個(gè)主要考察typeof,instanceof兩個(gè)操作符,前者是返回一個(gè)字符串表示未經(jīng)計(jì)算的操作數(shù)的類型,后者是判斷null的原型鏈中是否出現(xiàn)了Object的構(gòu)造函數(shù)的property。
這兩個(gè)操作符用來判斷類型,前者常用來判斷字面量,后者用來判斷對象的類型,但是兩個(gè)都有缺陷,詳見另一篇文章《javascript中判斷數(shù)據(jù)類型》
但是null是一個(gè)比較特殊的值,type of null返回的是“objec”,這是因?yàn)镴avaScript最初實(shí)現(xiàn)中,值是由一個(gè)表示類型的標(biāo)簽和實(shí)際數(shù)值表示的。對象的類型標(biāo)簽是0,由于null代表是空指針(大多數(shù)平臺下值為0x00),因此null的類型標(biāo)簽是0,typeof null也就返回“object”。
null是所有原型鏈的最頂端,null instanceof Object返回false,假設(shè)null這個(gè)值有構(gòu)造函數(shù)Null,obj instanceof Null才會返回true。
所以上面表達(dá)式返回["object", false]。
表達(dá)式[ [3,2,1].reduce(Math.pow), [].reduce(Math.pow) ]返回什么?
和第1題有些類似。arr.reduce方法對數(shù)組中每個(gè)元素執(zhí)行一個(gè)自定義的reducer函數(shù)(升序執(zhí)行),并將結(jié)果匯總為單個(gè)值,這個(gè)常常用來累加一個(gè)數(shù)組中的數(shù)字。原型如下:
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
注意:如果沒有提供initialValue,reduce 會從索引1的地方開始執(zhí)行 callback 方法,跳過第一個(gè)索引。如果提供initialValue,從索引0開始。
回調(diào)函數(shù)第一次執(zhí)行時(shí),accumulator 和currentValue的取值有兩種情況:
如果調(diào)用reduce()時(shí)提供了initialValue,accumulator取值為initialValue,currentValue取數(shù)組中的第一個(gè)值;如果沒有提供 initialValue,那么accumulator取數(shù)組中的第一個(gè)值,currentValue取數(shù)組中的第二個(gè)值。如果數(shù)組為空且沒有提供initialValue,會拋出TypeError 。如果數(shù)組僅有一個(gè)元素(無論位置如何)并且沒有提供initialValue, 或者有提供initialValue但是數(shù)組為空,那么此唯一值將被返回并且callback不會被執(zhí)行。
Math.pow(base, exponent),返回基數(shù)base的指數(shù)exponent次冪,即baseexponent。
上面表達(dá)式調(diào)用reduce方法的時(shí)候沒有提供initialValue,從索引1開始執(zhí)行,第一次執(zhí)行的時(shí)候accumulator取arr[0],這里是3,currentValue取第二個(gè)值,這里是2,傳給Math.pow,得到9。
第二個(gè)表達(dá)式是在空數(shù)組上調(diào)用reduce,并且沒有提供initialValue,所以拋出錯(cuò)誤:VM146:1 Uncaught TypeError: Reduce of empty array with no initial value at Array.reduce (<anonymous>)。
最后整個(gè)表達(dá)式的結(jié)果還是拋出錯(cuò)誤。
var val='smtg';
console.log('Value is ' + (val==='smtg') ? 'Something' : 'Nothing');
上面的表達(dá)式輸出結(jié)果是什么?這個(gè)問題考察的是加號和三元運(yùn)算的優(yōu)先級,由于加號的優(yōu)先級高于三元表達(dá)式,所以實(shí)際執(zhí)行的是:
console.log('Value is true' ? 'Something' : 'Nothing');
因此最后輸出“Something”。
var name='World!';
(function () {
if (typeof name==='undefined') {
var name='Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
上面表達(dá)式輸出什么?
這個(gè)是考察var變量提升問題,使用var申明的變量會提神到函數(shù)頂部,但是并不會初始化,這個(gè)是JavaScript內(nèi)部機(jī)制。于是上面語句相當(dāng)于:
var name='World!';
(function () {
var name=undefined;
if (typeof name==='undefined') {
var name='Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
name的聲明放在了函數(shù)頂部,但是值是undefined。因?yàn)榇a又放在一個(gè)閉包里,用外層那個(gè)name=“world”是不能訪問的,閉包有隔離變量的作用。最后,上面的語句輸出“Goodbye Jack”。
var END=Math.pow(2, 53);
var START=END - 100;
var count=0;
for (var i=START; i <=END; i++) {
count++;
}
console.log(count);
上面表達(dá)式輸出什么?
乍一看是100,其實(shí)是干擾,這考察的不是循環(huán),var變量啥的,而是JavaScript能表示的最大的數(shù)字是253,即次冪表達(dá)式Math.pow(2, 53)。在這個(gè)最大數(shù)的基礎(chǔ)上加上一個(gè)整數(shù)得到的結(jié)果都是不準(zhǔn)確的。看下面的例子:
題目只能有30個(gè)字,不能寫全,其實(shí)今天我們要學(xué)習(xí)的內(nèi)容有三個(gè),第一,下拉列表表單,第二,多行文字輸入表單,第三,數(shù)據(jù)集表單。
開始學(xué)習(xí)吧!
前天和昨天我們在《HTML表單元素初識1——零基礎(chǔ)自學(xué)網(wǎng)頁制作》和《HTML表單元素初識2——零基礎(chǔ)自學(xué)網(wǎng)頁制作》中基本上把<input/>標(biāo)簽的type屬性里不同的值進(jìn)行了講解與實(shí)踐,今天我們來學(xué)習(xí)其他包含在<form></form>之間的元素。
帶有下拉列表的表單
我們在一些網(wǎng)站填寫注冊信息時(shí),經(jīng)常會遇到選擇"生活所在地"的操作,因?yàn)橹袊牡孛枪潭ǖ模虼隧撁鏁槲覀兲峁┮粋€(gè)下拉列表選項(xiàng),我們直接點(diǎn)選即可,就不需要輸入文字了,這樣操作的好處在于不會出現(xiàn)拼寫錯(cuò)誤。例如:
寫這個(gè)功能我們需要介紹一組新標(biāo)簽<select></select>。"select"(選擇)。在這個(gè)標(biāo)簽中再添加<option></option>。"option"(選項(xiàng))。這樣就可以寫出帶有下拉列表的表單了,示例代碼如下:
<select><option></option></select>
這段代碼我們繼續(xù)在昨天的"表單.html"文件中添加即可,在<input type="image" src="img/示例圖片/submit.jpg"/><br>這段代碼之前即可!與這個(gè)圖片提交按鈕共用一個(gè)<form></form>標(biāo)簽!
下面我們?yōu)槎噙x表單添加名稱,示例代碼如下:
請選擇省份<select><option></option></select>
下面我們添加不同選項(xiàng),示例代碼如下:
請選擇省份
<select >
<option >河北</option>
<option >山東</option>
<option >河南</option>
<option >海南</option>
<option >江蘇</option>
<option >安徽</option>
</select>
<br><br>
為了規(guī)范起見,我們?yōu)楸韱涡畔⑻砑觧ame和value屬性,示例代碼如下:
請選擇省份
<select name="province">
<option value="Hebei">河北</option>
<option value="Shandong">山東</option>
<option value="Henan">河南</option>
<option value="Hainan">海南</option>
<option value="Jiangsu">江蘇</option>
<option value="Anhui">安徽</option>
</select>
<br><br>
大家要注意的是,在下拉列表表單中,name寫在<select>中,value寫在<option>中。
頁面效果如下:
這里告訴大家一個(gè)規(guī)律,下拉列表表單默認(rèn)顯示第一個(gè)<option></option>中的文字內(nèi)容。
如果您想改變這個(gè)默認(rèn)顯示,請?jiān)谛枰@示的<option>中添加selected屬性,并賦值為"selected"。
示例代碼如下:
請選擇省份
<select name="province">
<option value="Hebei">河北</option>
<option value="Shandong">山東</option>
<option value="Henan" selected="selected">河南</option>
<!--選中這個(gè)選項(xiàng)--><option value="Hainan">海南</option><option value="Jiangsu">江蘇</option><option value="Anhui">安徽</option></select><br><br>
頁面效果如圖:
多行文字輸入表單
我們在西瓜視頻上發(fā)布視頻時(shí)會被要求填寫視頻描述,頁面中的輸入框不是像下圖這么短的單行輸入框。
而是多行輸入框,如圖:
使用<textarea></textarea>標(biāo)簽即可添加這樣的輸入框,不過要設(shè)置row(列)和cols(行)屬性的數(shù)值。示例代碼如下:
<br>請簡要描述您的劇本的情節(jié)<br><textarea row="3" cols="20"></textarea><br>
這段代碼添加到</select><br><br>之后,與其共同使用一個(gè)<form></form>標(biāo)簽。
下面我們?yōu)檫@個(gè)多行輸入框添加一些提示和限制。
首先,添加提示文字,和type="text"的<input/>標(biāo)簽一樣,都是使用placeholder屬性。
第二,我們限制一下字?jǐn)?shù),使用maxlength(最大長度)屬性。
第三,在頁面加載完成后,直接讓光標(biāo)停留在輸入框中,使用autofocus屬性。
下面看看如何寫吧,示例代碼如下:(不要忘記寫好name屬性?。?/p>
<br>
請簡要描述您的劇本的情節(jié)<br>
<textarea row="3" cols="20" name="storyOutLine"placeholder="最多輸入80字"maxlength="80"autofocus></textarea><br>
頁面效果如圖:
如果刷新頁面不能正確顯示,請嘗試關(guān)閉后重新打開!
數(shù)據(jù)集表單
數(shù)據(jù)集表單實(shí)際上就是一個(gè)將不同選項(xiàng)或信息打包上傳的設(shè)置。
當(dāng)一組表單元素放到 <fieldset> 標(biāo)簽內(nèi)時(shí),瀏覽器會以特殊方式來顯示它們,它們可能有特殊的邊界、3D 效果,或者甚至可創(chuàng)建一個(gè)子表單來處理這些元素。(W3school)
這個(gè)數(shù)據(jù)集有三個(gè)部分組成,首先是<fliedset></fliedset>,這個(gè)標(biāo)簽不會顯示,只是告訴瀏覽器這里的數(shù)據(jù)要打包。
第二是<legend></legend>,"legend"(說明),這里添加數(shù)據(jù)集名稱。
第三就是我們之前學(xué)到的那些標(biāo)簽了。
示例代碼如下:
<fliedset> <legend>信息打包</legend> </fliedset>
下面我們使用這段代碼把form2打包一下吧。示例代碼如下:
<form>
<fieldset><!--開始-->
<legend>信息打包</legend><br>
<!--標(biāo)題-->興趣愛好:<br>
<input type="checkbox" name="hobby" value="reading"/>讀書
<input type="checkbox" name="hobby" value="film"/>電影
<input type="checkbox" name="hobby" value="painting"/>繪畫
<input type="checkbox" name="hobby" value="music"/>音樂
<br>
最高學(xué)歷:<br>
<input type="radio" name="education" value="highSchool"/>高中
<input type="radio" name="education" value="bachelor"/>本科
<input type="radio" name="education" value="master"/>碩士
<input type="radio" name="education" value="doctor"/>博士
<br>
請選擇省份
<select name="province">
<option value="Hebei">河北</option>
<option value="Shandong">山東</option>
<option value="Henan" selected="selected">河南</option><!--選中這個(gè)選項(xiàng)-->
<option value="Hainan">海南</option>
<option value="Jiangsu">江蘇</option>
<option value="Anhui">安徽</option>
</select>
<br><br><br>
請簡要描述您的劇本的情節(jié)<br>
<textarea row="3" cols="20" name="storyOutLine"placeholder="最多輸入80字"maxlength="80"autofocus></textarea>
<br>
</fieldset><!--結(jié)尾-->
<input type="image" src="img/示例圖片/submit.jpg"/><br>
<input type="reset" /><br>
<input type="submit" value="submit"/>
</form>
頁面效果如下:
今天的內(nèi)容結(jié)束了!
如果您喜歡我的教程請關(guān)注我,點(diǎn)贊也能讓我充滿動力!
HTML序章(學(xué)習(xí)目的、對象、基本概念)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML是什么?——零基礎(chǔ)自學(xué)網(wǎng)頁制作
第一個(gè)HTML頁面如何寫?——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML頁面中head標(biāo)簽有啥用?——零基礎(chǔ)自學(xué)網(wǎng)頁制作
初識meta標(biāo)簽與SEO——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML中的元素使用方法1——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML中的元素使用方法2——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML元素中的屬性1——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML元素中的屬性2(路徑詳解)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
使用HTML添加表格1(基本元素)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
使用HTML添加表格2(表格頭部與腳部)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
使用HTML添加表格3(間距與顏色)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
使用HTML添加表格4(行顏色與表格嵌套)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
16進(jìn)制顏色表示與RGB色彩模型——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML中的塊級元素與內(nèi)聯(lián)元素——零基礎(chǔ)自學(xué)網(wǎng)頁制作
初識HTML中的<div>塊元素——零基礎(chǔ)自學(xué)網(wǎng)頁制作
在HTML頁面中嵌入其他頁面的方法——零基礎(chǔ)自學(xué)網(wǎng)頁制作
封閉在家學(xué)網(wǎng)頁制作!為頁面嵌入PDF文件——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML表單元素初識1——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML表單元素初識2——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML表單3(下拉列表、多行文字輸入)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML表單4(form的action、method屬性)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML列表制作講解——零基礎(chǔ)自學(xué)網(wǎng)頁制作
為HTML頁面添加視頻、音頻的方法——零基礎(chǔ)自學(xué)網(wǎng)頁制作
音視頻格式轉(zhuǎn)換神器與html視頻元素加字幕——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML中使用<a>標(biāo)簽實(shí)現(xiàn)文本內(nèi)鏈接——零基礎(chǔ)自學(xué)網(wǎng)頁制作
最近看到一道跟Javascript中的setTimeout和Promise有關(guān)的面試題,感覺很有趣。題目循序漸進(jìn),不斷深入,雖然只是一道題目的簡單變形,卻考察了很多個(gè)知識點(diǎn),今天我們就一起來看看這道題目吧。
Javascript
我們就直接看題目的代碼,首先是最簡單的原始題目。
原始題目
上述的代碼很簡單,輸出0,1,2,3,4。你可能會疑問,面試題會有這么簡單?放心,好戲還在后頭呢。
我們將上述的代碼加上setTimeout,再進(jìn)行輸出,看看會輸出什么?
變形1
上述代碼每隔一秒會輸出一個(gè)5。
這道題考察的是函數(shù)的閉包,如果不太清楚閉包知識的,可以去看看我寫的這篇文章《前端面試中不可逃避的閉包問題,你真的了解嗎?》。
那么如果我們想要每間隔一秒輸出從0到4,該如何實(shí)現(xiàn)呢?
如果了解閉包知識的話,可以很容易想出通過立即執(zhí)行函數(shù)解決。
變形2
通過上述的代碼,就可以很容易達(dá)到我們的要求。
那么我們繼續(xù)對題目做變形,我們?nèi)サ暨@個(gè)立即執(zhí)行函數(shù)中的i參數(shù),看看結(jié)果會輸出什么?
變形3
通過在控制臺中運(yùn)行,我們發(fā)現(xiàn)結(jié)果和變形1一樣,間隔一秒輸出一個(gè)5,那么為什么會這樣呢?
這是因?yàn)樵诹⒓春瘮?shù)內(nèi)部并沒有對i的引用,實(shí)際的i仍然為外部作用域中的i,所以結(jié)果會和變形1相同。
我們繼續(xù)對這道題目做出變形,將setTimeout中函數(shù)改為一個(gè)立即執(zhí)行函數(shù),看看結(jié)果會是什么?
變形4
通過在控制臺運(yùn)行上述代碼,得到的結(jié)果是立即輸出0, 1, 2, 3, 4。為什么會這樣呢?
根據(jù)setTimeout的用法,它接收的參數(shù)為函數(shù)或者函數(shù)的字符串表示,如果給setTimeout傳遞一個(gè)立即執(zhí)行函數(shù),則相當(dāng)于傳遞了一個(gè)undefined,實(shí)際上是往定時(shí)器線程中添加了5個(gè)undefined。但是由于立即執(zhí)行函數(shù)的存在,這個(gè)函數(shù)會立即執(zhí)行,所以會立即輸出0, 1, 2, ,3 ,4。
如果以上的部分你都能知道,那么我們再來個(gè)更難一點(diǎn)的變形,將setTimeout配合Promise一起使用,看看以下的一段代碼會輸出什么?
變形5
通過在控制臺運(yùn)行以上代碼,我們得到結(jié)果是立即輸出2, 3, 5, 4, 1,這是為什么呢?
首先在代碼的開頭,使用了setTimeout設(shè)置了一個(gè)定時(shí)器,雖然這個(gè)定時(shí)器的時(shí)間為0,但是根據(jù)Javascript中的事件隊(duì)列機(jī)制,會將這個(gè)定時(shí)器添加到專屬的定時(shí)器線程中,等到當(dāng)前線程中的事件回調(diào)執(zhí)行完后才能執(zhí)行。不太懂Javascript的setTimeout機(jī)制的,可以去看看我寫的這篇文章《Javascript中的setTimeout黑魔法》。
然后是定義一個(gè)Promise,這個(gè)Promise會在setTimeout之前執(zhí)行。在Promise中執(zhí)行了兩個(gè)console.log(),所以會先輸出2,3。
在Promise中有一個(gè)for循環(huán),當(dāng)循環(huán)執(zhí)行到i等于9999時(shí),執(zhí)行resolve回調(diào)函數(shù),這個(gè)resolve函數(shù)就是后面輸出4的函數(shù)。但是由于Promise.then()的回調(diào)會在當(dāng)前事件隊(duì)列的最后執(zhí)行,因此4會在5的后面輸出。
在當(dāng)前事件隊(duì)列執(zhí)行完后,才會執(zhí)行setTimeout中的函數(shù),因此1是最后輸出的。
因此輸出結(jié)果是2, 3, 5, 4, 1。
由一道最簡單的題可以通過變形衍生出很多知識點(diǎn)的考題,看看你都會做嗎?
*請認(rèn)真填寫需求信息,我們會在24小時(shí)內(nèi)與您取得聯(lián)系。