前言
在下首语言是golang,所以会用他作为示例。
原文参见 @arialdomartini的: Back-End Developer Interview Questions
代码示例问题
1. 这段Javascript函数的输出是什么?
function hookupevents() {
for (var i = 0; i < 3; i++) {
document.getElementById("button" + i)
.addEventListener("click", function() {
alert(i);
});
}
}
这段JavaScript代码定义了一个名为hookupevents
的函数,该函数的主要作用是为三个ID分别为"button0"、"button1"和"button2"的HTML元素添加点击事件监听器。当这些按钮被点击时,会触发一个匿名函数,该函数会弹出一个警告框显示变量i
的值。
然而,由于闭包的特性,当事件处理函数被实际执行时,它会访问其所在的词法作用域中当时保存的i
变量的值,而不是事件绑定时的值。在循环结束后,i
的值将是3,因此无论点击哪一个按钮,弹出的警告框都将显示数字3。
所以,如果执行hookupevents()
函数并依次点击这三个按钮,弹出的警告框都会显示数字3。这就是著名的JavaScript闭包陷阱的一个例子。要解决这个问题,可以使用IIFE(立即调用的函数表达式)或其他方式来捕获每个循环迭代时i
的值,如下所示:
function hookupevents() {
for (var i = 0; i < 3; i++) {
(function(index) {
document.getElementById("button" + index)
.addEventListener("click", function() {
alert(index);
});
})(i);
}
}
通过这种方式,每个按钮的事件处理函数会记住各自绑定时的index
值,从而正确显示0、1或2。
2. 关于类型擦除(Type Erasure),这段Java代码的输出是什么?为什么?
ArrayList<Integer> li = new ArrayList<Integer>();
ArrayList<Float> lf = new ArrayList<Float>();
if (li.getClass() == lf.getClass()) // evaluates to true
System.out.println("Equal");
在Java中,由于类型擦除(Type Erasure)的机制,上述代码段的输出将会是:
Equal
原因在于Java泛型在编译后的字节码中并不保留具体类型参数信息。在运行时, ArrayList<Integer>
和ArrayList<Float>
都会变成原始的非泛型类ArrayList
。因此,li.getClass()
和lf.getClass()
实际上都是获取到ArrayList
类的Class对象,所以在运行时比较这两个类对象时,结果是相等的。
类型擦除确保了Java泛型的兼容性和运行时