Jake said:
I've a form for creating podcast episodes. The user can pick an MP3
from a drop down box (an HTML select box). I'm trying to add some error
checking. In the code below, I try to get the value of the select box,
and then I try to see if it contains the string ".mp3". I'm getting the
alert message every time. Why is that?
var inputToCheckReference =
document.getElementById(idOfFirstInputThatWeShouldCheckString);
Be sure to do feature tests.
if (inputToCheckReference != false && inputToCheckReference !=
undefined) {
There is no point in this for several reasons. First, comparing a boolean
against `false' is unnecessary; you can always use !inputToCheckReference
instead.
Second, if a boolean is returned, there is redundancy. Because in
true != false && true != undefined
(if we assume it is a true-value, see below) the second operand of `&&'
will be evaluated but also implicitly type-converted to
true != false (== !(1 == 0) == true)
and in
false != false && false != undefined
(if we assume it is a false-value, see below) the second operand will
never be evaluated because the first operand evaluates to
!(0 == 0) == false
Third, gEBI is not supposed to return a boolean at all, it is supposed
to return an object reference, `null' or /an/ undefined value (that is
not necessarily /the/ `undefined' value).
<URL:
http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-getElBId>
You cannot know about the value that the W3C DOM Level 2+3 Specifications
define as "undefined", so there is no way of testing against it. However,
a DOM implementation with reasonable ECMAScript language binding would
return a false-value then (one of `undefined', `null', `false', +0, -0,
NaN, or "").
So this test should be simply
if (inputToCheckReference)
var valueOfInputToCheckString = inputToCheckReference.value;
Since you do not test that value later, there is no need for assigning
it to a variable.
var regXString = characterThatsNeededForThisField;
var regX = new RegExp(regXString, "g");
Unless the `characterThatsNeededForThisField' are variant, there is no
need for the `regXString' and `regX' variables, including the RegExp
constructor.
var results = valueOfInputToCheckString.match(regX);
var results = valueOfInputToCheckString.match(/.../g);
var resultsTypeof = typeof(results);
Again, there is no need for this variable. And `typeof' is an operator,
not a function.
if (resultsTypeof != Array) {
`resultsTypeof' will always be a non-empty string, as that is what the
`typeof' operator evaluates to (in your case, always "object" [Array or
`null']). But `Array' is a Function object reference.
In order not to bother you with the details: that expression evaluates to
true always. Therefore, the (currently empty) first branch should be
executed always. (It does in my tests.)
The correct test would be
if (results)
I do not understand why you are "getting the alert message every time",
because you should _never_ get it with this code (the alert() call is in
the else-branch which should never be executed). The only reason I can
think of is that you are not using the code that you have posted. Another
indication of that is that you have replaced everything with identifiers
in the posted code.
(See the bottom of this posting for an example of how to do better.)
--------------------------------------------------------------------------
However, for those who are interested in the details, the following should
happen according to ECMAScript Ed. 3 Final:
| 11.9.2 The Does-not-equals Operator ( != )
|
| The production EqualityExpression :
| EqualityExpression != RelationalExpression
| is evaluated as follows:
|
| 1. Evaluate EqualityExpression.
| 2. Call GetValue(Result(1)).
| 3. Evaluate RelationalExpression.
| 4. Call GetValue(Result(3)).
| 5. Perform the comparison Result(4) == Result(2). (Section 11.9.3.)
| 6. If Result(5) is true, return false. Otherwise, return true.
| 11.9.3 The Abstract Equality Comparison Algorithm:
|
| The comparison x == y, where x and y are values, produces true or false.
x := "object"
y := Array
| Such a comparison is performed as follows:
|
| 1. If Type(x) is different from Type(y), go to step 14.
|
| (According to 5.2: Type(x) == String, Type(y) == Object)
| [...]
| 14. If x is null and y is undefined, return true.
| 15. If x is undefined and y is null, return true.
| 16. If Type(x) is Number and Type(y) is String,
| return the result of the comparison x == ToNumber(y).
| 17. If Type(x) is String and Type(y) is Number,
| return the result of the comparison ToNumber(x) == y.
| 18. If Type(x) is Boolean, return the result of the comparison
| ToNumber(x) == y.
| 19. If Type(y) is Boolean, return the result of the comparison
| x == ToNumber(y).
| 20. If Type(x) is either String or Number and Type(y) is Object,
| return the result of the comparison x == ToPrimitive(y).
Result(20) := "..." == ToPrimitive(Array)
According to "9.1 ToPrimitive":
| Input Type Result
|
| [...]
| Object Return a default value for the Object. The default value of
| an object is retrieved by calling the internal
| [[DefaultValue]] method of the object, passing the optional
| hint PreferredType. The behaviour of the [[DefaultValue]]
| method is defined by this specification for all native
| ECMAScript objects (section 8.6.2.6).
According to 8.6.2.6 [[DefaultValue]] (hint):
| 1. Call the [[Get]] method of object O with argument "toString".
Result(1) := Array.toString() == "function Array() { ... }"
| 2. If Result(1) is not an object, go to step 5.
| [...]
| 5. Call the [[Get]] method of object O with argument "valueOf".
Result(5) := Array.valueOf() == function Array() { ... }
| 6. If Result(5) is not an object, go to step 9.
| 7. Call the [[Call]] method of Result(5), with O as the this value and
| an empty argument list.
Result(7) := (function Array() { ... })[[Call]](this := Array)
(equivalent to Array.call(Array))
According to 13.2.1 [[Call]]:
| 1. Establish a new execution context using F's FormalParameterList, the
passed arguments list, and the `this' value as described in Section
10.2.3.
| 2. Evaluate F's FunctionBody.
According to 15.4.1 The Array Constructor Called as a Function:
| When Array is called as a function rather than as a constructor, it
| creates and initialises a new Array object. Thus the function call
| Array(...) is equivalent to the object creation expression new Array(...)
| with the same arguments.
| 15.4.2.1 new Array ( [ item0 [ , item1 [ , ... ] ] ] )
|
| This description applies if and only if the Array constructor is given no
| arguments or at least two arguments.
|
| The [[Prototype]] property of the newly constructed object is set to the
| original Array prototype object, the one that is the initial value of
| Array.prototype (section 15.4.3.1).
|
| The [[Class]] property of the newly constructed object is set to "Array".
|
| The length property of the newly constructed object is set to the number
| of arguments.
|
| The 0 property of the newly constructed object is set to item0 (if
| supplied); the 1 property of the newly constructed object is set to item1
| (if supplied); and, in general, for as many arguments as there are, the k
| property of the newly constructed object is set to argument k, where the
| first argument is considered to be argument number 0.
That means
Array.call(Array) == [] (empty array)
| 3. Exit the execution context established in step 1, restoring the
| previous execution context.
| 4. If Result(2).type is throw then throw Result(2).value.
| 5. If Result(2).type is return then return Result(2).value.
This would apply then.
And back to 8.6.2.6 [[DefaultValue]] (hint):
Result(7) := []
| 8. If Result(7) is a primitive value, return Result(7).
| 9. Throw a TypeError exception.
Since [] is not a primitive value, the exception should be thrown.
| 5.2 Algorithm Conventions
|
| [...]
| If an algorithm is defined to "throw an exception", execution of the
| algorithm is terminated and no result is returned. The calling algorithms
| are also terminated, until an algorithm step is reached that explicitly
| deals with the exception, using terminology such as "If an exception
| was thrown...". Once such an algorithm step has been encountered the
| exception is no longer considered to have occurred.
If I am not mistaken, something interesting happens here: The Specification
says that no result would be returned, and that the calling algorithms are
terminated then. Which should leave us with
Result(20) := "..." == ?
in 11.9.3.
However, since we know the expression "object" != Array evaluates to `true'
in implementations, some value that is required for
| 11.9.2 The Does-not-equals Operator ( != )
|
| [...]
| 5. Perform the comparison Result(4) == Result(2). (Section 11.9.3.)
| 6. If Result(5) is true, return false. Otherwise, return true.
must have been returned.
I see two possibilities for this to happen:
A) Array.call(Array) returns `undefined' internally (although we know
it returns [] in the implementation), therefore [[DefaultValue]]'s
Result(7) would be undefined.
B) "No result" for an execution context that throws an exception would
allow for "the `undefined' value". Since no exception happens in
the implementation, it would have to discard it silently.
Then `"object" == undefined' evaluated to `false', and therefore
`!("object" == undefined)' evaluated to `true'.
Am I missing something important here?
----------------------------------------------------------------------
As for your approach:
<form ... onsubmit="return isMP3(this);">
<script type="text/javascript">
function isMP3(f)
{
var es, sel;
if (f && (es == f.elements)
&& (sel = es['formInputs[cbLinksToWhatUrl]']))
{
if (!sel.options[sel.selectedIndex].value.test(/\.mp3$/))
{
window.alert("Please select an MP3 file.");
return false;
}
}
else
{
window.alert("h4x0r error. Please install Brain 1.0.");
return false;
}
return true;
}
</script>
<fieldset>
<select name="formInputs[cbLinksToWhatUrl]" ...>
<option value="" selected>--- Select a file ---</option>
...
</select>
</fieldset>
</form>
PointedEars