好程序员Java教程分享JavaScript常见面试题三

   好程序员Java 教程分享JavaScript常见面试题三:1. 下列代码行 1-4 如何排序,使之能够在执行代码时输出到控制台 为什么 ?

  (function() { console.log(1);

  setTimeout(function(){console.log(2)}, 1000);

  setTimeout(function(){console.log(3)}, 0);

  console.log(4);

  })();

  序号如下:

  1

  4

  3

  2

  让我们先来解释比较明显而易见的那部分:

  1  和  4 之所以放在前面,是因为它们是通过简单调用  console.log()  而没有任何延迟输出的

  2  之所以放在  3 的后面,是因为  是延迟了 1000 毫秒 ( 即, 1 ) 之后输出的,而  是延迟了 0 毫秒之后输出的。

   好的。但是,既然 3  0 毫秒延迟之后输出的,那么是否意味着它是立即输出的呢 ? 如果是的话,那么它是不是应该在  之前输出,既然  是在第二行输出的 ?

   要回答这个问题,你需要正确理解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  循环已经结束,变量  已经获得了 5 的值。 ( 面试者如果能够谈一谈有关如何执行上下文,可变对象,激活对象和内部“范围”属性贡有助于闭包行为,则可以加分 )

  (b) 要让代码工作的关键是,通过传递到一个新创建的函数对象,在每次传递通过  for  循环时,捕捉到  值。下面是三种可能实现的方法:

  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 下标表示数组中的最后一个元素,等等。

 

 

    原文作者:好程序员IT
    原文地址: http://blog.itpub.net/69913892/viewspace-2661632/
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