{infiniteZest}
// Articles. Tutorials. Utilities.
Home  |   Search  |   Login  
Categories Skip Navigation Links
New / All
AJAX
Apple
ASP.NET
.NET
Git
Google / Android
Python / IronPython
Miscellaneous
SQL Server
How does MS AJAX validate the parameters of JavaScript functions?
Summary
Since JavaScript is a loosely-typed language, type checking is not done for you automatically. If you are writing library-type functions (those that would be used by other developers), it is very useful to validate the parameters. Here is how MS AJAX does the parameter validation.
 
Table of Contents

What type of validation is needed?

How is a validation method invoked in MS AJAX?

Code Listing 1. Validation portion of the registerClass method

Comment Portion

Validate Parameters

The Validation Functions

Figure 1. The call sequence of validation methods in MS AJAX library

Validating Parameters (_validateParams)

Code Listing 2. Complete _validateParams method

Validating the Parameter Count (_validateParameterCount)

Code Listing 3. Complete _validateParameterCount method

Code Listing 4. The _validateParameter method

Code Listing 5. The _validateParameterType method

 

JavaScript is very very forgiving with the parameters of a function. Obviously, that’s the behavior of a loosely-typed language. In defining a JavaScript function, you don’t specify the type of the argument. You can actually pass fewer or more arguments than the function is defined for.

If you call a JavaScript function with fewer arguments, the remaining arguments get an ‘undefined’ value. If you pass more than the arguments that the function is defined for, JavaScript simply ignores the excess parameters.

That type of flexibility could sometimes make the run-time behavior very unpredictable. When a function is called with an argument type that you didn’t intend, the function might actually fully get executed, but the results might seem very strange. If the codebase is small, this problem can be resolved quickly, but if you have to figure out the problem inside, say, a huge library, it would become pretty frustrating.

What type of validation is needed?

So, what do you need to check / validate with respect to the arguments passed to the function:

  • Correct number of arguments. In general, you want the call to be made with the exact number of arguments. Two exceptions: some of them are optional arguments and you are explicitly expecting a parameter array.
  • Proper type for each argument. You have developed the function assuming the arguments are of some type every time the function is called. So, a mechanism for type checking is required.

The JavaScript class libraries need to be careful and do these extra checks. If these checks fail, the method should return right away, instead of further executing and failing somewhere or corrupting some other information.

How is a validation method invoked in MS AJAX?

For all the library methods, MS AJAX uses the following system to perform the validation discussed above. Below the validation part of the registerClass method is shown:

Code Listing 1. Validation portion of the registerClass method

    /// <param name="typeName" type="String"></param>
    /// <param name="baseType" type="Type" optional="true" mayBeNull="true"></param>
    /// <param name="interfaceTypes" parameterArray="true" type="Type"></param>
    /// <returns type="Type"></returns>
    var e = Function._validateParams(arguments, [
        {name: "typeName", type: String},
        {name: "baseType", type: Type, mayBeNull: true, optional: true},
        {name: "interfaceTypes", type: Type, parameterArray: true}
    ]);
    if (e) throw e;

Comment Portion

The comment part of the validation serves as a nice documentation.

    /// <param name="typeName" type="String"></param>
    /// <param name="baseType" type="Type" optional="true" mayBeNull="true"></param>
    /// <param name="interfaceTypes" parameterArray="true" type="Type"></param>
    /// <returns type="Type"></returns>

Since JavaScript is loosely typed, the type of parameter is not specified next to the parameter in the method. The above documentation added to the methods tells a lot about the parameters of a given method.

  • name: Name of the parameter
  • type: Type of the parameter (String, Type – an MS AJAX class, Array, etc.)
  • optional: This parameter is optional; you will see that a default value is defined in the method body (or, that param might not be needed if it is not specified)
  • mayBeNull: In JavaScript null and undefined are two different things
  • parameterArray: Can pass a series of values. In the above case, the interfaceTypes can be listed one after the other

Validate Parameters

    var e = Function._validateParams(arguments, [
        {name: "typeName", type: String},
        {name: "baseType", type: Type, mayBeNull: true, optional: true},
        {name: "interfaceTypes", type: Type, parameterArray: true}
    ]);
    if (e) throw e;

