Click here to Skip to main content
15,867,330 members
Articles / Web Development / HTML

HTML5, JavaScript, Knockout, JQuery, Guide for Recovering Silverlight/WPF/C# Addicts. Part 1 - JavaScript and DOM.

Rate me:
Please Sign up or sign in to vote.
4.88/5 (86 votes)
30 Nov 2012CPOL26 min read 169.2K   1.3K   179   78
JavaScript/DOM basics for WPF/Silverlight/C# developers

Introduction  

Being a consultant, makes me very sensitive to the newest trends in technology.

Several years ago, I came across WPF and fell in love with it. WPF introduced brand new concepts that enable the developers to achieve almost total separation between the visual design of the UI application and the underlying non-visual implementation. At the same time WPF provides great features for visual development. Silverlight brought the WPF power to multiple platforms.

Recent developments, however, indicate that Microsoft soured on both WPF and Silverlight in favor of HTML5/JavaScript. This is, probably, the correct strategy for Microsoft in the current tough situation. Over a period of several years, Microsoft lost its status as the largest software company and lost its superiority in the internet browser market. The primary reason behind it is that Microsoft overlooked and came too late to the smart phone and tablet markets. Being a follower is different from being the trend setter and currently Microsoft has to beat everyone else in their own game, which is HTML5 and JavaScript (and based on the previous history I am confident it is going to become a leader again).

These developments caused me to put a lot of effort into learning and working with HTML5 and JavaScript. I am also trying to understand how to apply the concepts I learned while working on WPF/Silverlight in JavaScript development.

The purpose of these series of articles is to make it easier for WPF/Silverlight developers to master programming HTML5/JavaScript utilizing WPF and Silverlight concepts. These articles assume that the reader already has some basic familiarity with HTML and JavaScript, so people who are completely new to it, should start with something else.

I also highly recommend pluralsight.com as a resource for HTML5/JavaScript learning.

Good and Bad about JavaScript and HTML

The following are the advantages of JavaScript and HTML:
  • HTML/JavaScript is a must if you want your application to reach many different platforms, including mobile platforms (IPhone, Android and Windows 8), especially if you want to avoid the hustle of going through putting your application on Apple or Window store.
  • Contrary to my experience 10 years ago, one can easily write a JavaScript code that is truly cross browser without much extra effort by utilizing JavaScript libraries that absorb the browser     differences. The same cannot be said, though about HTML5 and CSS3 features. HTML5 and CSS3 specifications have not been finalized yet and different browsers implement different subsets of it. One can visit caniuse.com web site to see what features are implemented by which browsers. According to this web site Google chrome is ahead of every other browser in terms of HTML5 and CSS3 implementation.
  • JavaScript is sufficiently powerful to implement WPF features resulting in separation between visual and non-visual functionality, namely observable properties and bindings. Knockout.js library is doing precisely that (and in some respect even more).
  • JavaScript as a loosely typed language is more powerful than C# - there are no restrictions on what object you can pass to which function. The flip side of it is, of course, that things can go wrong much easier in JavaScript and will be more difficult to detect.
  • You can use Ajax to send only data in JSON format between the server and the client instead of transferring large parts of HTML code.
  • You can prototype very fast with JavaScript.
  • HTML5 provides powerful visual capabilities comparable to those of WPF and Silverlight.
  • As browsers mature, the HTML5 features will become more and more hardware accelerated which will greatly improve the speed of rendering visuals and animating them.

JavaScript script has all the disadvantages of a loosely typed language:

  • The structure of its objects is not defined by classes, in fact, its objects are built by the functions when the application is running so that when you see e.g. an argument passed to a function you'll have a difficult task trying to figure out what information it contains. This makes code analysis quite difficult and requires much more documentation. Good documentation should also specify the implied structure of the objects passed to functions.
  • While in C#, Java and C++, the architects and senior developers can enforce certain uniformity of the code by providing a bunch of interfaces and requiring the rest of the team to work with them, no such ability exists in JavaScript. So when you have several people with different level of experience on a team, you can only rely on code reviews, tight code acceptance process, extensive documentation and tests to ensure the code quality.
  • Every JavaScript object is just a Dictionary (or Map or Bag) of fields and functions. The functions resolve the fields by names (not by offsets as in strongly typed languages). As a result, JavaScript language is slower than strongly typed languages.
  • Since the object type is difficult to infer, support for intellisense is not as good in JavaScript as it is in strongly typed managed languages.
  • The central object in JavaScript is a function, so JavaScript is actually related to functional languages just like F# and Lisp. The generic modules like JQuery.js or Knockout.js are written as a number of different functions calling each other without many intermediary results. This makes it difficult to analyze and debug the code, even though JavaScript code can also be written in a more object-oriented style.

Creating a Simple HTML Project in MS Visual Studio

Let us start by creating the simplest possible JavaScript project in Microsoft Visual Studio. While I am using VS 2010 SP1, one can create an HTML/JavaScript project in VS 2012 in exactly the same fashion.

When you are trying to create an HTML or JavaScript project in Visual Studio, you will discover that Microsoft does not provide any template for HTML or JavaScript. When creating a new project you should choose "ASP.NET Empty Web Application" project template:

Image 1

Name the project "HelloWorldJS" and click OK button to create the project.

Add an empty HTML file called HelloWorld.html to the project by right clicking on the project within Solution Explorer and then choosing Add->New Item. Within the open dialog choose "HTML Page" for the item type and name the file HelloWorld.html.

Within the HTML "body" tag, add the following code <h1>Hello World</h1>. You can now run the project and it will display "Hello World" in large letters.

