ITPub博客

首页 > 应用开发 > Javascript > 好程序员Java教程分享JavaScript常见面试题四

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

原创 Javascript 作者:好程序员IT 时间:2019-10-28 13:57:58 0 删除 编辑

  好程序员Java 教程分享JavaScript常见面试题四1、 下面的代码将输出什么到控制台,为什么?

 

console.log(1 + "2" + "2");console.log(1 + +"2" + "2");console.log(1 + -"1" + "2");console.log(+"1" + "1" + "2");console.log( "A" - "B" + "2");console.log( "A" - "B" + 2);

 

上面的代码将输出以下内容到控制台:

 

"122""32""02""112""NaN2"NaN

 

原因是…

 

这里的根本问题是,JavaScript(ECMAScript) 是一种弱类型语言,它可对值进行自动类型转换,以适应正在执行的操作。让我们通过上面的例子来说明这是如何做到的。

 

例1 : 1 + "2" + "2"  输出: "122"  说明:  1 + "2"  是执行的第一个操作。由于其中一个运算对象 ("2") 是字符串, JavaScript 会假设它需要执行字符串连接,因此,会将  1  的类型转换为  "1" ,  1 + "2" 结果就是  "12" 。然后,  "12" + "2"  就是  "122" 。

 

例2 :  1 + +"2" + "2"  输出:  "32"  说明:根据运算的顺序,要执行的第一个运算是  +"2"( 第一个  "2"  前面的额外  +  被视为一元运算符 ) 。因此, JavaScript 将  "2"  的类型转换为数字,然后应用一元  +  号 ( 即,将其视为一个正数 ) 。其结果是,接下来的运算就是  1 + 2  ,这当然是  3 。然后我们需要在一个数字和一个字符串之间进行运算 ( 即,  3  和  "2") ,同样的, JavaScript 会将数值类型转换为字符串,并执行字符串的连接,产生  "32" 。

 

例3 :  1 + -"1" + "2"  输出:  "02"  说明:这里的解释和前一个例子相同,除了此处的一元运算符是  -  而不是  + 。先是  "1"  变为  1 ,然后当应用  -  时又变为了  -1  ,然后将其与  1 相加,结果为  0 ,再将其转换为字符串,连接最后的  "2"  运算对象,得到  "02" 。

 

例4 :  +"1" + "1" + "2"  输出:  "112"  说明:虽然第一个运算对象  "1" 因为前缀的一元  +  运算符类型转换为数值,但又立即转换回字符串,当连接到第二个运算对象  "1"  的时候,然后又和最后的运算对象 "2"  连接,产生了字符串  "112" 。

 

例5 :  "A" - "B" + "2"  输出:  "NaN2"  说明:由于运算符  -  不能被应用于字符串,并且  "A"  和  "B"  都不能转换成数值,因此, "A" - "B" 的结果是  NaN ,然后再和字符串  "2"  连接,得到  "NaN2"  。

 

例6 :  "A" - "B" + 2  输出:  NaN  说明:参见前一个例子,  "A" - "B"  结果为  NaN 。但是,应用任何运算符到 NaN 与其他任何的数字运算对象,结果仍然是  NaN 。

 

2 、 下面的递归代码在数组列表偏大的情况下会导致堆栈溢出。在保留递归模式的基础上,你怎么解决这个问题?

 

var list = readHugeList();var nextListItem = function() { var item = list.pop(); if (item) { // process the list item...

 

nextListItem();

 

}

 

};

 

潜在的堆栈溢出可以通过修改nextListItem  函数避免:

 

var list = readHugeList();var nextListItem = function() { var item = list.pop(); if (item) { // process the list item...

 

setTimeout( nextListItem, 0);

 

}

 

};

 

堆栈溢出之所以会被消除,是因为事件循环操纵了递归,而不是调用堆栈。当 nextListItem  运行时,如果  item 不为空, timeout 函数 (nextListItem) 就会被推到事件队列,该函数退出,因此就清空调用堆栈。当事件队列运行其 timeout 事件,且进行到下一个  item  时,定时器被设置为再次调用  extListItem 。因此,该方法从头到尾都没有直接的递归调用,所以无论迭代次数的多少,调用堆栈保持清空的状态。

 

3 、JavaScript 中的“闭包”是什么 ? 请举一个例子。

 

闭包是一个可以访问外部( 封闭 ) 函数作用域链中的变量的内部函数。闭包可以访问三种范围中的变量:这三个范围具体为: (1) 自己范围内的变量, (2) 封闭函数范围内的变量,以及 (3) 全局变量。

 

下面是一个简单的例子:

 

var globalVar = "xyz";

 

(function outerFunc(outerArg) { var outerVar = 'a';

 

(function innerFunc(innerArg) { var innerVar = 'b'; console.log( "outerArg = " + outerArg + "\n" + "innerArg = " + innerArg + "\n" + "outerVar = " + outerVar + "\n" + "innerVar = " + innerVar + "\n" + "globalVar = " + globalVar);

 

})(456);

 

})(123);

 

在上面的例子中,来自于 innerFunc ,  outerFunc 和全局命名空间的变量都在  innerFunc 的范围内。因此,上面的代码将输出如下:

 

outerArg = 123innerArg = 456outerVar = ainnerVar = bglobalVar = xyz

 

4 、下面的代码将输出什么:

 

for (var i = 0; i < 5; i++) {

 

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

 

}

 

解释你的答案。闭包在这里能起什么作用?

 

上面的代码不会按预期显示值0 , 1 , 2 , 3 ,和 4 ,而是会显示 5 , 5 , 5 , 5 ,和 5 。

 

原因是,在循环中执行的每个函数将整个循环完成之后被执行,因此,将会引用存储在 i 中的最后一个值,那就是 5 。

 

闭包可以通过为每次迭代创建一个唯一的范围,存储范围内变量的每个唯一的值,来防止这个问题,如下:

 

for (var i = 0; i < 5; i++) {

 

(function(x) {

 

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

 

})(i);

 

}

 

这就会按预期输出0 , 1 , 2 , 3 ,和 4 到控制台。

 


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69913892/viewspace-2661635/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
欢迎关注公众号:好程序员特训营 web前端教程分享 723729549 大数据教程分享 703503210

注册时间:2019-03-20

  • 博文量
    539
  • 访问量
    410772