The Function object is extended with a ‘private’ _validateParams method. The arguments object and an array of objects in JSON format are passed as arguments to this function.

{name: "typeName", type: String}

The above statement will make up an object with two properties: name and type. The name property will be a String with value “typeName”. And the type property will be an object with value String (the built-in and extended String object).

The Validation Functions

Following is the list of validation methods (these methods are added to the JavaScript Function object):

  • _validateParams
  • _validateParameterCount
  • _validateParameter
  • _validateParameterType

Figure 1. The call sequence of validation methods in MS AJAX library

Figure 1. The call sequence of validation methods in MS AJAX library

Let’s look at these functions a bit more closely.

Validating Parameters (_validateParams)

The _validateParams calls other validation methods. Following is the complete listing of _validateParams method.

Code Listing 2. Complete _validateParams method

function Function$_validateParams(params, expectedParams) {
    var e;
    e = Function._validateParameterCount(params, expectedParams);
    if (e) {
        e.popStackFrame();
        return e;
    }
    for (var i = 0; i < params.length; i++) {
        var expectedParam = expectedParams[Math.min(i, expectedParams.length - 1)];
        var paramName = expectedParam.name;
        if (expectedParam.parameterArray) {
            paramName += "[" + (i - expectedParams.length + 1) + "]";
        }
        e = Function._validateParameter(params[i], expectedParam, paramName);
        if (e) {
            e.popStackFrame();
            return e;
        }
    }
    return null;
}

Some important pieces of the above function are discussed below.