Important note: Before running the project, make sure that HelloWorld.html file has the key board focus within Visual Studio before you press "Run" icon. You can run different HTML files by changing the keyboard focus between them.

Adding a Reference to JQuery

JQuery is a cross-browser JavaScript library for parsing HTML DOM. It greatly simplifies the development effort. You can download the latest version of JQuery script from jquery.com and add it manually to the project, or, even simpler, you can download a reference to JQuery as a NuGet package.

Before you can use Visual Studio to install NuGet packages, you need to install NuGet Package Manager VS extension. You do it once for your Visual Studio and it will enable you to install NuGet packages for any project you need.

To install NuGet Package Manager, go to "Tools" menu within your Visual Studio and choose "Extension Manager" menu item. Choose "Online Gallery" option on the left of the window. Type "nuget package manager" in the search area located at the top right corner of the Extension Manager window and press the "Download" button next to "NuGet Package Manager" item to download and install it:

Image 2

After the installation restart your Visual Studio so that you could start using NuGet Package Manager.

To install JQuery for your project, right mouse click on the "References" within the Solution Explorer and choose "Manage NuGet Packages" option (which should be there after the installation of NuGet Package Manager). Within the search area on the right hand side at the top of the dialog, type "jquery". Click install button within JQuery entry:

Image 3

After the installation, you can see that "Scripts" folder was created under the project and 3 files were added to it: jquery-1.8.1.min.js (optimized for transfer over the internet), jquery-1.8.1.js - for debugging JQuery on your machine if needed and jquery-1.8.1-vsdoc.js for intellisense.

You can now, mouse drag jquery-1.8.1.min.js to any place within HelloWorld.html file, e.g. to its end. It results in the following line added to your file:

<script src="Scripts/jquery-1.8.1.min.js" type="text/javascript"></script>

JavaScript code can be placed in the HTML file within <script type="text/javascript"> HTML tag or it can be placed in a separate file with extension .js. For this simple example, we'll put the JavaScript code in the HTML file.

Since we want to use JQuery in our JavaScript code, we need to place this code after the JQuery reference.

Our JavaScript code will modify the displayed string to "Hello Wonderful World".

Since JQuery code interacts with the DOM, we need to make sure that the code is called only after the DOM is created. To do this, we place the whole code within the $(document).ready function.

$(document).ready(
    function () {
        // to make sure that the DOM is created
        // all the relevant code should go here.
    }
);

Since we want to refer to some specific HTML DOM node, we want to identify that node in a  way. The best way to do it is by giving it an id: so let us change our HTML line to <h1 id="TheText">Hello World</h1>. JQuery can find the DOM element by id by using '#' selector: $("#TheText");. Finally we can use text function to replace the text within the tag. Here is how the code looks:

<script type="text/javascript">
    $(document).ready( // "ready" function ensures that 
                       // the functionality within executes after the DOM creation
        function () {
            $("#TheText"). // finds the HTML tag with "TheText" id
                text("Hello Wonderful World"); // changes the text within the tag
        }
    );
</script>

Running the application now will result in "Hello Wonderful World" text being displayed.

In the sample above, we have shown how to use JQuery and write a basic JavaScript. Note that just like many other JQuery functions, function text returns the current text within a tag if no argument is passed to it and modifies the text within a tag when an argument is passed to it.

The code for this sample is contained within HelloWorldJS project.

Note on Debugging JavaScript within Visual Studio 2010 or 2012

In my experience Visual Studio 2010 and 2012 debugging works only if you are running your application in Internet Explorer. If your application pops up in a different browser, the VS debugger won't work. The easiest way to convince your Visual Studio to start your HTML/JavaScript application in Internet Explorer is to set Internet Explorer as your default browser. For more complex ways to achieve the same, without changing your PC's default browser, see How to change the default browser in Visual Studio programmatically with PowerShell and possibly poke yourself in the eye by Scott Hansleman.

The JavaScript debugger works very much the same as a C# debugger: you can add a breakpoint; once the program stops on breakpoint, you can check the variables, the call stack etc.

Samples Highlighting JavaScript Features

While this article is not intended to be a JavaScript reference, I would like to present several samples highlighting different JavaScript features. To display the results of these samples, you can simply put them within $(document).ready() function of the HelloWorldJS project discussed above and plug the result into text() function instead of "Hello Wonderful World" string.

Local Variables and Scope

A JavaScript variable can be declared within a function or outside of it in the global scope. The most common way to declare a variable is to use the keyword var, e.g. var i = 10;. Note that curly bracket do not change the variable scope in JavaScript:
var i = 52;
and
{
   var i = 52;
}
are two exactly equivalent ways to define variable i and set it to 52. The following JavaScript will work and will still display 52 on the screen:
$(document).ready(
    function () {

        {
            var i = 52;
        }

        $("#TheText").text(i);
    }
);

Functions and Arguments

Functions can be named or anonymous. A Named function can be called by name. Anonymous functions can be called right after their construction, or by using a reference to them just like anonymous functions and lambda expressions in C#. Functions can return one value by using return keyword, just like the functions in C#, Java and C++.

Here is an example of defining and calling a named function called "MyFunction":

// defining a function
function MyFunction()
{
   return 20;
}

// calling a function
var i = MyFunction(); // i is set to 20
Note that even if the function does not return any values, one can still write var i = MyNonReturningFunction(). In that case, variable i will be set to "undefined".

Here is an example of creating an anonymous function and calling it at once:

function() {
   var i = 20;
}();
Parenthesis after the function definition will ensure that it is called right away.

Here is an example of storing a reference to an anonymous function at the time of its creation and calling it later:

