好程序员Java教程分享JavaScript常见面试题三:1.下列代码行1-4如何排序,使之可以在执行代码时输出到控制台? 为何?程序员
(function() { console.log(1);面试
setTimeout(function(){console.log(2)}, 1000);数组
setTimeout(function(){console.log(3)}, 0);浏览器
console.log(4);闭包
})();app
序号以下:ide
1函数
4spa
3orm
2
让咱们先来解释比较明显而易见的那部分:
1 和 4之因此放在前面,是由于它们是经过简单调用 console.log() 而没有任何延迟输出的
2 之因此放在 3的后面,是由于 2 是延迟了1000毫秒(即,1秒)以后输出的,而 3 是延迟了0毫秒以后输出的。
好的。可是,既然 3 是0毫秒延迟以后输出的,那么是否意味着它是当即输出的呢?若是是的话,那么它是否是应该在 4 以前输出,既然 4 是在第二行输出的?
要回答这个问题,你须要正确理解JavaScript的事件和时间设置。
浏览器有一个事件循环,会检查事件队列和处理未完成的事件。例如,若是时间发生在后台(例如,脚本的 onload 事件)时,浏览器正忙(例如,处理一个 onclick),那么事件会添加到队列中。当onclick处理程序完成后,检查队列,而后处理该事件(例如,执行 onload 脚本)。
一样的, setTimeout() 也会把其引用的函数的执行放到事件队列中,若是浏览器正忙的话。
当setTimeout()的第二个参数为0的时候,它的意思是“尽快”执行指定的函数。具体而言,函数的执行会放置在事件队列的下一个计时器开始。可是请注意,这不是当即执行:函数不会被执行除非下一个计时器开始。这就是为何在上述的例子中,调用 console.log(4) 发生在调用 console.log(3) 以前(由于调用 console.log(3) 是经过setTimeout被调用的,所以会稍微延迟)。
2.写一个简单的函数(少于80个字符),要求返回一个布尔值指明字符串是否为回文结构。
下面这个函数在 str 是回文结构的时候返回true,不然,返回false。
function isPalindrome(str) {
str = str.replace(/\W/g, '').toLowerCase(); return (str == str.split('').reverse().join(''));
}
例如:
console.log(isPalindrome("level")); // logs 'true'console.log(isPalindrome("levels")); // logs 'false'console.log(isPalindrome("A car, a man, a maraca")); // logs 'true'
3.写一个 sum方法,在使用下面任一语法调用时,均可以正常工做。
console.log(sum(2,3)); // Outputs 5console.log(sum(2)(3)); // Outputs 5
(至少)有两种方法能够作到:
方法1
function sum(x) { if (arguments.length == 2) { return arguments[0] + arguments[1];
} else { return function(y) { return x + y; };
}
}
在JavaScript中,函数能够提供到 arguments 对象的访问,arguments 对象提供传递到函数的实际参数的访问。这使咱们可以使用 length 属性来肯定在运行时传递给函数的参数数量。
若是传递两个参数,那么只需加在一块儿,并返回。
不然,咱们假设它被以 sum(2)(3)这样的形式调用,因此咱们返回一个匿名函数,这个匿名函数合并了传递到 sum()的参数和传递给匿名函数的参数。
方法2
function sum(x, y) { if (y !== undefined) { return x + y;
} else { return function(y) { return x + y; };
}
}
当调用一个函数的时候,JavaScript不要求参数的数目匹配函数定义中的参数数量。若是传递的参数数量大于函数定义中参数数量,那么多余参数将简单地被忽略。另外一方面,若是传递的参数数量小于函数定义中的参数数量,那么缺乏的参数在函数中被引用时将会给一个 undefined值。因此,在上面的例子中,简单地检查第2个参数是否未定义,就能够相应地肯定函数被调用以及进行的方式。
4.请看下面的代码片断:
for (var i = 0; i < 5; i++) { var btn = document.createElement('button');
btn.appendChild(document.createTextNode('Button ' + i));
btn.addEventListener('click', function(){ console.log(i); }); document.body.appendChild(btn);
}
(a)当用户点击“Button 4”的时候会输出什么到控制台,为何?(b)提供一个或多个备用的可按预期工做的实现方案。
(a)不管用户点击什么按钮,数字5将总会输出到控制台。这是由于,当 onclick 方法被调用(对于任何按钮)的时候, for 循环已经结束,变量 i 已经得到了5的值。(面试者若是可以谈一谈有关如何执行上下文,可变对象,激活对象和内部“范围”属性贡有助于闭包行为,则能够加分)。
(b)要让代码工做的关键是,经过传递到一个新建立的函数对象,在每次传递经过 for 循环时,捕捉到 i 值。下面是三种可能实现的方法:
for (var i = 0; i < 5; i++) { var btn = document.createElement('button');
btn.appendChild(document.createTextNode('Button ' + i));
btn.addEventListener('click', (function(i) { return function() { console.log(i); };
})(i)); document.body.appendChild(btn);
}
或者,你能够封装所有调用到在新匿名函数中的 btn.addEventListener :
for (var i = 0; i < 5; i++) { var btn = document.createElement('button');
btn.appendChild(document.createTextNode('Button ' + i));
(function (i) {
btn.addEventListener('click', function() { console.log(i); });
})(i); document.body.appendChild(btn);
}
也能够调用数组对象的本地 forEach 方法来替代 for 循环:
['a', 'b', 'c', 'd', 'e'].forEach(function (value, i) { var btn = document.createElement('button');
btn.appendChild(document.createTextNode('Button ' + i));
btn.addEventListener('click', function() { console.log(i); }); document.body.appendChild(btn);
});
5.下面的代码将输出什么到控制台,为何?
var arr1 = "john".split('');var arr2 = arr1.reverse();var arr3 = "jones".split('');
arr2.push(arr3);console.log("array 1: length=" + arr1.length + " last=" + arr1.slice(-1));console.log("array 2: length=" + arr2.length + " last=" + arr2.slice(-1));
输出结果是:
"array 1: length=5 last=j,o,n,e,s""array 2: length=5 last=j,o,n,e,s"
arr1 和 arr2 在上述代码执行以后,二者相同了,缘由是:
调用数组对象的 reverse() 方法并不仅返回反顺序的阵列,它也反转了数组自己的顺序(即,在这种状况下,指的是 arr1)。
reverse() 方法返回一个到数组自己的引用(在这种状况下即,arr1)。其结果为,arr2 仅仅是一个到 arr1的引用(而不是副本)。所以,当对 arr2作了任何事情(即当咱们调用 arr2.push(arr3);)时,arr1 也会受到影响,由于 arr1 和 arr2 引用的是同一个对象。
这里有几个侧面点有时候会让你在回答这个问题时,阴沟里翻船:
传递数组到另外一个数组的 push() 方法会让整个数组做为单个元素映射到数组的末端。其结果是,语句 arr2.push(arr3); 在其总体中添加 arr3 做为一个单一的元素到 arr2 的末端(也就是说,它并无链接两个数组,链接数组是 concat() 方法的目的)。
和Python同样,JavaScript标榜数组方法调用中的负数下标,例如 slice() 可做为引用数组末尾元素的方法:例如,-1下标表示数组中的最后一个元素,等等。