2015阿里巴巴前端实习生在线笔试题
前几天参加了2015阿里巴巴前端实习生在线笔试,发现题目真的挺难的,后来再重新回想的时候,除了本来就不会做的,还发现自己做错了几道题,现在整理一下那些笔试题,这里的笔试题部分是自己的,也有部分是工作室其他小伙伴们提供的。感谢楷豪师兄和闻东师兄的相关指导,感谢工作室其他小伙伴们提供的题目和答案。下面选择题给出的一些解析和答案都是自己上网查过相关资料然后根据自己的理解给出的,不保证全部正确哈,仅作参考作用。
一、(单项选择)对于下列程序运行结果,符合预期的是
function f1() {
console.time('time span');
}
function f2() {
console.timeEnd('time span');
}
setTimeout(f1, 100);
setTimeout(f2, 200);
function waitForMs(n) {
var now = Date.now();
while (Date.now() - now < n) {}
}
waitForMs(500);
- A、time apan:700.077ms
- B、time apan:0.066ms
- C、time apan:500.077ms
- D、time apan:100.077ms
解析:
console.time()
语句和console.timeEnd()
语句是用来对程序的执行进行计时的。因为f1
和f2
被都setTimeout()
事先设置的定时器装到一个事件队列里面。本来f1
应该在100ms后就要执行了,但是因为waitForMs()
占用了线程,而执行JavaScript
是单线程的,所以就没办法在100ms后执行那个f1
,所以需要等500ms等waitForMs()
执行完,然后再执行f1
和f2
,这时候f1
和f2
就几乎同时执行了。所以应该选时间最短的一项,所以答案应该选B
(楷豪师兄提供的解答)
二、(单项选择)请选择结果为真的表达式
- A、null instanceof Object
- B、null == undefined
- C、NaN == NaN
- D、false == undefined
解析:
A、未定义的值和定义未赋值的为undefined,null是一种特殊的object,所以typeof null
返回的应该是object
,但是为什么null instanceof Object
返回的是false
呢?原因就是null
是个特殊的Object
类型的值 ,表示空引用的意思 。instanceof
表示某个变量是否是某个对象的实例 ,所以为false
。
B、undefined == null
是正确的,尽管如此,和其他相似之处,但null
和undefined
并不是等价的。每个作为其独特的类型的唯一成员,undefined
是Undefined
类型和null
是Null
类型。所以undefined === null
是不正确的,因为他们虽然值相等,但是类型不相等。区分这两个值,可以认为undefined
代表一个意想不到的没有值而null
作为预期没有值的代表。
(null:)是一个对象,但是为空。因为是对象,所以typeof null
返回object
。null
是JavaScript
保留关键字。
null
参与数值运算时其值会自动转换为0
,因此,下列表达式计算后会得到正确的数值:
表达式:123 + null
结果值:123
表达式:123 * null
结果值:0
(undefined:)是全局对象(window)
的一个特殊属性,其值是未定义的。但typeof undefined
返回undefined
。
C、NaN
是一个值类型,同是也是一个数值.意思是Not A
Number
,这个都知道是什么意思.值比较特殊,特殊在于NaN
是一个数字,是一个与任何数值都不相等的数字。所以NaN == NaN
返回false
。
D、undefined
被转换为布尔值为false
,Boolean(undefined)
返回的是false
,但是undefined
不等于false
。所以false == undefined
返回false
。
所以最终答案应该为B
。
三、(单项选择)下面程序的执行结果是
var name = 'World!';
(function () {
if (typeof name === 'undefined') {
var name = 'Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
- A、Goodbye Jack
- B、Hello Jack
- C、Hello undefined
- D、Hello World
解析:
因为JavaScript
中的变量的查找是就近原则去寻找var
定义的变量,当就近没有找到的话就会找外层。题目中因为if
判段语句(typeof name === 'undefined')
就近定义的name
就在其执行完的下一行,所以name
就被预解析了,实际上可以理解成在if
判段语句(typeof name === 'undefined')
上面var name
这样定义了name
,但是尚未被赋值。而在它执行完后面再去为name
赋值name = 'Jack';
,所以name
的值是undefined
。所以typeof name === 'undefined'
成立,所以判断语句会走if
成立部分。
所以最终答案应该为A
。
四、(不定项选择)以下关于DOM事件流的表述哪些是正确的
- A、事件流包括两个阶段:事件捕获阶段、事件冒泡阶段
- B、IE跟标准浏览器对于DOM事件流实现不一样
- C、假设parentEle是childEle的父节点,绑定事件:parentEle.addEventListener("click", fn1, false)和childEle.addEventListener("click", fn2,false),当点击childEle的时候fn1将先于fn2触发
- D、addEventListener第三个参数true代表支持捕获,false代表不支持捕获
解析:
在W3C
事件模型中,任何事件会首先被捕获直至到达目标元素然后再冒泡回去。事件流包括3
个阶段:事件捕获阶段
、处于目标阶段
和事件冒泡阶段
。所以A
选项是错
的。Web开发者可以选择将事件处理程序注册在捕获或者冒泡阶段。这可以通过addEventListener()
方法来实现。如果该方法传入的最后一个参数值为true
,表示事件处理程序被注册在捕获阶段,如果为false
表示件处理程序被注册在冒泡阶段。所以D
选项也是错
的。
假设有如下程序(childEle
是parentEle
的子元素):
1.parentEle.addEventListener("click", parentDoSomething, true);
2.childEle.addEventListener("click", childEleDoSomething, false);
如果用户点击子元素childEle
会发生如下事情:
a、点击事件开始于
捕获阶段
。它会先查询是否有childEle
的任何祖先元素在捕获阶段
绑定了onclick
事件。b、它发现祖先元素1在捕获阶段绑定了
onclick
事件,于是parentEle.parentDoSomething()
首先被执行。c、事件一直查询到目标元素
childEle
都没有再发现别的在捕获阶段
绑定的onclick
事件,事件转到它的冒泡阶段
并执行childEleDoSomething()
(注册在childEle
上的在冒泡阶段
执行的事件处理程序)。d、事件再次向上查询并检查是否有任何祖先元素在
冒泡阶段
绑定了onclick
事件,并没有查询到,所以什么都没有发生。
再看相反的例子:
1.parentEle.addEventListener("click", parentDoSomething, false);
2.childEle.addEventListener("click", childEleDoSomething, false);
现在如果用户点击childEle
,下面的事情会按顺序发生:
a、点击事件发生于
捕获阶段
。事件查询childEle
是否有任何祖先元素在捕获阶段
绑定了onclick
事件并且没有查找到这样的元素。b、事件查询到目标元素
childEle
自己。事件转为冒泡阶段
并执行childEleDoSomething()
。c、事件再次向上查询并检查目标元素是否有任何祖先元素在
冒泡阶段
绑定了onclick
事件。d、它找到了满足条件的
parentEle
,然后执行parentDoSomething()
。所以选项C
是错
的,应该是fn2
先触发。
因为IE
没有提供对事件捕获阶段
的支持,所以IE
跟标准浏览器
对于DOM事件流
实现不一样。
所以最终答案应该为B
。
五、(不定项选择)通过下面的哪些方法可以获取页面的html元素
- A、document.getElementById
- B、document.getElementsByClassName
- C、document.querySelector
- D、document.querySelectorAll
解析:
A、页面的html元
素可以通过id
获取,具有唯一性,如:var divObjId = document.getElementsById("test");
。所以A
是正确的。
B、页面的html
元素可以通过class
获取,会选择页面上所有class
名为test
的DOM标签,如:var divObjClass = document.getElementsByClassName("test");
。所以B
是正确的。
C、D 、document.querySelector
只返回匹配的第一个元素,如果没有匹配项,返回null
。document.querySelectorAll
返回匹配的元素集合,如果没有匹配项,返回空的nodelist
(节点数组)。这两个方法都可以接受三种类型的参数:id(#)
,class(.)
,标签
,很像jquery
的选择器。如:
var obj = document.querySelector("#id");
var obj = document.querySelector(".classname");
var obj = document.querySelector("div");
var el = document.body.querySelector("style[type='text/css'], style:not([type])");
var elements = document.querySelectorAll("#score>tbody>tr>td:nth-of-type(2)");
var elements = document.querySelectorAll("#id1, #id2, .class1, class2, div a, #list li img");
所以C
和D
都是正确的。
所以最终的答案是A,B,C,D
。
六、(不定项选择)下面选项中,对javascript事件的描述不正确的是
- A、IE使用attachEvent/detachEvent方法来添加和删除事件监听器;w3c使用addEventListener/removeEventListener方法
- B、IE是将event对象作为参数传递给监听器,w3c事件监听器内使用的是一个全局的Event对象
- C、IE提供了对事件捕获阶段的支持
- D、要停止事件的传递,IE的做法是设置event对象的cancelBubble为true,而w3c的做法是设置执行stopPropagation方法
解析:
A、IE
使用attachEvent/detachEvent
方法来添加和删除事件监听器;w3c
使用addEventListener/removeEventListener
方法。这是正确的。
B、IE
事件监听器内使用的是一个全局的Event
对象,而w3c
是将event
对象作为参数传递给监听器。所以B
是错误的。
C、IE
没有提供对事件捕获阶段的支持。所以C
也是错误的。
D、要想阻止冒泡,在Microsoft
模型中,需要将事件的cancelBubble
属性设置为true
。在W3C
模型中,需要调用事件的stopPropagation()
方法。
这两种方法阻止了事件的所有冒泡。如果想解决浏览器兼容问题,可以像下面这样写:
function doSomething(e){
e = window.event || e;
e.cancelBubble = true;
if(e.stopPropagation){
e.stopPropagation();
}
}
在不支持cancelBubble
属性的浏览器中设置它的值并不会报错。浏览器会忽略它并创建这个属性。当然,它并不能真正地阻止冒泡,但是给它分配值的操作本身是安全的。
所以最终的答案是B,C
。
七、(单项选择)
var array1 = [1,2];
var array2 = array1;
array1[0] = array2[1];
array2.push(3);
console.log(array1);
console.log(array2);
执行上面的代码array1
和array2
的值分别是什么?
- A、Array1的值为[2,2];Array2的值为[1,2,3]
- B、Array1的值为[2,2,3];Array2的值为[1,2,3]
- C、Array1的值为[2,2,3];Array2的值为[2,2,3]
- D、Array1的值为[1,2,3];Array2的值为[1,2,3]
解析:
数组对象是引用的关系,array2
改变,array1
也会改变。array1
改变,array2
也会改变。
所以最终的答案是C
。
八、(不定项选择)有如下代码
function Test(name,age){
this.name = name;
this.age = age;
};
Test.prototype = {
name:'aliyun',
hasOwnproperty:function(){
return false;
}
};
var instance = new Test('alibaba',102);
以下关于原型链的说法正确的是:
- A、JavaScript对象有两种不同的属性,一种是对象自身的属性,另一种是继承于原型链上的属性
- B、instance.name == 'aliyun'为true
- C、instance.hasOwnproperty('age')结果将是false
- D、所有对象都继承自Object.prototype
解析:
A、javascript
对象有两种不同的属性来源,一个是对象自身属性,另一是继承于原型链上的属性,所以A
是正确的。
B、因为instance
是Test
对象的一个实例,如果我们在该实例中创建了name
这个属性,这个属性的值将会屏蔽原型中的那个属性。所以instance.name == 'aliyun'
为false
,instance.name
的值应为alibaba
,所以B
是错误的。
C、因为instance
是Test
对象的一个实例,所以同样拥有hasOwnproperty
这个方法,所以返回的结果是false
.
D、每个JavaScript
对象都继承一个原型链,而所有原型都终止于Object.prototype
。注意,这种继承是活动对象之间的继承。它不同于继承的常见概念,后者是指在声明类时类之间的发生的继承。因此,JavaScript
继承动态性更强。它使用简单算法实现这一点,如下所示:当您尝试访问对象的属性/方法时,JavaScript
将检查该属性/方法是否是在该对象中定义的。如果不是,则检查对象的原型。如果还不是,则检查该对象的原型的原型,如此继续,一直检查到Object.prototype
。下图说明了此解析过程
所以D
是正确的。
所以最终的答案是A、C、D
。
九、实现函数range([start,]stop[,step])返回一个数组(step大于1)
> range(1,11); => [1,2,3,4,5,6,7,8,9,10]
> range(0); => []
> range(10); => [0,1,2,3,4,5,6,7,8,9]
> range(0,30,5); => [0,5,10,15,20,25]
解析: 实现代码如下:
function range(){
var argLength = arguments.length,
newArray = [],
i = 0,
start = arguments[0],
stop = arguments[1],
step = arguments[2];
switch(argLength){
case 0 : throw Error('至少输入一个参数,限止数组在哪里结束');
case 1 : {
stop = arguments[0];
for( i = 0 ; i < stop ; i++){
newArray.push(i);
}
return newArray;
}
case 2 : {
for( i = start ; i < stop ; i++){
newArray.push(i);
}
return newArray;
}
case 3 : {
if(step < 1) {
throw Error('step > 1');
}else{
for( i = start ; i < stop ; i += step){
newArray.push(i);
}
return newArray;
}
}
default : throw Error('最多传入三个参数');
}
}
十、背景:
1、对象A直接调用对象B的某个方法,实现交互逻辑。但是导致的问题是A和B紧密耦合,修改B可能导致A调用B的方法失效。 2、为了解决耦合导致的问题,我们可以设计成: 对象A生成消息 -> 将消息通知给一个消息处理器(Observable)-> 消息处理器将消息传递给B 具体的调用过程变成: A.emit(‘message’,data); B.on(‘message’,function(data){}); 请实现这一事件消息代理功能 //请将事件消息功能补充完整 function EventEmitter(){}
解析: 实现代码如下:
function EventEmitter() {
this.eventFunctionMap = {};
}
EventEmitter.prototype.emit = function(eventName, data){
this.eventFunctionMap[eventName].call(this, data);
}
EventEmitter.prototype.on = function(eventName, callback) {
this.eventFunctionMap[eventName] = callback;
}
十一、实现下图的布局
<main>
<div>
A
</div>
<div>
B
</div>
<div>
C
</div>
</main>
解析: 实现代码如下:
div{
height: 50px;
width: 50px;
background-color: black;
display: inline-block;
margin-left: 10px;
color: white;
font-size: 20px;
text-align: center;
line-height: 50px;
}
下面是锦欣大神提供的另一种答案:
/**base style**/
div{
background:#000;
color:#fff;
height:50px;
width:50px;
text-align:center;
line-height:50px;
}
/**start here**/
main{
text-align:center;
}
div{
display:inline-block;
_display:inline;/*hank IE*/
_zoom:0;/*hank IE*/
}
十二、有一个包含数据列表的页面,数据行数不确定。每一行数据都有一个删除按钮,单击删除按钮删除该列数据,请用JavaScript实现该功能。
解析: 实现代码如下:
<script type="text/javascript">
window.onload = function(){
var oUl = document.getElementsByTagName('ul')[0];
oUl.onclick = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.tagName.toLowerCase() == 'button'){
var tr = target.parentNode;
tr.parentNode.removeChild(tr);
}
}
}
</script>
<body>
<ul>
<li>一<button>删除一</button></li>
<li>二<button>删除二</button></li>
<li>三<button>删除三</button></li>
<li>四<button>删除四</button></li>
<li>五<button>删除五</button></li>
<li>六<button>删除六</button></li>
</ul>
</body>
十三、编写CSS让一个已知宽高的DIV,在PC/手机端水平垂直居中。
解析:
实现代码如下:
div{
width : 300px;
height : 300px;
border : 1px solid red;
position : absolute;
top : 50%;
left : 50%;
margin-top : -150px;
margin-left : -150px;
}
十四、使用语义化的 HTML 标签及css完成以下布局
• 容器默认宽度320px,图片100*100 • hover 时容器宽度变为400px • 右侧文字宽度自适应,考虑模块化和扩展性 解析:
实现代码如下:
<style type="text/css">
div{
width : 320px;
}
div:hover{
width : 400px;
}
img{
float : left;
width : 100px;
height : 100px;
}
h1{
color : #333;
margin-bottom : 8px;
font-size : 20px;
}
p{
color : #666;
font-size : 12px;
line-height: 1.2em;
}
</style>
<div>
<img src="d:\1.png">
<h1>(最多两行20px #333,顶部对齐图片,底部间距8px)</h1>
<p>(12px #666 行高1.2)使用语义化的HTML标签完成以下布局,考虑模块化和扩展性。容器默认为320px,右侧文字宽度自适应</p>
</div>
十五、写一个可以暂停执行的JavaScript函数
解析:
1、使用函数闭包来实现
<input type="button" value="继续" onclick='st();'/>
<script>
/*需要执行的函数*/
function test(x){
alert(x++);
alert(x++);
return function(){
alert(x++);
}
}
var st = test(10);
</script>
2、使用setTimeOut来实现
<script language="javascript">
/*Javascript中暂停功能的实现
Javascript本身没有暂停功能(sleep不能使用)同时 vbscript也不能使用doEvents,故编写此函数实现此功能。
javascript作为弱对象语言,一个函数也可以作为一个对象使用。
比如:
function Test(){
alert("hello world");
this.NextStep=function(){
alert("NextStep");
}
}
我们可以这样调用 var myTest=new Test();myTest.NextStep();
我们做暂停的时候可以吧一个函数分为两部分,暂停操作前的不变,把要在暂停后执行的代码放在this.NextStep中。
为了控制暂停和继续,我们需要编写两个函数来分别实现暂停和继续功能。
暂停函数如下:
*/
function Pause(obj,iMinSecond){
if (window.eventList==null) window.eventList=new Array();
var ind=-1;
for (var i=0;i<window.eventList.length;i++){
if (window.eventList[i]==null) {
window.eventList[i]=obj;
ind=i;
break;
}
}
if (ind==-1){
ind=window.eventList.length;
window.eventList[ind]=obj;
}
setTimeout("GoOn(" + ind + ")",iMinSecond);
}
/*
该函数把要暂停的函数放到数组window.eventList里,同时通过setTimeout来调用继续函数。
继续函数如下:
*/
function GoOn(ind){
var obj=window.eventList[ind];
window.eventList[ind]=null;
if (obj.NextStep) obj.NextStep();
else obj();
}
/*
该函数调用被暂停的函数的NextStep方法,如果没有这个方法则重新调用该函数。
函数编写完毕,我们可以作如下测试:
*/
function Test(){
alert("hellow");
Pause(this,1000);//调用暂停函数
this.NextStep=function(){
alert("NextStep");
}
}
</script>
十六、用JavaScript写一个Ajax的get请求
解析:
/* 创建 XMLHttpRequest 对象 */
var xmlHttp = null;
function GetXmlHttpObject(){
if (window.XMLHttpRequest){
// code for IE7+, Firefox, Chrome, Opera, Safari
Xmlhttp = new XMLHttpRequest();
}else{// code for IE6, IE5
Xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlhttp;
}
// -----------ajax方法-----------//
function getLabelsGet(){
xmlHttp = GetXmlHttpObject();
if (xmlHttp == null){
alert('您的浏览器不支持AJAX!');
return;
}
var id = document.getElementById('id').value;
var url="http://timtsang.github.io?id="+id+"&t/"+Math.random();
xmlHttp.open("GET",url,true);
xmlHttp.onreadystatechange=favorOK;//发送事件后,收到信息了调用函数
xmlHttp.send();
}
function getOkGet(){
if(xmlHttp.readyState==1||xmlHttp.readyState==2||xmlHttp.readyState==3){
// 本地提示:加载中
}
if (xmlHttp.readyState==4 && xmlHttp.status==200){
var d= xmlHttp.responseText;
// 处理返回结果
}
}
十七、使用html+css实现以下图形(不能用图片)
解析:
这道题感觉是做的最蛋疼的一道题,因为我之前根本就不理解题目到底要我实现哪个图形,狂刷新了N多遍网页,也没看到什么图形,后来经过闻东师兄提醒之后才恍然大悟,原来真的是要我实现右边那个插入图片的小图标。不过就算当初知道这要实现这个小图标,我也做不出来,因为我根本不知道那两个三角形要怎么实现。
<title>picture</title>
<style type="text/css">
#rectangle{
background: #FFF;
border: 10px solid #999999;
padding:10px;
height: 120px;
width: 200px;
}
#circle{
position:absolute;
margin-left: 140px;
margin-top: 10px;
width: 40px;
height: 40px;
background: #999999;
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
border-radius: 20px;
}
#triangle{
width: 0;
height: 0;
position:absolute;
margin-top: 40px;
border-bottom: 80px solid #999999;
border-left: 50px solid transparent;
border-right: 70px solid transparent;
}
#triangle2{
width: 0;
height: 0;
position:absolute;
margin-top: 60px;
margin-left: 80px;
border-bottom: 60px solid #999999;
border-left: 30px solid transparent;
border-right: 70px solid transparent;
}
</style>
</head>
<div id="rectangle"><span id="circle"></span><span id="triangle"></span><span id="triangle2"></span></div>
</body>
效果图如下:
十八、数组去重,然后使数组元素按降序排序
解析:
在排序的算法中,快速排序是相对比较高效的:
Array.prototype.quickSort = function(){
if(this.length <= 1){
return this;
}else{
var leftArray = [],
rightArray = [],
num = Math.floor((this.length)/2),
middleValue = this.splice(num,1);
for(var i = 0; i < this.length; i++){
if(this[i] > middleValue){
leftArray.push(this[i]);
}else{
rightArray.push(this[i]);
}
}
return leftArray.quickSort().concat(middleValue,rightArray.quickSort());
}
}
对于数组去重,有以下三种方法:
第一种:
Array.prototype.unique1 = function(){
var newArray = [this[0]];//结果数组
for(var i = 1; i < this.length; i++){
if(newArray.indexOf(this[i]) == -1){
newArray.push(this[i]);
}
}
return newArray;
}
第二种:
Array.prototype.unique2 = function(){
var newArray = [this[0]];//结果数组
for(var i = 1; i < this.length; i++){
if(this.indexOf(this[i]) == i){
newArray.push(this[i]);
}
}
return newArray;
}
第三种:
Array.prototype.unique3 = function(){
var arrayMap = {}, newArray = [];
for(var i = 0; i < this.length; i++){
if(!arrayMap[this[i]]){
arrayMap[this[i]] = true;
newArray.push(this[i]);
}
}
return newArray;
}
先对数组按降序排序,再去重便可实现题目的要求,这样效率也会高一点:
var newArray = [1,2,1,9,10,3,4,3,5,2,4,6,5,7,4,8,7,3,5,3];
var nowArray = newArray.quickSort().unique1();
console.log(nowArray);
十九、已知:
var data = {
name: 'xiaoming',
age: '18'
};
var template = "My name is {$name}, my age is {$age}".
//写一个函数,实现:
function shenmegui(template, data) {
} => My name is xiaoming, my age is 18.
解析:
var data = {
name:'xiaoming',
age:'18'
};
var template = "My name is {$name},my age is {$age}."
function outputTemplate(template,data){
var regName = /(\{\$name\})/g;
var regAge = /(\{\$age\})/g;
template = template.replace(regName,data.name);
template = template.replace(regAge,data.age);
return template;
}
alert(outputTemplate(template,data));
二十、利用闭包,实现点击<p>时,被点击的p的背景色变为#eee
解析:
window.onload = function(){
var pObj = document.getElementsByTagName("p");
for(var i = 0; i < pObj.length; i++){
pObj[i].onclick = (function(){
return function(){
this.style.background = "#eee";
}
})(i);
};
}
<p>第一个</p>
<p>第二个</p>
<p>第三个</p>
<p>第四个</p>
<p>第五个</p>