var f =  function() { // we create an anonymous function and store a reference to it
   return 25;
};

...
var i = f(); // we call the anonymous function via a reference

Functions can have arguments defined, e.g. function MyFunction(a, b, c), but the number of arguments passed does not have to match the number of arguments within the function definition, e.g. MyFunction defined above can be called without arguments: MyFunction(). In that case, the arguments that are not passed will be assumed in "undefined" state within the function. One can also pass more arguments to the function than those defined within the function definition. In that case only the first arguments are matched with the defined arguments within a function. Another way to access all the arguments within a function is by using the arguments variable e.g.

function MyFunction()
{
   var result = "";
   for(var i = 0; i < arguments.length; i++)
   {
       result += arguments[i];
   }

   return result;
}

var concatenatedString = MyFunction("Hi ", "World");

The function above will concatenate all the arguments string passed to it, so that the result will be "Hi World".

Since the argument list is flexible, there is no function overloading in JavaScript, and the function should have a unique name within its scope, otherwise the later definition of a function will override the previous one of the same name.

Child Functions, Function Scope, Closures, Global Variables

As we saw above, we can define a function within a different function. e.g.
function MyFunction()
{

    var MyChildFunction() // define MyChildFunction
    {
       ...
    };

    ...
    MyChildFunction(); // call MyChildFunction
}
A function defined within a function is called a child function.

The functions define a scope, in a sense that if you define a variable using var within a function, it will only be visible within the function itself or within descendants of this function and won't be visible outside of it:

function() {
   var i = 20;

   var f = function() {
      // variable i is visible
   }
}

// variable i is not visible

Just like lambdas in C#, the functions have closures, i.e. the function records reference to variables from the higher scope, not the values:

function () {
    var i = 10;
    var square = function () {
        i = i * i;
    }

    i = 40;

    var result = square(); // result is 1600, not 100 as one might assume
}

