Brian Lalonde
VBScript and JScript are extremely lightweight ActiveX Scripting languages. ActiveX Scripting Engines may be used in a variety of Microsoft environments: Windows Scripting Host, HyperText Applications, HyperText Components and scripting for Internet Explorer, and classic Active Server Pages. There are other ActiveX Scripting languages, such as ActivePerl and ActivePython, but these tend to be complete languages in contrast to the minimal logic layer that VBScript and JScript provide. In fact, VBS/JS must use ActiveX/COM components to accomplish anything other than trivial tasks. This optimization results in some noteworthy shortcomings in both languages.
VBScript is typically the default scripting language for ActiveX Scripting environments, and so is used far more widely than any other scripting engine. The English-like syntax is arguably more approachable for less technical users. VBScript SafeArrays are typically the type of array expected by COM components (e.g. the ActiveDirectory Filter property).
Multiple, bidirectional, or large arguments may be passed ByRef
. This bypasses creating a local copy of the variable (increasing efficiency for large values), and allows the function or subroutine to make changes to a variable passed to it.
FormatCurrency
, FormatDateTime
, FormatNumber
, and FormatPercent
not only make short work of tedious formatting tasks, but also use locale-specific formatting rules.
CBool
, CByte
, CCur
, CDate
, CDbl
, CInt
, CLng
, CSng
, and CStr
all tend to overreact to unconvertable data by throwing runtime errors, but are complemented by VarType
, IsDate
, IsEmpty
, IsNull
, IsNumeric
, and IsObject
. Hex
and Oct
allow converting numbers to non-decimal strings (though no functions are provided to do the inverse). DateValue
and TimeValue
allow returning just the parsed date or time values, respectively.
Along with the usual functions for individual date fields, Day
, Hour
, Minute
, Month
, MonthName
, Second
, Timer
, Weekday
, WeekdayName
, Year
, and the more generic DatePart
, there are some more granular functions for current info: Now
, Date
, Time
. The DateSerial
and TimeSerial
functions allow for complex date arithmetic, as do DateAdd
, DateDiff
. Date literals are supported, using #
as the delimiter: #
datestring#
(using various formats). Durations can be stored as date/time values, except month durations.
Collections (objects containing multiple values that can only be accessed one after the other, starting at the first) can be iterated natively using For Each
.
VBScript supports true constants, which are faster than alternatives (variables or functions), and enforce the read-only nature of constants.
With
Blocks
Using With
allows you to perform several operations on an object without using a temporary variable. It is particularly well-suited to DOM programming. The VBScript syntax for With
blocks is unambiguous, so there are no performance or readablity drawbacks.
With
xml.appendChild(xml.createElement("category"))
.setAttribute("id",id)
.setAttribute("keywords",keywords)
With
.appendChild(xml.createElement("item"))
.setAttribute("count",count)
.setAttribute("tip",tip)
.appendChild(xml.createTextNode(text))
End
With
End
With
While standard functions like Filter
, Join
, and
Split
Appending to strings in VBScript is shockingly slow. VBScript code should avoid repeated concatenation whenever possible.
Date/time values cannot be reliably converted between UTC and local timezones, since there is no way to determine either the local timezone or Daylight Saving Time (Summer Time in
Automatic exception handling has two modes: on (all errors and warnings are fatal), and off. Modern, structured exception handling is not supported.
Objects are not first-class objects; assignment, for example, is handled completely differently from built-in datatypes. Passing functions as arguments requires using the GetRef
keyword. Adding to this difficulty, naught is expressed in many distinct (and confusing) terms: Nothing
is an invalid object variable, Null
adds the database-style complexity of three-valued logic (not true, but not false either), and Empty
is the value in an uninitialized variable. Numeric values can be interpreted as booleans, as can some string values (but only if they are numeric or boolean strings):
Expression
|
Value
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Error
|
|
|
|
|
|
Error
|
The only way to avoid evaluating conditions in VBScript is to put them into separate If
statements. This means much more verbose code when the second condition relies on the success of the previous one:
' Wrong
If
Not
conn
Is
Nothing
And
conn.State
=
ADODB.adStateOpen
Then
' won't work
' continue
Else
' problem
End
If
' Redundant Workaround
If
Not
conn
Is
Nothing
Then
If
conn.State
=
ADODB.adStateOpen
Then
' continue
Else
' problem (first time)
End
If
Else
' problem (again)
End
If
' Manual Short-Circuit Workaround
Dim
ok
ok=
Not
conn
Is
Nothing
If
ok
Then
ok=
conn.State
=
ADODB.adStateOpen
' conditional second test
If
ok
Then
' continue
Else
' problem
End
If
Anyone familiar with client-side web scripting can start using JScript right away.
A reasonable complement of expected array functions is supported: sort
, split
, join
, slice
, splice
, concat
, push
, pop
, shift
, unshift
, and reverse
. No grep/filter, search, or membership-test function are provided.
Actually, all JScript arrays are hashes: an array with numeric keys can have string keys added, and all keys can be iterated via the for
...in
loop. As Perl programmers already know, native hash support allows arbitrarily complex data structures to be built quite easily.
Using try
...catch
, errors can be handled much more readably, maintainably, and conveniently.
Specially formatted comments can be used to hide code from the scripting engine based on platform or JScript version for last-minute optimization.
Date/time values can be converted between UTC and local timezones, even handling Daylight Saving Time (Summer Time in
JScript stops evaluating a conditional expression as soon as it knows the outcome, skipping superfluous subexpressions. Not only is this more efficient, but it enables subexpressions to assume previous subexpressions have succeeded:
if(conn && conn.State == ADODB.adStateOpen)
conn.Execute(SQL);
Any COM components that require reference parameters are completely useless to JScript.
Tool support for JScript tends to be somewhat scarcer than VBScript. Productive familiarity with the language is also less common, particularly outside of web development groups.
All languages should have some kind of formatting ability: C's (and Perl's) printf
, C++'s iomanip.h
library, Python's %
operator, etc. JScript has only toFixed
and toExponential
for specifying the number of digits a number should include after the decimal. Doing something as simple as grouping digits in a number is incredibly tedious. Localized formatting is completely out of the question.
Dates and non-decimal numbers (e.g. hexadecimal strings) are not converted natively.
No native currency (fixed decimal) type is supported, so rounding errors may have a tendency to creep into many calculations. In fact, all numbers are treated as double floating point; no integer, long integer, or single float types are available.
No functions exist specifically for date/time arithmetic, and there is an inadequate granularity for parsing control. No date literal is supported.
Special values must be stored in variables, or trivial functions, neither of which are optimal.
with
Blocks
Since the syntax for with
blocks in JScript is ambiguous, members (indeed, all variables and functions within the block) must be searched for and bound at runtime. Without any distinguishing features, it is also impossible to see which items are members of the with
object when reading the code.
with(o)
{
a=x;
// o.a=x or a=o.x or o.a=o.x or just a=x ?
M(w);
// o.M(w) or M(o.w) or o.M(o.w) or just M(w) ?
}
The interpreter (and the reader) has no way to know which items within the with
block are members of o
, so it has to wait until runtime and painstakingly check each item.
Looping over items in a collection requires an Enumerator
object.
for(var e= new Enumerator(fso.Drives); !e.atEnd(); e.moveNext())
{
WScript.Echo(e.item().DriveLetter);
}