If I have a function like
<cfscript>
function say(what) {
var a = what;
variables.b = what;
return what;
}
</cfscript>
我认为变量 a 的作用域是 variables
,但是转储 variables
只返回了 b
。那么变量 a 的作用域是什么?
If I have a function like
<cfscript>
function say(what) {
var a = what;
variables.b = what;
return what;
}
</cfscript>
我认为变量 a 的作用域是 variables
,但是转储 variables
只返回了 b
。那么变量 a 的作用域是什么?
这其实是一条注释,但太长了。看下面的代码:
<cfscript>
function doMath() {
var a = 1;
local.b = 2;
return a + local.b;
}
</cfscript>
乍一看,人们可能会认为 var
和 local.
具有相同的范围。毕竟它们都仅存在于函数内部。当函数完成时,这两个变量都不存在了。结束了吗?也许不是。
在ColdFusion中,我们有暗示范围和隐式范围。
url.a
form.a
cookie.a
session.a
application.a
local.a
arguments.a
myQuery.a
<cfoutput>#a#</cfoutput>
,我将得到哪个a
?ColdFusion会浏览其暗示范围列表,直到找到匹配项为止。并显示该内容。所以回到问题上来。
因此,当我在函数内部时,如果使用var
,我是在告诉ColdFusion,查看所有的暗示范围,直到找到匹配项为止。如果我使用local.a
,我是在告诉ColdFusion只查看一个地方并使用它。
好处
我知道我正在选择哪个变量。如果您正在编写需要尽可能快的代码,您将不使用暗示范围。如果您正在编写最易读的代码,您也将不使用暗示范围。
因此,var
不等同于local.
了解作用域可以帮助您避免一些极其难以追踪的问题。在大多数情况下,var a
将 a
放入本地作用域,并且可以作为本地变量引用。如果之后声明该变量,它将覆盖已经存在于本地作用域中的任何 a
变量。
https://trycf.com/gist/faf04daa53194a5fad2e69e164518299/acf2016?theme=monokai
<cfscript>
function say() {
local.a = "local" ;
var b = "var" ;
lv = local.b ; // We didn't explicitly assign b to Local scope.
try {
v = variables ; // Let's dump the variables scope.
} catch (any e) {
v = "Error: " & e.message ;
}
variables.nh = "Now here." ; // Explicitly populate variables scope.
var c = "var c" ; // We have a variables scope, what happens to var?
try {
v2 = variables ; // Let's dump the variables scope.
} catch (any e) {
v2 = "Error: " & e.message ;
}
var d = "var" ;
local.d = "local" ;
local.e = "local" ;
var e = "var" ;
return {
a : a , // Local.
b : b , // Var.
d : d , // Which one?
e : e , // Which one?
el : local.e , // Which one??
l : lv , // Ref b in local scope.
l2 : local , // Dump local scope.
v : v , // There doesn't seem to be a variables scope yet.
v2 : v2 // Defined a variable scope and now here.
} ;
}
writeDump(say());
</cfscript>
我们可以看到,声明var b
将b
放入local
作用域中,只有在我们向其中声明了一些内容后,variables
作用域才存在。我们可以引用local.b
,但variables.b
不存在。在我们明确创建并填充了nh
的variables
作用域之后,我们创建了一个var c
。这也没有进入variables
作用域,而是进入了local
作用域。
当一个变量在local
或var
中被使用相同的名称声明时,最后一个声明的变量将覆盖另一个变量(参见d
,e
和el
)。要注意这点。
还要注意函数中的空arguments
作用域也在local
作用域中。
关于作用域的观察,我的最后两个需要注意的事项如下:
https://trycf.com/gist/65b73e7a57d0434049d0eb9c0d5f9687/acf11?theme=monokai
<cfscript>
function ks() {
variables.jay = "Snoogins." ; // variables scope leaks out of function.
local.silentbob = "____" ; // local scope stays inside function.
}
function sayArgs(arg) {
local.arg = "local" ; // Order after agruments in CF10 but not 2016.
ks() ; // Run ks() function to instantiate jay and silentbob.
return {
arg : arg , // CF10 = arguments scope. CF11+ = local scope.
args : arguments ,
local : local , // No leakage from ks().
vars : variables // Jay leaks from ks().
} ;
}
writeDump(sayArgs("argue")) ;
</cfscript>
我注意到两件事情:
首先,在CF10和后来的CF版本中,arguments
和local
作用域的评估顺序有所不同。当前CF2016(或2011+)的行为是函数内部的local
作用域不会覆盖arguments
作用域,但它将首先进行评估。在CF10中相反:arguments
会首先进行评估。Lucee和Railo的行为类似于ACF2016。
第二个注意点与变量泄漏有关,涉及variables
和local
。 local
只存在于声明它的函数内部。 variables
更加全局,可以在函数外部访问。
https://helpx.adobe.com/coldfusion/developing-applications/the-cfml-programming-language/using-coldfusion-variables/about-scopes.html << 对于ACF2016,显示了使用local
覆盖arguments
的评估顺序。
http://www.learncfinaweek.com/week1/Scopes/ << 列出了ACF10评估顺序,但在后续版本中,arguments
和local
的顺序被交换。
https://help.adobe.com/zh_CN/ColdFusion/9.0/Developing/WSc3ff6d0ea77859461172e0811cbec09af4-7fdf.html << 这是 ACF9 的文档。它列出了与 ACF2016 相同的顺序,但在 ACF10 中不同。我现在没有 CF9 的副本来测试,因此我不知道 CF9 和更早版本如何处理评估。
让我们逐行解释(看注释):
<cfscript>
function say(what) {
// using the "var" keyword define a variable named "a" in the "local" scope
// the "local" scope is private to the current function context
// give to "a" the value of the "what" argument
var a = what;
// explicitly define a variable "b" in the "variables" scope
// the "variables" scope is available anywhere in the current template context
// give to "b" the value of the "what" argument
variables.b = what;
// return the value of "what" argument
return what;
}
</cfscript>
var
是一个关键字
variables
是一个作用域
local
是一个私有作用域(也是一个关键字)
local
作用域可以通过var a = "foo"
或local.a = "foo"
来填充。
var
关键字声明变量将其放入局部
作用域中,而不是变量
作用域中。a
仅在函数范围内可用。
var
时,变量的作用域限制在函数内部,与使用local.a
相同。 - Bernhard Döbler