测试你的技能的5个JavaScript问题和答案
今天我们将继续学习我们心爱的JavaScript语言,在这一版中,我们将通过回答一些JavaScript小挑战来测试我们的技能。
尽管我会在每个问题的结尾处给出答案和解释,但还是要先试着自己弄清楚,然后用我的答案来验证你的答案。
问题#1:数组排序比较
考虑以下数组和条件,你认为结果会是什么?
const arr1 = ['a', 'b', 'c']
const arr2 = ['c', 'b', 'a']
console.log(
arr1.sort() === arr1,
arr2 === arr2.sort(),
arr1.sort() === arr2.sort()
)
答案
true true false
现在我们知道了结果,让我们解释一下原因。对于前两个输出,解释相当简单,sort() 方法对原始数组进行排序,并返回对同一对象的引用,所以arr1.sort() 实际上是对同一对象的引用arr1 。
对于第三个输出,arr1.sort() === arr2.sort() ,尽管每一个数组上的元素都是一样的,但=== 操作符不会测试数组的元素,而是测试每个对象的引用,在这种情况下,引用是不同的,因此返回false 。
问题#2:对象互斥性
在这个场景中,我想模拟一个对象,它代表一个作者,以及他的网站信息。然后我们将使用Object.freeze() ,所以它不能被改变,我们将对它进行测试。你认为结果会是什么?
const author = {
name: 'Juan',
website: {
type: 'blog',
url: 'https://livecodestream.dev',
}
}
Object.freeze(author)
author.website.type = 'test'
console.log(author.website.type)
答案
test
如果你答对了,恭喜你!如果没有,别担心,我也在那里。我们来解释一下发生了什么。
当我们调用方法Object.freeze() ,我们冻结了对象,这意味着对象不能再被改变;冻结对象可以防止新的属性被添加到对象中,现有的属性被删除或改变。
但是,为什么我们能够改变这个对象呢?实际上我们没有,这就是诀窍。就所有目的而言,在变量author 网站是对一个对象的引用,并且这个引用在整个代码中保持不变。我们确实改变了website 对象内部的一个属性,但这并没有改变对该对象本身的引用。
如果你想知道如果我们试图改变author 对象的一个直接属性会发生什么,有两个可能的答案。让我们从第一种情况开始。
author.name = 'Laura'
console.log(author.name)
---------
Output
---------
"Juan"
在第一种情况下,即使我们改变了属性name ,也没有什么真正的改变,我们没有得到错误,没有警告,就像那行代码永远不会被执行。第二个方案是在严格模式下
"use strict"; author.name = 'Laura'
Uncaught TypeError: Cannot assign to read only property 'name' of object '#<Object>'
at <anonymous>:1:27
在严格模式下,如果我们试图修改一个冻结的对象,我们会得到一个TypeError 。比以前好多了。
问题#3:递归
给出以下递归函数,当我们以 "blog "为参数调用它时,你认为结果会是什么?
const recursive = str => {
if (str.length > 1) {
return recursive(str.slice(1))
}
return str
}
console.log(recursive('blog'))
答案
g
对于这个问题,没有什么诀窍,只是递归函数的一个基本用法,它将继续调用自己,直到字符串中只有一个元素str ,从而打印出原始字符串的最后一个字符,在这个例子中是g 。递归函数很重要,可以用非常有趣的方式解决问题,我们了解它们很重要。
问题#4:作用域
你认为输出到控制台的结果会是什么,为什么?
(function(){
const a = b = 3
})()
console.log("a defined? " + (typeof a !== 'undefined'))
console.log("b defined? " + (typeof b !== 'undefined'))
答案
a defined? false
b defined? true
奇怪的警报!由于a 和b 都是在函数的包围范围内定义的,你会认为a 和b 实际上都是undefined 。
然而,情况并非如此。这里的问题是常见的误解,即:const a = b = 3 是对:const a = 3; const b = 3; 的速记,但事实上,它是对
b = 3;
const a = b;
但是,b 怎么能在包围函数的范围之外被定义呢?诀窍是:b 最终成为一个全局变量(因为前面没有let,const 或var )。但是a 仍然在函数的包围范围内。
注意,在严格模式下,这将产生一个ReferenceError: b is not defined 。
问题5:关于闭包的更多信息
下面的片段是一个实际流行的面试问题,问题是,你认为输出会是什么?
for (var i = 0; i < 5; i++) {
setTimeout(function() { console.log(i); }, i * 1000 );
}
答案是
5
5
5
5
5
和你想象的不太一样?原因是在循环中执行的每个函数都会在整个循环完成后执行,因此都会引用存储在i 中的最后一个值,也就是5 。
闭包可以用来防止这个问题,为每个迭代创建一个唯一的范围,在其范围内存储变量的每个唯一值,如下所示。
for (var i = 0; i < 5; i++) {
(function(x) {
setTimeout(function() { console.log(x); }, x * 1000 );
})(i);
}
从ES2015开始的另一个选择是使用let ,而不是var 。
for (let i = 0; i < 5; i++) {
setTimeout(function() { console.log(i); }, i * 1000 );
}
总结
我希望你和我一样从中获得乐趣和学习,这篇文章写得特别有意思,我以后可能会做更多类似的文章。