棘手的 JavaScript 问题

2025-05-28

棘手的 JavaScript 问题

为了成为一名更优秀的 JavaScript 程序员,我需要深入研究 JavaScript 基础知识。在本文中,我将向你展示一些令人费解的问题(对我来说,这确实令人费解,我希望对你来说也是如此),以便我们了解这些问题背后的一些概念。

在我们开始之前,我想提一下我用于撰写本文的一些资源,并且强烈建议您也使用它们:

  1. 70 个 JavaScript 面试问题- 优秀的文章,您可以从中学到很多有关 JavaScript 基础知识的知识。
  2. 是什么让 Javascript 变得奇怪...并且很棒- 我发现了这个 Youtube 播放列表,在我看来,这些解释非常容易理解,并且他展示了可视化的代码示例。
  3. 事件循环到底是什么?| 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);
Enter fullscreen mode Exit fullscreen mode

转到答案 1

问题 2
function foo(){
    a = 2
  }
  foo()
  console.log(a);
Enter fullscreen mode Exit fullscreen mode

转到答案 2

问题 3
var answer = 0;

const baseValue = value => multipleValue => value * multipleValue;

const multiple = baseValue(2);
answer = multiple(5);
console.log(answer);
Enter fullscreen mode Exit fullscreen mode

转到答案 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);
Enter fullscreen mode Exit fullscreen mode

转到答案 4

问题 5
let arr =[1,2]
function test(array){
  array.push(3)
}
test(arr)
console.log(arr)
Enter fullscreen mode Exit fullscreen mode

转到答案 5

问题 6
let arr =[1,2]
function test(array){
  array.push(3)
}
test([...arr])
console.log(arr)
Enter fullscreen mode Exit fullscreen mode

转到答案 6

问题 7
let arr =[1,2]
function test(array){
  array = [1,2,3]
}
test(arr)
console.log(arr)
Enter fullscreen mode Exit fullscreen mode

转到答案 7

问题 8
const carDetails = {
    name: "Tomer",
    getName(){
       return this.name;
    },
  };
  var name = "Joe";
  var getCarName = carDetails.getName;
  console.log(getCarName());
Enter fullscreen mode Exit fullscreen mode

转到答案 8

问题 9
console.log(a)
console.log(b)
var a = 2
let b = 2
Enter fullscreen mode Exit fullscreen mode

转到答案 9

问题 10
a()
function a(){
    console.log("a")
}
b();
var b =function(){
    console.log("b")
}
Enter fullscreen mode Exit fullscreen mode

转到答案 10

答案

问题 1 的答案

我认为答案很简单。如果你说的是21,那么你是正确的。这个问题是关于作用域的。在 JavaScript 中,有两种类型的作用域:全局作用域和 局部作用域。在 JavaScript 函数内声明的变量是局部变量,而在函数外声明的变量是全局变量。在函数外声明的
变量保存在全局内存中。在函数内声明的变量保存在局部内存中。它们是内存中的不同位置(即使它们具有相同的名称)。var a = 1var a = 2

回到问题 1

问题 2 的答案

如果你说a is not defined,你思维很健康,但答案是2。这就是为什么 JavaScript 是一种独特的语言。根据我们在上一个问题中讨论的逻辑,变量应该在局部作用域中,但是,如果你注意的话,变量并没有声明(没有varletconst)。当我们在 JavaScript 中执行未声明的赋值时(a=2),编译器会将变量保存在全局作用域中。仅供参考,我们可以通过添加 来修复此行为"use strict"

回到问题2

问题 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);
Enter fullscreen mode Exit fullscreen mode

回到问题 3

问题 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);
Enter fullscreen mode Exit fullscreen mode

num仍将是1但 outerParam 将是 2)。

回到问题4

问题 5 的答案

答案是[1,2,3],数组是引用(完整解释见上一个答案)。

回到问题5

问题 6 的答案

答案是[1,2]。我用的是 ES6 的“展开运算符”,它和 do 基本一样test([1,2,3])。这样,我们创建了一个新数组(新的引用),并将arr引用保存在不同的 id 中——我们没有改变引用,只是添加了另一个

回到问题 6

问题 7 的答案

答案是[1,2]。我知道在看了所有关于引用的解释之后,这看起来很奇怪。不过,这有一个很好的理由,运算=符创建了一个新的引用(你可以查看这个讨论了解更多信息),它array存在于局部作用域中,并且在这种情况下不会影响全局变量。
如果代码如下:

let arr =[1,2]
function test(array){
  arr = [1,2,3]
}
test(arr)
console.log(arr)
Enter fullscreen mode Exit fullscreen mode

答案是[1,2,3],因为在这种情况下,我们用新的引用替换了全局变量( )。arr

回到问题7

问题 8 的答案

答案是Joe。这个问题的主题是“上下文”(this)。在 JavaScript 中,this是被调用函数 的对象。当我们这样做时var getCarName = carDetails.getName;,我们将函数存储在全局作用域中,因此 this 将是 。Window,由于我们在全局作用域(window)中设置name,因此输出将是Joe(与 window.name 相同)。这是 JavaScript 的默认行为。如果您想更改此行为,可以使用:bind、apply、call 和箭头函数。

回到问题 8

问题 9 的答案

如果你回答了undefined“and” b is not defined(错误),那么恭喜你,你了解了变量提升。简单来说,变量提升就是编译器定义变量的方式。函数执行时,编译器会查找变量声明,如果变量已声明,就会将其提升到顶部。它相当于:

var a;
console.log(a)
a = 2
Enter fullscreen mode Exit fullscreen mode

它只对var.有效,let并且const 不会“提升”变量。这就是为什么我们会看到错误:b is not defined.

回到问题 9

问题 10 的答案

答案是aand b is not a function(错误)。在我看来,这是 JavaScript 中非常棘手的部分——函数也会被提升。如果你读过最后一个答案,你就会明白var也会被提升,但运算符后面是什么并不重要=。在提升阶段,它始终是undefined。所以当我们执行 时b(),它相当于undefined().

回到问题 10

感谢您阅读本文。希望您喜欢这篇文章并学到了新知识。如果您有任何问题或建议,请留言。

文章来源:https://dev.to/tomeraitz/tricky-javascript-questions-7nk
PREV
10 个能让你成为更优秀开发人员的项目和技能
NEXT
JavaScript 中的模块模式