棘手的 JavaScript 问题
为了成为一名更优秀的 JavaScript 程序员,我需要深入研究 JavaScript 基础知识。在本文中,我将向你展示一些令人费解的问题(对我来说,这确实令人费解,我希望对你来说也是如此),以便我们了解这些问题背后的一些概念。
在我们开始之前,我想提一下我用于撰写本文的一些资源,并且强烈建议您也使用它们:
- 70 个 JavaScript 面试问题- 优秀的文章,您可以从中学到很多有关 JavaScript 基础知识的知识。
- 是什么让 Javascript 变得奇怪...并且很棒- 我发现了这个 Youtube 播放列表,在我看来,这些解释非常容易理解,并且他展示了可视化的代码示例。
- 事件循环到底是什么?| Philip Roberts | JSConf EU - 近期最著名的 JavaScript 视频之一。他解释了 JavaScript 的“幕后”工作原理(事件循环的工作原理)。
当然,这只是关于这个主题的一些资源。还有很多其他资源可供学习。
那么,您准备好迎接令人震惊的(JavaScript 问题)了吗?

问题
注意 1!:每个问题都有一个答案和解释(链接在每个条目下方)。
注意 2!:如果您在控制台上运行问题,请记住有些变量会重复出现,因此请逐个问题刷新。
注意 3!:思考一下每个问题的输出结果是什么。
问题 1
var a = 1
function foo(){
var a = 2
console.log(a)
}
foo()
console.log(a);
转到答案 1
问题 2
function foo(){
a = 2
}
foo()
console.log(a);
转到答案 2
问题 3
var answer = 0;
const baseValue = value => multipleValue => value * multipleValue;
const multiple = baseValue(2);
answer = multiple(5);
console.log(answer);
转到答案 3
问题 4
function outerFunc(outerParam) {
function innerFunc(innerParam) {
outerParam["b"] = innerParam;
}
return innerFunc;
}
const obj = {a:1}
const example = outerFunc(obj);
const answer = example(2)
console.log(obj);
转到答案 4
问题 5
let arr =[1,2]
function test(array){
array.push(3)
}
test(arr)
console.log(arr)
转到答案 5
问题 6
let arr =[1,2]
function test(array){
array.push(3)
}
test([...arr])
console.log(arr)
转到答案 6
问题 7
let arr =[1,2]
function test(array){
array = [1,2,3]
}
test(arr)
console.log(arr)
转到答案 7
问题 8
const carDetails = {
name: "Tomer",
getName(){
return this.name;
},
};
var name = "Joe";
var getCarName = carDetails.getName;
console.log(getCarName());
转到答案 8
问题 9
console.log(a)
console.log(b)
var a = 2
let b = 2
转到答案 9
问题 10
a()
function a(){
console.log("a")
}
b();
var b =function(){
console.log("b")
}
转到答案 10
答案
问题 1 的答案
我认为答案很简单。如果你说的是2
和1
,那么你是正确的。这个问题是关于作用域的。在 JavaScript 中,有两种类型的作用域:全局作用域和 局部作用域。在 JavaScript 函数内声明的变量是局部变量,而在函数外声明的变量是全局变量。在函数外声明的
变量保存在全局内存中。在函数内声明的变量保存在局部内存中。它们是内存中的不同位置(即使它们具有相同的名称)。var a = 1
var a = 2
问题 2 的答案
如果你说a is not defined,
你思维很健康,但答案是2
。这就是为什么 JavaScript 是一种独特的语言。根据我们在上一个问题中讨论的逻辑,变量应该在局部作用域中,但是,如果你注意的话,变量并没有声明(没有var
、let
、const
)。当我们在 JavaScript 中执行未声明的赋值时(a=2
),编译器会将变量保存在全局作用域中。仅供参考,我们可以通过添加 来修复此行为"use strict"
。
问题 3 的答案
答案是10
。这个问题是关于闭包的。简而言之,闭包是返回另一个函数的函数,内部函数可以访问外部函数的变量(您可以在此处阅读更多内容)。我们可以看看像全局作用域(外部函数)和局部作用域(内部函数)这样的闭包,它们在局部作用域内(baseValue
)。与 JavaScript 中的常规作用域一样,局部作用域可以访问全局作用域。因此,编译器可以知道什么是value
。
仅供参考,这看起来不像是一个“保守的”闭包示例,因为它是用 ES5 语法(箭头函数)编写的。“保守的”闭包示例如下:
var answer = 0;
function baseValue(value){
return function(multipleValue){
return value * multipleValue;
}
}
const multiple = baseValue(2);
answer = multiple(5);
console.log(answer);
问题 4 的答案
答案是{a: 1,b: 2}
。经过上一个问题,我们可以认识到它是一个闭包,但这个问题也与引用有关。在 JavaScript 中,有两种变量类型:原始变量(字符串,数字和布尔值)和引用变量(数组和对象)。原始变量以其值保存在内存中,而引用作为虚拟 id 保存在内存中。因此,当我们将对象从一个函数传递到另一个函数时,我们实际上传递的是虚拟 id。在我们的例子中,编译器保存了obj
并看到我们再次调用引用outerParam["b"] = innerParam.
因此,他将键b
和值2
(innerParam 的值)添加到对象中。
对于类似原始变量的情况:
function outerFunc(outerParam) {
function innerFunc(innerParam) {
outerParam = innerParam;
}
return innerFunc;
}
const num = 1
const example = outerFunc(num);
const answer = example(2)
console.log(num);
num
仍将是(1
但 outerParam 将是 2)。
问题 5 的答案
答案是[1,2,3]
,数组是引用(完整解释见上一个答案)。
问题 6 的答案
答案是[1,2]
。我用的是 ES6 的“展开运算符”,它和 do 基本一样test([1,2,3])
。这样,我们创建了一个新数组(新的引用),并将arr
引用保存在不同的 id 中——我们没有改变引用,只是添加了另一个。
问题 7 的答案
答案是[1,2]
。我知道在看了所有关于引用的解释之后,这看起来很奇怪。不过,这有一个很好的理由,运算=
符创建了一个新的引用(你可以查看这个讨论了解更多信息),它array
存在于局部作用域中,并且在这种情况下不会影响全局变量。
如果代码如下:
let arr =[1,2]
function test(array){
arr = [1,2,3]
}
test(arr)
console.log(arr)
答案是[1,2,3]
,因为在这种情况下,我们用新的引用替换了全局变量( )。arr
问题 8 的答案
答案是Joe
。这个问题的主题是“上下文”(this
)。在 JavaScript 中,this
是被调用函数 的对象。当我们这样做时var getCarName = carDetails.getName;
,我们将函数存储在全局作用域中,因此 this 将是 。Window,
由于我们在全局作用域(window)中设置name
,因此输出将是Joe
(与 window.name 相同)。这是 JavaScript 的默认行为。如果您想更改此行为,可以使用:bind、apply、call 和箭头函数。
问题 9 的答案
如果你回答了undefined
“and” b is not defined
(错误),那么恭喜你,你了解了变量提升。简单来说,变量提升就是编译器定义变量的方式。函数执行时,编译器会查找变量声明,如果变量已声明,就会将其提升到顶部。它相当于:
var a;
console.log(a)
a = 2
它只对var
.有效,let
并且const
不会“提升”变量。这就是为什么我们会看到错误:b is not defined.
问题 10 的答案
答案是a
and b is not a function
(错误)。在我看来,这是 JavaScript 中非常棘手的部分——函数也会被提升。如果你读过最后一个答案,你就会明白var
也会被提升,但运算符后面是什么并不重要=
。在提升阶段,它始终是undefined
。所以当我们执行 时b()
,它相当于undefined().
感谢您阅读本文。希望您喜欢这篇文章并学到了新知识。如果您有任何问题或建议,请留言。
文章来源:https://dev.to/tomeraitz/tricky-javascript-questions-7nk