久以前看过一个老外写的帖子,JavaScript Puzzlers!,直译就是JavaScript难题,里面列举了44道JavaScript选择题,大部分都是让人摸不着头脑的题目,需要仔细琢磨一番才能得到正确答案。也有一些作者也没有解释清除,直接通过实验给出答案了。
这44个问题是在ECMA 262(5.1)环境下,浏览器中试验的,如果是node环境下可能不同。这是因为二者环境差异,比如node环境下顶层变量是global,浏览器环境下则是windows。
本文部分内容也参考了文章Javascript 变态题解析。
["1", "2", "3"].map(parseInt)结果是什么?
map方法指定一个回调函数,重新创建一个由回调函数返回值组成的新数组。该方法的原型是:
var new_array=arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
map接受2个参数,一个是回调函数callback,一个是回调函数的this值。
解释如下:
Number.parseInt接受两个参数,原型Number.parseInt(string[, radix]),一个是要解析的值,一般是字符串,如果不是的话,使用toString方法将它转化为字符串。参数radix,是一个介于2到36之间的整数,如果省略该值或者为0,则按照10进制来解析,也就是说默认值是10,如果是“0x”或者“0X”开头,则以16进制为基数。如果小于2或者大于36,则parseInt返回NaN。
也就是说[].map(parseInt)这种写法根本就是想当然的,本题相当于下面的三句:
parseInt('1', 0);parseInt('2', 1);parseInt('3', 2);
这三句只有第一句会把第二个参数0默认为10,剩下两句都不满足radix参数介于2到36之间,所有返回[1, NaN, NaN]。另外,如果想得到正确的结果,应该这样写["1", "2", "2"].map(i=> parseInt(i))。
运行[typeof null, null instanceof Object]这个表达式结果是什么?,这个主要考察typeof,instanceof两个操作符,前者是返回一个字符串表示未经计算的操作数的类型,后者是判断null的原型链中是否出现了Object的构造函数的property。
这两个操作符用来判断类型,前者常用来判断字面量,后者用来判断对象的类型,但是两个都有缺陷,详见另一篇文章《javascript中判断数据类型》
但是null是一个比较特殊的值,type of null返回的是“objec”,这是因为JavaScript最初实现中,值是由一个表示类型的标签和实际数值表示的。对象的类型标签是0,由于null代表是空指针(大多数平台下值为0x00),因此null的类型标签是0,typeof null也就返回“object”。
null是所有原型链的最顶端,null instanceof Object返回false,假设null这个值有构造函数Null,obj instanceof Null才会返回true。
所以上面表达式返回["object", false]。
表达式[ [3,2,1].reduce(Math.pow), [].reduce(Math.pow) ]返回什么?
和第1题有些类似。arr.reduce方法对数组中每个元素执行一个自定义的reducer函数(升序执行),并将结果汇总为单个值,这个常常用来累加一个数组中的数字。原型如下:
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
注意:如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。
回调函数第一次执行时,accumulator 和currentValue的取值有两种情况:
如果调用reduce()时提供了initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;如果没有提供 initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。如果数组为空且没有提供initialValue,会抛出TypeError 。如果数组仅有一个元素(无论位置如何)并且没有提供initialValue, 或者有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行。
Math.pow(base, exponent),返回基数base的指数exponent次幂,即baseexponent。
上面表达式调用reduce方法的时候没有提供initialValue,从索引1开始执行,第一次执行的时候accumulator取arr[0],这里是3,currentValue取第二个值,这里是2,传给Math.pow,得到9。
第二个表达式是在空数组上调用reduce,并且没有提供initialValue,所以抛出错误:VM146:1 Uncaught TypeError: Reduce of empty array with no initial value at Array.reduce (<anonymous>)。
最后整个表达式的结果还是抛出错误。
var val='smtg';
console.log('Value is ' + (val==='smtg') ? 'Something' : 'Nothing');
上面的表达式输出结果是什么?这个问题考察的是加号和三元运算的优先级,由于加号的优先级高于三元表达式,所以实际执行的是:
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);
}
})();
上面表达式输出什么?
这个是考察var变量提升问题,使用var申明的变量会提神到函数顶部,但是并不会初始化,这个是JavaScript内部机制。于是上面语句相当于:
var name='World!';
(function () {
var name=undefined;
if (typeof name==='undefined') {
var name='Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
name的声明放在了函数顶部,但是值是undefined。因为代码又放在一个闭包里,用外层那个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);
上面表达式输出什么?
乍一看是100,其实是干扰,这考察的不是循环,var变量啥的,而是JavaScript能表示的最大的数字是253,即次幂表达式Math.pow(2, 53)。在这个最大数的基础上加上一个整数得到的结果都是不准确的。看下面的例子:
题目只能有30个字,不能写全,其实今天我们要学习的内容有三个,第一,下拉列表表单,第二,多行文字输入表单,第三,数据集表单。
开始学习吧!
前天和昨天我们在《HTML表单元素初识1——零基础自学网页制作》和《HTML表单元素初识2——零基础自学网页制作》中基本上把<input/>标签的type属性里不同的值进行了讲解与实践,今天我们来学习其他包含在<form></form>之间的元素。
带有下拉列表的表单
我们在一些网站填写注册信息时,经常会遇到选择"生活所在地"的操作,因为中国的地名是固定的,因此页面会为我们提供一个下拉列表选项,我们直接点选即可,就不需要输入文字了,这样操作的好处在于不会出现拼写错误。例如:
写这个功能我们需要介绍一组新标签<select></select>。"select"(选择)。在这个标签中再添加<option></option>。"option"(选项)。这样就可以写出带有下拉列表的表单了,示例代码如下:
<select><option></option></select>
这段代码我们继续在昨天的"表单.html"文件中添加即可,在<input type="image" src="img/示例图片/submit.jpg"/><br>这段代码之前即可!与这个图片提交按钮共用一个<form></form>标签!
下面我们为多选表单添加名称,示例代码如下:
请选择省份<select><option></option></select>
下面我们添加不同选项,示例代码如下:
请选择省份
<select >
<option >河北</option>
<option >山东</option>
<option >河南</option>
<option >海南</option>
<option >江苏</option>
<option >安徽</option>
</select>
<br><br>
为了规范起见,我们为表单信息添加name和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>中。
页面效果如下:
这里告诉大家一个规律,下拉列表表单默认显示第一个<option></option>中的文字内容。
如果您想改变这个默认显示,请在需要显示的<option>中添加selected属性,并赋值为"selected"。
示例代码如下:
请选择省份
<select name="province">
<option value="Hebei">河北</option>
<option value="Shandong">山东</option>
<option value="Henan" selected="selected">河南</option>
<!--选中这个选项--><option value="Hainan">海南</option><option value="Jiangsu">江苏</option><option value="Anhui">安徽</option></select><br><br>
页面效果如图:
多行文字输入表单
我们在西瓜视频上发布视频时会被要求填写视频描述,页面中的输入框不是像下图这么短的单行输入框。
而是多行输入框,如图:
使用<textarea></textarea>标签即可添加这样的输入框,不过要设置row(列)和cols(行)属性的数值。示例代码如下:
<br>请简要描述您的剧本的情节<br><textarea row="3" cols="20"></textarea><br>
这段代码添加到</select><br><br>之后,与其共同使用一个<form></form>标签。
下面我们为这个多行输入框添加一些提示和限制。
首先,添加提示文字,和type="text"的<input/>标签一样,都是使用placeholder属性。
第二,我们限制一下字数,使用maxlength(最大长度)属性。
第三,在页面加载完成后,直接让光标停留在输入框中,使用autofocus属性。
下面看看如何写吧,示例代码如下:(不要忘记写好name属性!)
<br>
请简要描述您的剧本的情节<br>
<textarea row="3" cols="20" name="storyOutLine"placeholder="最多输入80字"maxlength="80"autofocus></textarea><br>
页面效果如图:
如果刷新页面不能正确显示,请尝试关闭后重新打开!
数据集表单
数据集表单实际上就是一个将不同选项或信息打包上传的设置。
当一组表单元素放到 <fieldset> 标签内时,浏览器会以特殊方式来显示它们,它们可能有特殊的边界、3D 效果,或者甚至可创建一个子表单来处理这些元素。(W3school)
这个数据集有三个部分组成,首先是<fliedset></fliedset>,这个标签不会显示,只是告诉浏览器这里的数据要打包。
第二是<legend></legend>,"legend"(说明),这里添加数据集名称。
第三就是我们之前学到的那些标签了。
示例代码如下:
<fliedset> <legend>信息打包</legend> </fliedset>
下面我们使用这段代码把form2打包一下吧。示例代码如下:
<form>
<fieldset><!--开始-->
<legend>信息打包</legend><br>
<!--标题-->兴趣爱好:<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>
最高学历:<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><!--选中这个选项-->
<option value="Hainan">海南</option>
<option value="Jiangsu">江苏</option>
<option value="Anhui">安徽</option>
</select>
<br><br><br>
请简要描述您的剧本的情节<br>
<textarea row="3" cols="20" name="storyOutLine"placeholder="最多输入80字"maxlength="80"autofocus></textarea>
<br>
</fieldset><!--结尾-->
<input type="image" src="img/示例图片/submit.jpg"/><br>
<input type="reset" /><br>
<input type="submit" value="submit"/>
</form>
页面效果如下:
今天的内容结束了!
如果您喜欢我的教程请关注我,点赞也能让我充满动力!
HTML序章(学习目的、对象、基本概念)——零基础自学网页制作
HTML是什么?——零基础自学网页制作
第一个HTML页面如何写?——零基础自学网页制作
HTML页面中head标签有啥用?——零基础自学网页制作
初识meta标签与SEO——零基础自学网页制作
HTML中的元素使用方法1——零基础自学网页制作
HTML中的元素使用方法2——零基础自学网页制作
HTML元素中的属性1——零基础自学网页制作
HTML元素中的属性2(路径详解)——零基础自学网页制作
使用HTML添加表格1(基本元素)——零基础自学网页制作
使用HTML添加表格2(表格头部与脚部)——零基础自学网页制作
使用HTML添加表格3(间距与颜色)——零基础自学网页制作
使用HTML添加表格4(行颜色与表格嵌套)——零基础自学网页制作
16进制颜色表示与RGB色彩模型——零基础自学网页制作
HTML中的块级元素与内联元素——零基础自学网页制作
初识HTML中的<div>块元素——零基础自学网页制作
在HTML页面中嵌入其他页面的方法——零基础自学网页制作
封闭在家学网页制作!为页面嵌入PDF文件——零基础自学网页制作
HTML表单元素初识1——零基础自学网页制作
HTML表单元素初识2——零基础自学网页制作
HTML表单3(下拉列表、多行文字输入)——零基础自学网页制作
HTML表单4(form的action、method属性)——零基础自学网页制作
HTML列表制作讲解——零基础自学网页制作
为HTML页面添加视频、音频的方法——零基础自学网页制作
音视频格式转换神器与html视频元素加字幕——零基础自学网页制作
HTML中使用<a>标签实现文本内链接——零基础自学网页制作
最近看到一道跟Javascript中的setTimeout和Promise有关的面试题,感觉很有趣。题目循序渐进,不断深入,虽然只是一道题目的简单变形,却考察了很多个知识点,今天我们就一起来看看这道题目吧。
Javascript
我们就直接看题目的代码,首先是最简单的原始题目。
原始题目
上述的代码很简单,输出0,1,2,3,4。你可能会疑问,面试题会有这么简单?放心,好戏还在后头呢。
我们将上述的代码加上setTimeout,再进行输出,看看会输出什么?
变形1
上述代码每隔一秒会输出一个5。
这道题考察的是函数的闭包,如果不太清楚闭包知识的,可以去看看我写的这篇文章《前端面试中不可逃避的闭包问题,你真的了解吗?》。
那么如果我们想要每间隔一秒输出从0到4,该如何实现呢?
如果了解闭包知识的话,可以很容易想出通过立即执行函数解决。
变形2
通过上述的代码,就可以很容易达到我们的要求。
那么我们继续对题目做变形,我们去掉这个立即执行函数中的i参数,看看结果会输出什么?
变形3
通过在控制台中运行,我们发现结果和变形1一样,间隔一秒输出一个5,那么为什么会这样呢?
这是因为在立即函数内部并没有对i的引用,实际的i仍然为外部作用域中的i,所以结果会和变形1相同。
我们继续对这道题目做出变形,将setTimeout中函数改为一个立即执行函数,看看结果会是什么?
变形4
通过在控制台运行上述代码,得到的结果是立即输出0, 1, 2, 3, 4。为什么会这样呢?
根据setTimeout的用法,它接收的参数为函数或者函数的字符串表示,如果给setTimeout传递一个立即执行函数,则相当于传递了一个undefined,实际上是往定时器线程中添加了5个undefined。但是由于立即执行函数的存在,这个函数会立即执行,所以会立即输出0, 1, 2, ,3 ,4。
如果以上的部分你都能知道,那么我们再来个更难一点的变形,将setTimeout配合Promise一起使用,看看以下的一段代码会输出什么?
变形5
通过在控制台运行以上代码,我们得到结果是立即输出2, 3, 5, 4, 1,这是为什么呢?
首先在代码的开头,使用了setTimeout设置了一个定时器,虽然这个定时器的时间为0,但是根据Javascript中的事件队列机制,会将这个定时器添加到专属的定时器线程中,等到当前线程中的事件回调执行完后才能执行。不太懂Javascript的setTimeout机制的,可以去看看我写的这篇文章《Javascript中的setTimeout黑魔法》。
然后是定义一个Promise,这个Promise会在setTimeout之前执行。在Promise中执行了两个console.log(),所以会先输出2,3。
在Promise中有一个for循环,当循环执行到i等于9999时,执行resolve回调函数,这个resolve函数就是后面输出4的函数。但是由于Promise.then()的回调会在当前事件队列的最后执行,因此4会在5的后面输出。
在当前事件队列执行完后,才会执行setTimeout中的函数,因此1是最后输出的。
因此输出结果是2, 3, 5, 4, 1。
由一道最简单的题可以通过变形衍生出很多知识点的考题,看看你都会做吗?
*请认真填写需求信息,我们会在24小时内与您取得联系。