VBS 中函数参数支持 ByVal 和 ByRef 两种传递方式,它们的区别是什么呢?
ByRef 表示传递的是指向对象的指针,函数体内修改变量值时将直接修改指针所指向的对象值,参数定义时如果没有声明为 ByVal 或 ByRef ,则默认为 ByRef ,例如:
msg = "DB MSG - Some junk from error message:SQL Err001"
Msgbox IsDBError(msg)
Msgbox msg
Function IsDBError(ByRef sMessage)
If inStr(sMessage, "DB") <= 0 Then
IsDBError = False
Exit Function
End If
sMessage = Replace(sMessage, "Some junk from error message:", "")
IsDBError = True
End Function
在这里调用 IsDBError 不仅返回布尔值,而且返回 ByRef 传递的修改后的变量值。
ByVal 表示传递的是对象的拷贝,函数体内修改的是局部变量的值。例如:
msg = "The field Value: abc"
Report msg
Msgbox msg
Function Report(ByVal Message)
Message = Replace(Message, "The field Value: ", "")
Msgbox (Message)
End Function
但是有个看起来像是例外的是 Dictionary ,例如下面的代码:
Sub AddValue(ByVal oDicationay)
oDicationay.Add "Some", "Thing"
End Sub
Set oDic = CreateObject("Scripting.Dictionary")
Call AddValue(oDic)
Msgbox oDic.Containes("Some") 'What will this print ,True or False?
按理, ByVal 是传递变量的拷贝,因此跳出 AddValue 函数体外之后应该取原来的变量值,但是这里脚本执行的结果是 True ,表明 AddValue 函数体内对变量值进行了直接的修改,其行为相当于 ByRef 。
原因是 oDic 对象并不是真正的 Dictionary 对象,而是指向 Dictionary 对象的指针,因此传递给 AddValue 的也不过是指针而已,最终修改的还是所指向的同一个 Dictionary 对象!
再来看下面的例子:
Sub DoIt(ByVal oDictionary)
oDictionary.Add "1", "1"
Set oDictionary = Nothing
End Sub
Sub DoIt2(ByRef oDictionary)
oDictionary.Add "2", "2"
Set oDictionary = Nothing
End Sub
Set oDic = CreateObject("Scripting.Dictionary")
Call DoIt(oDic)
MsgBox oDic.Count 'What will this print?
Call DoIt2(oDic)
MsgBox oDic.Count 'What will this print?
两个 Sub 中都用了 Set oDictionary = Nothing ,但是由于 ByVal 和 ByRef 的不同而产生不一样的结果:
第一个 Sub 中, ByVal 传递的是指向 oDic 对象的指针拷贝,因此设置为 Nothing 释放的是 oDictionary ,而不是 oDic ,因此 MsgBox 能显示 oDic 的 Count 属性值。
而第二个 Sub 中, ByRef 传递的是指向 oDic 对象的指针,因此设置为 Nothing 释放的就是 oDic 本身,因此后面的 MsgBox 尝试显示已被销毁的 oDic 对象的属性值时发生错误:缺少对象‘ oDic ’ !