jjzjj

javascript - 为什么变量声明不允许作为参数,而函数声明可以?

coder 2025-02-20 原文

这可能是个愚蠢的问题。我用谷歌搜索但找不到答案。如下所示,变量声明不允许作为函数的参数。

function t(a) {
    alert(a);
}

t(var x = 1); // Uncaught SyntaxError: Unexpected token var
t(let x = 1); // Uncaught SyntaxError: missing ) after argument list
t(x = 1); // working fine and later I am able to access x also
console.log(x); // printing 1

但是函数声明被允许作为函数的参数,如下所示。

function callback(str, f1, f2) {
    if(str == "")
        f1();
    else
        f2();
};

callback("", function b1() { alert("empty") }, function b2() { alert("not empty") }); // working fine

b1(); // Throwing error Uncaught ReferenceError: b1 is not defined

谁能帮我理解一下

  • 为什么变量声明不允许作为函数的参数 但允许函数声明作为参数?
  • 为什么我们不能访问声明为函数的函数 函数调用之外的参数?

最佳答案

好问题!我会把它分成几部分。此处将有很多 Material 可供谷歌搜索,因为您的问题涉及多个深层次主题。

1。语句没有值(value)

声明是声明。它们没有值(value),因此不能作为参数。这段代码...

let a = 1

...没有值(value),意味着这些都不起作用:

doStuff(let a = 1)
let b = (let a = 1)
(let a = 1) + 5

名字a , 或 a + 5 , 或 f(a)表达式,与语句不同,表达式具有值。但是a的声明本身没有。

请注意,您对此的直觉并不荒谬:在其他语言中,let a = 1是一个计算结果为 1 的表达式.不在 Javascript 中。

2。函数是对象

但是function关键字确实有值:Function它定义的对象。与为方便起见的语言构造变量不同,Functions是存在于运行程序中的实际对象。我们说函数是一等对象

可以做所有这些:

doStuff(function f() {})
let a = function f() {}
let b = (function f() {}) + 5 // the result of this is funny

回到你的例子,然后:

callback(
  "", // a String object
  function b1() { alert("empty") }, // a Function object
  function b2() { alert("not empty") } // a Function object
);

类似这样:

function b1() { alert("empty") }
function b2() { alert("not empty") }

callback("", b1, b2)

但不完全是。让我们谈谈作用域。

3。名称在范围内定义

名称(例如变量或函数)的范围是具有该定义的代码部分。

例如:

// Top-level scope:
let a = 1

if (a == 1) {
  // Inner block scope:
  let b = 2
  console.log(a, b) // 1, 2
}

console.log(a, b) // 1, undefined

作用域存在于更大的作用域中。内部作用域可以访问周围的作用域(因此 ab 在 block 内部可见)但反之则不行(因此 b 在外部不可见)。

当您创建 function 时调用中的对象...

f(function a() { })

...它们被困在内部范围内,无法从外部引用。

4。赋值是表达式

在您的示例代码中,您注意到声明 a像这样工作:

f(a = 5)

这……很不幸。确实是 Javascript 历史的产物。在现代代码中,您应该始终使用 letconst定义变量。

那么它为什么有效?两个原因。首先,因为它是一个赋值,而不是一个声明。像这样:

let x = 1
f(x = 2)

赋值是表达式。他们评估分配的值。 x = 2 的值是2 , 和 x作为副作用发生变化。

5.有一个全局范围

第二个原因是不幸的。当你避开 let , varconst关键字,您隐式使用了 global范围。

这是所有作用域之母,可以从代码中的任何位置访问存在于其中的名称。所以,如果你只是这样做......

f(a = 5)

... 没有声明 a当前作用域中的任何地方,它在全局作用域中隐式声明,并且赋值发生。把它想象成这样(伪代码):

global let a
f(a = 5)

那当然不是有效的 Javascript。但是你明白了。

关于javascript - 为什么变量声明不允许作为参数,而函数声明可以?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54032324/

有关javascript - 为什么变量声明不允许作为参数,而函数声明可以?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  7. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  8. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  9. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  10. ruby-on-rails - active_admin 目录中的常量警告重新声明 - 2

    我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA

随机推荐