5

如果你不知道我在说什么,试试这个:

<cffunction name="myFunc">
    <cfargument name="myArg" default="foobar">
    <cfdump var="#local#" label="local and arguments scopes before deleting myArg">
    <cfset StructDelete(arguments, "myArg")>
    <cfdump var="#local#" label="local and arguments scopes after deleting myArg">
    <cfset StructDelete(local, "arguments")>
    <cfdump var="#local#" label="local scope after deleting arguments scope">
    <cftry>
        <cfset writeOutput("myArg still exists, and evaluates to: " & myArg)>
        <cfcatch>
            <cfset writeOutput("myArg no longer exists")>
        </cfcatch>
    </cftry>
</cffunction>

<cfset myFunc()>

<cfexit>

如果您运行该代码,您会发现即使在删除参数和参数范围之后,您仍然可以通过非范围引用访问声明的参数。这意味着存在一个未命名的范围,其中包含声明的参数的副本或值的引用。我试图找出是否有某种方法可以直接使用此范围,例如未记录的范围名称或底层 Java 中的 getter 方法。现在考虑这是一个纯粹的学术问题,因为我很确定我可能想到的任何用例都会被大多数有声望的程序员忽略掉。

编辑

我认为提供我目前对 UDF 范围的理解的细分可能很有用,因为 Adam 的反应有点模糊了界限。为简单起见,我将排除特定于 cfc 的内容...

  • 没有范围或“var”关键字定义的变量被放置在调用页面的变量范围中。

  • 局部作用域包含在函数执行期间使用var关键字或局部作用域名称(例如 local.myvar、local["myvar"])创建的变量。它还包含参数范围。

  • arguments范围包含在函数调用中声明或传递的每个参数。变量也可以在函数执行期间添加到其中或从中删除。arguments作用域是本地作用域的成员,可以这样引用(例如 local.arguments.myvar、local.arguments[1]),但也可以单独引用(例如 arguments.myvar、arguments[1]) .

  • 有一个无名作用域,其中包含声明的每个参数的副本(即包含在 cfargument 标记中,或 cfscript 中函数定义开头的括号中)。我观察到与此范围相关的以下特征和行为:

    • 未声明的参数不会添加到无名范围。

    • 声明参数是使变量进入无名作用域的唯一方法,ColdFusion 似乎不会在任何其他情况下使用它。

    • 参数作用域不同,无名作用域与局部作用域没有明显关系。

    • 无名范围变量的值及其参数范围对应的值要么是对相同值的引用,要么以这样一种方式相互连接,即改变一个会改变两者。

    • 将新变量动态添加到参数不会其添加到无名范围(因为只有声明的参数才会添加到无名范围)。

    • 您不能通过常规方式(即 StructDelete()、ArrayDeleteAt())删除无名范围的变量。您可以删除其arguments范围的对应项,但该值将通过无范围的引用保持可用。(有关完全删除已声明参数的方法,请参见亨利的回答)。

    • 一旦从arguments中删除了已声明的参数,就可以独立设置其无名范围对应项的值。即使将具有相同名称的变量添加回arguments ,这仍然是正确的。

    • CF9 和 CF10 中存在无名范围,但(正如 Henry 和 Adam 指出的)Railo 中没有。

    • 无名作用域位于 CF 作用域层次结构的绝对顶部,在使用无作用域引用时优先于所有其他作用域。这一点,连同前面关于不可删除性的观点,可能是关于无名作用域最重要的事情。与官方文档相反,特定于功能的范围层次结构如下:

      1. 无名(声明的参数)
      2. 当地的
      3. 论据
4

2 回答 2

2

在 ColdFusion 中,所有参数都在每个函数开头的未命名函数局部范围内重复。这段代码:

<cfset writeOutput("myArg still exists, and evaluates to: " & myArg)>

不是访问参数范围,而是访问函数本地范围。如果您更改代码以访问参数范围,您将 - 不出所料 - 看到该变量不再存在。

顺便说一句,Railo 的行为并非如此。

于 2013-09-11T06:08:11.000 回答
1

有趣的是,这个测试用例有一个非常奇怪的行为。我不知道为什么myArg仍然可用。但是,如果您确定 var 的范围并执行以下操作:

<cfset writeOutput("myArg still exists, and evaluates to: " & arguments.myArg)>

或者,如果不是structDelete(),您将其设置为null

<cfset myArg = javacast("null","")>

然后你会得到"myArg no longer exists".

它可能是 Adob​​e CF 优化的边缘案例。Railo 按预期运行并获得预期结果。您可以在http://cflive.net/上自行测试

于 2013-09-11T01:15:35.920 回答