function Function$_validateParams(params, expectedParams) {

The arguments passed to the method and an array of expected parameters are passed as the arguments to the _validateParams method.

    e = Function._validateParameterCount(params, expectedParams);
        e = Function._validateParameter(params[i], expectedParam, paramName);

Then this method calls _validateParameterCount to see if the correct number of parameters are passed. Then for each parameter, _validateParameter is called to check whether that individual parameter is ok.

Validating the Parameter Count (_validateParameterCount)

This method checks if the length of the passed argument list is same as the number of objects in the expected parameters array.

Code Listing 3. Complete _validateParameterCount method

function Function$_validateParameterCount(params, expectedParams) {
    var maxParams = expectedParams.length;
    var minParams = 0;
    for (var i = 0; i < expectedParams.length; i++) {
        if (expectedParams[i].parameterArray) {
            maxParams = Number.MAX_VALUE;
        } else if (!expectedParams[i].optional) {
            minParams++;
        }
    }
    if (params.length < minParams || params.length > maxParams) {
        var e = Error.parameterCount();
        e.popStackFrame();
        return e;
    }
    return null;
}

Here care is taken to include the parameters in a parameter array (this is a list of parameters separated by commas at the end)

For example, in the following call to registerClass, several interfaces are listed at the end of the call (Sys.IDisposable, Sys.INotifyPropertyChange, Sys.INotifyDisposing). While the registerClass takes a maximum of 3 parameters, here the call is made with 5 parameters. The last 3 parameters form part of a parameter array.

Sys.Component.registerClass(’Sys.Component’, null, Sys.IDisposable, Sys.INotifyPropertyChange, Sys.INotifyDisposing);

H1. Validating individual Parameter (_validateParameter)

In this method, type of method is validated for both the individual parameters and the parameter array.

Code Listing 4. The _validateParameter method

function Function$_validateParameter(param, expectedParam, paramName) {
    var e;
    var expectedType = expectedParam.type;
    var expectedInteger = !!expectedParam.integer;
    var expectedDomElement = !!expectedParam.domElement;
    var mayBeNull = !!expectedParam.mayBeNull;
    e = Function._validateParameterType(param, expectedType, expectedInteger, expectedDomElement, mayBeNull, paramName);
    if (e) {
        e.popStackFrame();
        return e;
    }
    var expectedElementType = expectedParam.elementType;
    var elementMayBeNull = !!expectedParam.elementMayBeNull;
    if (expectedType === Array &&
        typeof param !== "undefined" &&
        param !== null && (expectedElementType || !elementMayBeNull)) {
        var expectedElementInteger = !!expectedParam.elementInteger;
        var expectedElementDomElement = !!expectedParam.elementDomElement;
        for (var i = 0; i < param.length; i++) {
            var elem = param[i];
            e = Function._validateParameterType(elem, expectedElementType, expectedElementInteger, expectedElementDomElement, elementMayBeNull, paramName + "[" + i + "]");
            if (e) {
                e.popStackFrame();
                return e;
            }
        }
    }
    return null;
}

H1. Validating the Parameter Type (_validateParameterType)

This method checks the type of the individual parameter. So, the JavaScript’s ‘typeof’ keyword is used a couple of times to check the type. In addition to the basic JavaScript data types like number, string, null, undefined, the object types are also validated.

Code Listing 5. The _validateParameterType method

function Function$_validateParameterType(param, expectedType, expectedInteger, expectedDomElement, mayBeNull, paramName) {
    var e;
    if (typeof param === "undefined") {
        if (mayBeNull) {
            return null;
        } else {
            e = Error.argumentUndefined(paramName);
            e.popStackFrame();
            return e;
        }
    }
    if (param === null) {
        if (mayBeNull) {
            return null;
        } else {
            e = Error.argumentNull(paramName);
            e.popStackFrame();
            return e;
        }
    }
    if (expectedType && expectedType.__enum) {
        if (typeof param !== "number") {
            e = Error.argumentType(paramName, Object.getType(param), expectedType);
            e.popStackFrame();
            return e;
        }
        if (param % 1 === 0) {
            var values = expectedType.prototype;
            if (!expectedType.__flags || param === 0) {
                for (var i in values) {
                    if (values[i] === param) {
                        return null;
                    }
                }
            } else {
                var v = param;
                for (var i in values) {
                    var vali = values[i];
                    if (vali === 0) {
                        continue;
                    }
                    if ((vali & param) === vali) {
                        v -= vali;
                    }
                    if (v === 0) {
                        return null;
                    }
                }
            }
        }
        e = Error.argumentOutOfRange(paramName, param, String.format(Sys.Res.enumInvalidValue, param, expectedType.getName()));
        e.popStackFrame();
        return e;
    }
    if (expectedDomElement &&
        param !== window &&
        param !== document &&
        !(window.HTMLElement && param instanceof HTMLElement) &&
        typeof param.nodeName !== "string") {
        e = Error.argument(paramName, Sys.Res.argumentDomElement);
        e.popStackFrame();
        return e;
    }
    if (expectedType && !expectedType.isInstanceOfType(param)) {
        e = Error.argumentType(paramName, Object.getType(param), expectedType);
        e.popStackFrame();
        return e;
    }
    if (expectedType === Number && expectedInteger) {
        if (param % 1 !== 0) {
            e = Error.argumentOutOfRange(paramName, param, Sys.Res.argumentInteger);
            e.popStackFrame();
            return e;
        }
    }
    return null;
}

Bookmark and Share This

More Articles With Similar Tags
icon-ajax-to-existing-projects.jpg
Since JavaScript has been supported by every major web browser for a long time now, every decent-sized web site uses some JavaScript. Now that ASP.NET AJAX is available, you might want to refactor and start adding some of the functionality available in these libraries. This article goes through the initial refactoring steps.
icon-ajax-browser-detection.jpg
ASP.NET AJAX client side libraries provide a Sys.Browser class. This class along with objects like Sys.Browser.InternetExplorer can be used to detect the browser that the current page is running on. This article discusses the browser detection from the client side.
icon-ajax-char-counting.jpg
It would be very useful to have counter right next to the textbox and increase that number as the user is typing into that textbox. Based on the lengths of the string entered into the textbox we could change the background of the textbox (white, yellow, red). This can be done in JavaScript (on MS AJAX) with relatively a few lines of client-side code.
icon-extender-class-hierarchy.jpg
This article looks at how a control written with MS AJAX gets initialized on the client side. Discusses the JavaScript methods from the client-side library that get called in the initialization of the control. The example used here is the creation of an instance an autocompleteextender control.
icon-ajax-sys-namespaces.jpg
This article looks at how Microsoft AJAX library adds (‘simulates’) the namespace functionality. Understanding this not only lets you create namespaces in your client-side JavaScript code, but also helps you debug the client-side code effectively.
About  Contact  Privacy Policy  Site Map