A function can define a global variable (analogous to a static variable in C# sense). In order to create such a variable one should assign the variable a name without a var keyword in front of it. In that case, it is assigned to the global windows object representing the browser window and is accessible from any other function:

 function () {
     globalVariable = 10; // no 'var' in front the variable definition
 }

// globalVariable is visible outside of the function scope

Objects and Arrays

There are 3 types of variables in JavaScript:
  • Built in value types - numbers, strings, booleans etc.
  • Objects - reference types that have a bunch of fields
  • Arrays - collections of objects or built in types accessible by index.

Let us further discuss the Object type. Essentially, it is a Dictionary/Map/Bag of name-value pairs accessible by name. Unlike in C# or other strongly typed languages, there are no classes that predefine what an object contains; instead the fields within an object are added dynamically during the program run. One can add a field to an object simply by assigning to it:

var myObject = new Object(); // creates a new object
myObject.someField = 5; // assigns number 5 to 'someField' field within the object.

The fields within an object can also be set or accessed by name: myObject.someField = 5; is equivalent to myObject["someField"] = 5;. Also, one can write var myField = myObject["someField"]; to retrieve a field from an object.

The object's fields can be built-in types, other objects, arrays or references to functions.

Now, let us briefly discuss the Arrays. Below is an example of Array creation and manipulation:

var myArray = new Array();

myArray[0] = 1; // array resizes as it is assigned
myArray[10] = "hello world"; // array resizes as it is assigned
                             // (now myArray.length is 11) and the
                             // array cells with indices 1 to 9 are not defined.

myArray.push(2); // adds number 2 to the end of the array, array length is now 12

var myVar = myArray.pop(); // removes and returns the last array value (number 2)
                           // myArray.length now is 11
                           // myVar gets value 2

JSON Object Notations

JSON is a compact way of storing and transferring data. It is considerably more compact than XML. JavaScript objects and arrays can be created via JSON notations. Here is an example:
var student =
  {
    firstName:"Joe",
    lastName:"Doe",
    age: 20,
    friends : [
      {firstName:"John", lastName:"Smith"},
      {firstName:"Dan", lastName:"Brown"}
    ]
  };
The code above creates an object student with firstName field set to "Joe", lastName "Doe", age 20 and an array of friends.

Curly brackets in JSON delineate object boundaries while square brackets - array boundaries. Multiple fields within an object or cells within an array are separated by commas. Colon is used to separate the name from the value for the Object's name value pairs.

JSON notation also provide a more concise way of initializing empty objects and arrays:

var myObj = {};
var myArray = [];

Mapping Object Oriented Concepts into JavaScript

Here we show how to translate OO concepts such as classes, interfaces, virtual functions and inheritance into JavaScript language.

Classes and Constructors 

Classes in C# and other object-oriented languages specify objects of the same "shape", e.i. having similar members but possibly different data. In JavaScript we can write a function for creating an object, populating it with some values, and then returning it to the caller. This function will play a role of a C# constructor by churning out objects of similar structure. Here is an example:
function createStudent(firstName, lastName)
{
   // create an object
   var student = new Object();

   // populate the fields
   student.firstName = firstName;
   student.lastName = lastName;

   // populate the function(s)
   student.getFullName = function()
   {
      return firstName + " " + lastName;
   }

   return student;
}
Now we can call this function to create students:
var student1 = createStudent("Joe", "Doe");

var student1FullName = student1.getFullName(); // returns "Joe Doe"

var student2 = createStudent("John", "Smith");

var student2FullName = student2.getFullName(); // returns "John Smith"

The objects student1 and student2 will have the same structure but different data, as if they are created by new'ing the same class in C#.

There is even a better way to create objects of the same type, which we describe below. Every function has a "this" object that specifies the function's context. One can assign to it any fields and any values. When a function is called prepended by the operator new: new <FunctionName>(...) the "this" object is 'newed' in the beginning of the function and returned by the function to the caller. Such functions are called JavaScript constructors, similar to constructors in C++, Java and C#. So let us rewrite the function above using "this" object (note that I changed the function name to Student):

function Student(firstName, lastName, age) {
  // populate the fields
  this.firstName = firstName;
  this.lastName = lastName;

  // populate the function(s)
  this.getFullName = function () {
      return this.firstName + " " + this.lastName;
  }
}
Here is how we can call such a function with operator new:
var student1 = new Student("Joe", "Doe"); // note that the syntax is the same as in OO languages

var student1FullName = student1.getFullName(); // returns "Joe Doe"

Note that now we can check if the student object was created by Student constructor by using instanceof operator:

var student1 = new Student("Joe", "Doe");

var isStudent = student1 instanceof Student; // isStudent is set to true

The constructor functions can be applied to already existing objects by using the <FunctionName>.call() method, but then instanceof operator will now show that the object came from the constructor:

var student1 = new Object(); // create a student as an object, not by calling <code>Student</code> constructor

Student.call(student1, "Joe", "Doe"); // "this" object of Student function
                                      // is set by the first parameter to "call" function
                                      // (student1 in our case). Then Student function
                                      // populates the student1 object with the fields

var student1FullName = student1.getFullName(); // student1FullName is set to "Joe Doe"

var isStudent = student1 instanceof Student; // isStudent is set to false, since
                                             // student was not created by using operator "new"

More about JavaScript Constructors and "this" Variable

As we mentioned above, every function contains this variable. It provides a context in which the function is called. The function called outside of an object would have this variable set to the browser window object:
AFunction(); // "this" variable within AFunction is set to global "window" object

If a function is called within object's context this variable within the function will be set to the object in which it is called:

var anObj = {
    aVar: 1,

    aFunction: function () {
        var canAccessObjectContext = this.aVar === 1; // checks if we can access aVar from anObj
    }
};

anObj.aFunction(); // function is accessed from within anObj context, "this" variable set to anObj
                  //and canAccessObjectContext within the function is set to "true"

Unlike in C#, Java and C++, this variable within a JavaScript function can be changed by one of the following means:

  • The function can be called using call() or apply methods. In that case, this variable within the function is set to the first argument passed:
    var anObj = {
        aVar: 1,
    
        aFunction: function () {
            var canAccessObjectContext = this.aVar === 1; // checks if we can access aVar from anObj
        }
    };
    
    var anotherObj = {};
    
    anObj.aFunction.call(anotherObj, arg1, arg2); //"this" variable set to anotherObj
                                                  //and canAccessObjectContext within the function is set to "false"
    
  • One can clone the function and provide a different context to it using bind() method:
    var anObj = {
        aVar: 1,
    
        aFunction: function () {
            var canAccessObjectContext = this.aVar === 1; // checks if we can access aVar from anObj
        }
    };
    
    var anotherObj = {};
    
    var clonedFunction = anObj.aFunction.bind(anotherObj); //"this" variable set to anotherObj for the cloned function
    
    clonedFunction(); //canAccessObjectContext within the clonedFunction is set to "false"
    
    Unfortunately IE8 does not support bind().
  • Operator new used to call the constructors, changes the context of the function to a new empty object.

A reasonable question arises of what is going to happen if someone forgets to put new in front of a constructor. The answer is that some context represented by this can become corrupted because of the assignments within the constructor.

This case (of a developer forgetting to put new in front of a constructor) is considered in detail in JavaScript: Using a constructor without new. It turns out that the condition can be detected by adding the following check in the beginning of the constructor:

function Student(firstName, lastName, age) {
  if (!(this instanceof Student)) // check if the call to the
                                  // constructor does not have "new"
                                  // in front of it.
  {
      alert("Programming Error: You forgot to put 'new' in front of the constructor");
      return; // if the call of the constructor does not have "new"
              // in front of it, return undefined value
  }

  // populate the fields
  this.firstName = firstName;
  this.lastName = lastName;

  // populate the function(s)
  this.getFullName = function () {
      return this.firstName + " " + this.lastName;
  }
}

I prefer to alert the software developers or QA if something is wrong in the program. The solution in JavaScript: Using a constructor without new, however, shows how to create a correct object even if the constructor is called without new.

Prototype Chain of Responsibility and Inheritance 

Every object in JavaScript has a hidden field called "prototype". When you try to access a field or a function and it cannot be found on the main object, it checks its prototype field for that field or function. If it cannot find a field or method on the prototype, it will check the prototype of the prototype and so on, until it hits an object without any prototype. This pattern is called "chain of responsibility".

Prototype field can be used in order to have only one instance of some functions or fields for multiple objects (these objects will have to share the prototype). Prototype can also be used to implement functionality similar to inheritance.

The field "prototype" is hidden from the developers and can only be set via JavaScript constructors. Here is an example of how to move the getFullName() function to the prototype and make is shared among all the object created by Student constructor

function Student(firstName, lastName) {
  // populate the fields
  this.firstName = firstName;
  this.lastName = lastName;
}

// setting the prototype for the constructor
// will set the prototype to all the created object
// to refer to function getFullName of the shared prototype
Student.prototype.getFullName = function() {
      return this.firstName + " " + this.lastName;
}

var student1 = new Student("Joe", "Doe"); // calling a constructor

var student1FullName = student1.getFullName(); // student1FullName is set to "Joe Doe"

Instead of defining some function on the prototype, we can set the prototype to be a whole new object obtained with new operator. This will imitate inheritance:

// 'base class' is Student
function Student(firstName, lastName) {
  // populate the fields
  this.firstName = firstName;
  this.lastName = lastName;

  // 'base class' defines a function accessible from
  // the 'derived class'
  this.getFullName = function () {
    return this.firstName + " " + this.lastName;
  }
}

// 'derived class' is HonorStudent
function HonorStudent(firstName, lastName){
  // we have to redefine the fields
  // - since the prototype object is shared
  // it won't be able to have correct data for all
  // the "child" objects
  this.firstName = firstName;
  this.lastName = lastName;
}

// assign HonorStudent's prototype to be Student object
HonorStudent.prototype = new Student();

var student1 = new HonorStudent("Joe", "Doe"); // calling a constructor

var student1FullName = student1.getFullName(); // student1FullName is set to "Joe Doe"

BTW, the fact that the full name of the student is returned as "Joe Doe", also means that the JavaScript functions are "virtual" in a sense that they work with the "derived class" object's fields and not with the "base class" ones. Indeed the prototype object's firstName and lastName fields are not defined (since the prototype object is shared between different objects, there is no way to define them to satisfy all possible combinations). However, the function getFullName defined in the "base class" is returning a correct result working with the objects of the "derived class".

To completely convince you that the functions are "virtual" in the C# sense, let us introduce two more functions in the "base class", one calling another, override the called function in the "derived class" and make sure that the caller called on the "derived class" returns the correct value:

// 'base class' is Student
function Student(firstName, lastName) {
  // populate the fields
  this.firstName = firstName;
  this.lastName = lastName;

  // 'base class' defines a function accessible from
  // the 'derived class'
  this.getFullName = function () {
    return this.firstName + " " + this.lastName;
  }

  // getLongDescription function calls getShortDescription function
  this.getLongDescription = function() {
     return "this is " + this.ShortDescription();
  }

  this.getShortDescription = function() {
     return "a Student";
  }
}

// 'derived class' is HonorStudent
function HonorStudent(firstName, lastName){
  this.firstName = firstName;
  this.lastName = lastName;

  // redefine the function in the "derived class"
  this.ShortDescription = function() {
     return "an Honor Student";
  }
}

// assign HonorStudent's prototype to be Student
HonorStudent.prototype = new Student();

var student = new HonorStudent("Joe", "Doe"); // calling a constructor

var studentLongDescription = student.getLongDescription(); // studentLongDescription is set to
                                                           // "this is an Honor Student"

The instanceof operator propagates up the prototype property, i.e. if the current object has not been created by a constructor specified on the right of instanceof operator, it will check its prototype and the prototype of the prototype and so on, untill it finds a prototype created by the constructor, or comes to the end of the chain. So in the above example we have both student instanceof HonorStudent and student instanceof Student returning true.

Calling call() function on the constructor does not set the prototype and does not make the object to be an instanceof the constructor, i.e. if in the code above we called

var student = new Object();
HonorStudent.call(student, "Joe", "Doe");
The student would have been set to have first an last name but would not be instanceof HonorStudent or Student constructors and also would not have functions getFullName or getLongDescription that are coming from the prototype.

Extending an Array to Have Methods Similar to C#

Prototype can also be used to extend objects without modifying their constructors. All you need to do is to add the functions you want to the prototype of the constructor of the objects and these functions will appear within those objects. Built in types also can be extended this way. For example, I miss collection related methods, like clear(), remove() etc. that come with C# or Java collections, so I created a JavaScript file ArrayExtensions.js and added those functions to the Array functionality:
// remove an element from an array
Array.prototype.remove = function (arrayElement) {
    var currentIndex = 0;
    do {
        if (this[currentIndex] === arrayElement) {
            this.splice(currentIndex, 1);
        }
        else {
            currentIndex++;
        }
    } while (currentIndex < this.length);
};

// insert an element at specified index
Array.prototype.insert = function (idxToInsertAfter, arrayElement) {
    this.splice(idxToInsertAfter, 0, arrayElement);
};

// return index of the first occurance of an element
Array.prototype.firstIndexOf = function (arrayElement) {
    var currentIndex = 0;
    do {
        if (this[currentIndex] === arrayElement) {
            return currentIndex;
        }

        currentIndex++;
    } while (currentIndex < this.length);
}

// return index of the last occurance of an element
Array.prototype.lastIndexOf = function (arrayElement) {
    var currentIndex = this.length - 1;
    do {
        if (this[currentIndex] === arrayElement) {
            return currentIndex;
        }

        currentIndex--;
    } while (currentIndex >= 0);
}

// clear all elements from an array
Array.prototype.clear = function () {
    this.length = 0;
}

// copies a subset of an array to a new array
Array.prototype.copy = function (beginIdx, numberElements) {
    if (!beginIdx) {
        beginIdx = 0;
    }
        
    var endIdx;

    if (!numberElements) {
        endIdx = this.length;
    }
    else
    {
        endIdx = beginIdx + numberElements;

        if (endIdx > this.length)
        {
            endIdx = this.length;
        }
    }

    var copiedArray = new Array();

    for(var i = beginIdx; i < endIdx; i++)
    {
        copiedArray.push(this[i]);
    }

    return copiedArray;
};

ArrayExtensions.js file can be found under the Scripts folder within SimpleEventsJS project.

Interfaces

There are no interfaces in JavaScript and they are not needed. Think about it, the interfaces do not provide new functionality; they restrict the functionality by forcing the developers to program to them and by adding compile time compatibility checking. In JavaScript one can pass any arguments to any functions - there are no compile time compatibility tests, so the interfaces are not needed.

Mapping C# LINQ Functionality into JavaScript

There is a JavaScript library Underscore.js that provides functionality similar to LINQ. You can download the library from Underscore.js or install it using NuGet. The web site also contains excellent documentation.

The Underscore functionality sample is located under UnderscoreTests project. You have to run it in the debugger in order to check the states of the variables, since the project does not change any visual information. Here is the JavaScript code:

// student constructor sets firstName and lastName fields
// and getFullName function
function Student(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;

    this.getFullName = function () {
        return firstName + lastName;
    };
}

$(document).ready(function () {

    // we create a collection of student objects
    var collectionOfStudents =
    [
        new Student("Joe", "Doe"),
        new Student("Jim", "Smith"),
        new Student("Jane", "Smith"),
    ];

    // get all the students with last name "Smith"
    var studentsWithLastNameSmith =
        _(collectionOfStudents).filter(function (student) { return student.lastName === "Smith"; });

    // use chain() function to chain different operations (in our case it is filter() followed by map();
    // map will convert the Student objects returned by the filter() operation into strings containing
    // their last names
    // value() function will unwrap the object and return the array of last names of the 
    // selected students.
    var fullNamesOfStudentsWithLastNameSmith = _.chain(collectionOfStudents)
        .filter(function (student) { return student.lastName === "Smith"; })
        .map(function (student) { return student.getFullName(); })
        .value();
});

You can see that the filter(...) function is very similar to the Where(...) function in C#, while the  map(...) function is the same as Select(...).

The chain(...) function allows to chain the Underscore.js operators one after the other the way it is usually done in LINQ.

For more details about Underscore.js functionality, please look at the online documentation.

Mapping C# and WPF Event Functionality into JavaScript

There are two types of events in WPF/Silverlight/C# - simple events and routed events. Routed events can propagate up and down the visual tree and can be mimicked by document events in JavaScript. There is no built-in JavaScript feature corresponding to simple C# Events, but such a feature can be added very easily. We name such events - Simple Events in order to distinguish them from the document events built into JavaScript.

Simple Events

The SimpleEventsJS project contains a Simple Event sample. The script SimpleEvent.js adds Simple Event functionality to JavaScript. It is located under Scripts folder within SimpleEventsJS project. Here is how HelloWorld.html uses the functionality from that script:

$(document).ready( // "ready" function ensures that 
                   // the functionality within is executed after the DOM is created
    function () {
        var mySimpleEvent = new SimpleEvent();

        // add an event handler to change the header text
        mySimpleEvent.addSimpleEventHandler(function () {
            $("#TheText").text("Yes, the first event handler is fired indeed!");
        });

        // add an event handler to add some text after the header
        mySimpleEvent.addSimpleEventHandler(function () {
            $("body").
               append("<div>Yes, the second event handler also fired!</div>");
        });

        $("#TheText"). // finds the HTML tag with "TheText" id
            text("Hello Wonderful World"); // changes the text within the tag

        // fire the simple event
        // (if you comment out this line the text within the browser stays
        //  "Hello Wonderful World", while if the event fires, the text will change).
        mySimpleEvent.fire();
    }
);

Note that if you comment out mySimpleEvent.fire() line, you will get the same message "Hello Wonderful World" displayed as in the previous HelloWorldJS sample. If, however, you let the mySimpleEvent fire, the messages will be replaced by the event handlers, and this is what you are going to see:

Image 4

Here is the code for the SimpleEvent functionality:

function SimpleEvent() {
    this.eventHandlers = new Array();
};

SimpleEvent.prototype = {
    addSimpleEventHandler: function (eventHandler) {
        this.eventHandlers.push(eventHandler);
    },

    removeSimpleEventHandler: function (eventHandler) {
        this.eventhandlers.remove(eventHandler);
    },

    clearSimpleEventHandlers: function () {
        this.eventHandlers.clear();
    },

    setSimpleEventHandler: function (eventHandler) {
        this.clearEventHandlers();
        this.eventHandlers.addEventHandler(eventHandler);
    },

    fire: function (context, anyOtherArguments) {
        var result;

        var context;

        if (arguments.length > 0) {
            context = arguments[0];
        }

        var argsToPassToEvents = Array.prototype.copy.call(arguments, 1);

        for (var i = 0; i < this.eventHandlers.length; i++) {
            // apply function will execute the event handler, passing to 
            // it the context and an the arguments
            result = this.eventHandlers[i].apply(context, argsToPassToEvents);
        }

        return result;
    }
};

Of course, unlike in C#, there is no way to ensure that one of the developers does not access eventHandlers array and erases all of the event handlers from it.

DOM Events

DOM events just like WPF's routed events can propagate up the DOM tree (bubble). There is no concept of tunneling events in JavaScript, but the tunneling-like functionality can be added if required.

Built-In Event Sample

A simple DOM event sample is located under the BuiltInDomEvents project. Here is the relevant HTML part of the code
HTML
<body>
    <h1 id="TheText">Hello World/<h1>
    
    <!-- we add a 'div' to demonstrate how the built-in click event works -->
    <div id="clickmeDiv" 
         style="width:200px; height:200px; background:red; float:left; font-size:60px">
        Click Me
    </div>
</body>

As you can see, we've added a <div> element called "clickmeDiv" 200x200 px and colored it red.

Here is the JavaScript code that uses a JQuery's bind() function to attach an action to the built-in JavaScript click event at the level of the <div> tag itself and also at the higher level of the <body> tag:

$(document).ready(// "ready" function ensures that 
    // the function passed to it is executed after the DOM is created
    function () {
        $("body").bind("click", function () {
            alert("Clicked within body");
        });

        $("#clickmeDiv").bind("click", function (event) {
            alert("Clicked within 'clickmeDiv'");

            // to prevent the event from bubbling, 
            // uncomment "return false" line below
            // return false;
        });
    }
);

Why use JQuery's bind() function to set handlers to the events, and not the native browser JavaScript functionality? Because the native browser JavaScript functionality for handling the events is slightly different on different browsers while JQuery conveniently provides a common multi-platform way of doing it.

Now, if you run the sample, and click on the red square, you will see two alerts popping up - one at the <div> level and the other one at the <body> level and that means the event bubbles up the DOM. If the <div> level event returns false, however, the event will be prevented from further bubbling and you will only see one alert.

JQuery's bind() functionality can also disable default action on a DOM element as the event fires. Default action is an HTML action performed when someone e.g. clicks on an element. For example, for a hyperlink that would be changing the HTML page to the link's target. An event handler can prevent it by returning false or by calling the event.preventDefault() function.

Custom DOM Events

Newer browsers (but unfortunately not IE 8) also support creating custom DOM events using document.createEvent(...) function. WPF and Silverlight software developer can consider custom DOM events to be analogous to custom routed events.

A sample demonstrating custom DOM events is located under the CustomDOMEvents project. Its HTML part is almost the same as the one of the previous sample. Here is the JavaScript code for the sample:

$(document).ready(// "ready" function ensures that 
// the function passed to it is executed after the DOM is created
    function () {

        if (!document.createEvent) {
            alert("this browser does not support custom event functionality. Please use a different browser");
            return;
        }

        // create a custom event
        var myCustomEvent = document.createEvent("Event");

        // initialize the custom event
        // 1st argument is the custom event name.
        // 2nd argument means that the event bubbles up the
        // DOM. 
        // 3rd argument means that the default action of the
        // event can be cancelled.
        myCustomEvent.initEvent("MyCustomEvent", true, true);

        // set the event handler for the custom event
        // at the body level
        $("body").bind("MyCustomEvent", function () {
            alert("Custom event is handled at the body level");
        });

        // set the event handler for the custom event
        // at the div level
        $("#TheDiv").bind("MyCustomEvent", function () {
            alert("Custom event is handled at the TheDiv level'");

            // to prevent the event from bubbling, 
            // uncomment "return false" line below
            // return false;
        });

        // Fire the custom event from the div element.
        // dispatchEvent should be called on
        // the DOM element itself, not on its JQuery wrapper.
        // We use $("#clickmeDiv")[0] to
        // extract a DOM element from the wrapper
        $("#TheDiv")[0].dispatchEvent(myCustomEvent);
    }
);

Running it with a browser that supports custom events, results in two alert messages stating that the event is handled at the corresponding DOM level.

JQuery

I'd like to end this part of the guide with a brief overview of basic JQuery. JQuery is a cross-browser library for parsing the DOM and manipulating the DOM elements. For WPF and Silverlight developers, there is some similarity between JQuery and LINQ to Visual Tree library by Colin Eberhardt.

For a detailed documentation on JQuery please look at JQuery.com and api.jquery.com. There are also a number of JQuery courses on pluralsight.com, which I highly recommend.

JQuery Selectors and DOM Manipulations 

JQuery has a number of string patterns allowing to select some elements from within the DOM. These string patterns are called Selectors.

The function for selecting a bunch of DOM elements looks like this: $(selector), where "selector" is some string. This function always returns an array of DOM elements, even if you know for sure that only one element is returned, so in order to access an individual DOM element within the array you have to use an indexer, e.g. $("#theDiv")[0].

All of the selectors are listed at JQuery Selectors link. Here we consider only the most important ones.

JQuery sample is located under JQueryTests project. Here is the how DOM of the application looks:

<body>
    <h1 id="header"></h1>
    <div class="MyClass" style="width:700px; height:100px;font-size:40px;background-color:Yellow">
    </div>

    <div class="MyClass" style="width:700px; height:100px;font-size:40px;background-color:Aqua">
    </div>
    
    <div>
        <button style="width:250px;height:50px;"></button>
    </div>

    <div data-test="Test" style="width:800px; height:100px;font-size:30px;background-color:Gray">
        
    </div>

    <div id="ReplaceChildTest" style="width:200px; height:200px;font-size:30px;background-color:Green">
        <div id="ChildDiv" style="width:100px; height:100px;font-size:30px;background-color:Blue">
        </div>
    </div>
</body>
Here is the JavaScript:
$(document).ready(function () {
    // gets all the items with id="header" 
    // (since id is unique there can be only one item line that)
    // adds "Test ID Selector ..." text to the found dom element
    $("#header").text("Test ID Selector $(\"#header\")");

    // gets all elements of class .MyClass and sets
    // their text to "Test class selector ..." + index,
    // where index is the index of the element within the returned
    // array
    $(".MyClass").text(function (index, txt) {
        return "Test class selector $(\".MyClass\")   " + index;
    });

    // gets all "button" tags from the DOM 
    // and sets their text to "Test tag selector ..."
    $("button").text("Test tag selector $(\"button\")   ");

    // selects all the tags whose data-test attribute is set to 'Test'
    // and replaces text on them.
    $("div[data-test='Test']").text("Test attribute selector $(\"div[data-test='Test']\")");

    // remove the blue child div
    $("#ChildDiv").remove();

    // add red child div to ReplaceChildTest div.
    $("#ReplaceChildTest").append( "<div style='width:100px; height:100px;font-size:30px;background-color:Red'>");
});
As you can see in the JavaScript comments, we give usages examples of the following selectors:
  • $("#header") - selects all DOM elements whose id equals to "header" (there can only be one such element)
  • $(".MyClass") - selects all DOM elements whose class is "MyClass"
  • $("button") - selects all DOM elements whose tag is "button"
  • $("div[data-test='Test'") - selects all DOM elements whose "data-test" attribute is set to "Test"

We also see that using the text(...) function you can change text under every element returned by JQuery.

Additionally you can use a different version of the text(...) function to utilize the indices of DOM elements within the array passed to this function by JQuery:

$(".MyClass").text(function (index, txt) {
    return "Test class selector $(\".MyClass\")   " + index;
});

Using these indices, we can e.g. change the text to end with the index, (as we did in the sample) or we can have some index dependent processing e.g. styling the entry differently depending on whether the index is odd or even (though JQuery provides a better functionality to achieve that).

Lastly, we also showed how to remove or add an element to the DOM:

// remove the blue child div
$("#ChildDiv").remove();

// add red child div to ReplaceChildTest div.
$("#ReplaceChildTest").append( "<div style='width:100px; height:100px;font-size:30px;background-color:Red'>");

Summary

In this article, I discussed JavaScript and some of the design patterns that people with a WPF/Silverlight/C# background would find familiar. Here are some of the most important points:
  • Prototyping is related to inheritance
  • Simple C# events can be easily added to JavaScript functionality as was shown above
  • Underscore.js library provides LINQ functionality.
  • DOM maps to Visual tree
  • JQuery loosely maps into LINQ to Visual Tree functionality
  • DOM events map to routed events
In this part, I was concentrating primarily on the non-visual aspects of JavaScript. In subsequent parts, I plan to further discuss the visuals - SVG, JQueryui library, using MVVM with knockout.js library, HTML5 Canvas, building lookless custom controls etc.

History

Sept 11, 2012 - based on Colin Eberhardt's comment added information on the preferred way to initialize objects and arrays. Also added more information about this variable and on what happens if a there is no new operator in front of a call to a constructor.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect AWebPros
United States United States
I am a software architect and a developer with great passion for new engineering solutions and finding and applying design patterns.

I am passionate about learning new ways of building software and sharing my knowledge with others.

I worked with many various languages including C#, Java and C++.

I fell in love with WPF (and later Silverlight) at first sight. After Microsoft killed Silverlight, I was distraught until I found Avalonia - a great multiplatform package for building UI on Windows, Linux, Mac as well as within browsers (using WASM) and for mobile platforms.

I have my Ph.D. from RPI.

here is my linkedin profile

Comments and Discussions

 
GeneralRe: My vote of 5 Pin
Nick Polyak20-Sep-12 22:13
mvaNick Polyak20-Sep-12 22:13 
General5 from me Pin
James McConville19-Sep-12 9:47
James McConville19-Sep-12 9:47 
GeneralRe: 5 from me Pin
Nick Polyak19-Sep-12 11:01
mvaNick Polyak19-Sep-12 11:01 
GeneralMy vote of 5 Pin
Paolo Foti13-Sep-12 23:44
Paolo Foti13-Sep-12 23:44 
GeneralRe: My vote of 5 Pin
Nick Polyak14-Sep-12 9:05
mvaNick Polyak14-Sep-12 9:05 
GeneralRe: My vote of 5 Pin
paulmorgan17-Sep-12 6:56
paulmorgan17-Sep-12 6:56 
GeneralRe: My vote of 5 Pin
Nick Polyak18-Sep-12 22:18
mvaNick Polyak18-Sep-12 22:18 
GeneralMy vote of 5 Pin
Kanasz Robert12-Sep-12 3:19
professionalKanasz Robert12-Sep-12 3:19 
Good job. This could be very helpful for everyone beginner. You've got my 5
GeneralRe: My vote of 5 Pin
Nick Polyak12-Sep-12 8:16
mvaNick Polyak12-Sep-12 8:16 
GeneralMy vote of 5 Pin
Yvan Rodrigues11-Sep-12 9:25
professionalYvan Rodrigues11-Sep-12 9:25 
GeneralRe: My vote of 5 Pin
Nick Polyak11-Sep-12 9:36
mvaNick Polyak11-Sep-12 9:36 
GeneralMy vote of 5 Pin
David197611-Sep-12 3:48
David197611-Sep-12 3:48 
GeneralRe: My vote of 5 Pin
Nick Polyak11-Sep-12 9:18
mvaNick Polyak11-Sep-12 9:18 
QuestionA pretty good article ... but ... PinPopular
Colin Eberhardt10-Sep-12 23:41
Colin Eberhardt10-Sep-12 23:41 
AnswerRe: A pretty good article ... but ... Pin
wknopf11-Sep-12 8:34
wknopf11-Sep-12 8:34 
GeneralRe: A pretty good article ... but ... Pin
Nick Polyak11-Sep-12 9:38
mvaNick Polyak11-Sep-12 9:38 
AnswerRe: A pretty good article ... but ... Pin
Nick Polyak11-Sep-12 9:35
mvaNick Polyak11-Sep-12 9:35 
GeneralRe: A pretty good article ... but ... Pin
Colin Eberhardt11-Sep-12 9:45
Colin Eberhardt11-Sep-12 9:45 
AnswerRe: A pretty good article ... but ... Pin
Nick Polyak8-Dec-12 19:55
mvaNick Polyak8-Dec-12 19:55 
GeneralMy vote of 5 Pin
saxenaabhi610-Sep-12 21:15
saxenaabhi610-Sep-12 21:15 
GeneralRe: My vote of 5 Pin
Nick Polyak11-Sep-12 9:36
mvaNick Polyak11-Sep-12 9:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.