Some JavaScript OOP – Student search Engine.

I was experimenting with object oriented programming in JavaScript yesterday. Imagine the following scenario: you have a list of students. You want to keep their name, age, school year, average mark and part-time employment (if applicable) information.
Additionally, you want to be able to search and sort them by their information.

The best way to do this would be to use objects to store the students’ information. Imagine objects as special variables that can hold other variables (properties) and functions (methods).
We’ll use one object to store the information for one student. In order to be able to store multiple students’ information, we can just use an Array (it’s just a variable that holds many variables.)

Apologies in advance if the spacing is bad – I spent about an hour just modifying the code so that it would fit in the wordpress box. Not my idea of fun! You can just download the script below

Students = new Array(); //initialize the array which will hold ALL the students

// To define a class in JavaScript all we have to do is
//store a function (the constructor) in a variable. (our class name)
//This is the default code that will be called every time we create
//a new object.
//It works exactly like any other function. You can set each object's 
//properties using 'this'.

Student = function (stuName, stuAge, stuYear, stuAverage,
stuEmployment) {
    //all the this.blah lines below just copy the
    //values provided to the function to object properties.
    this.name = stuName;
    this.age = stuAge;
    this.year = stuYear;
    this.average = stuAverage;
    this.employment = stuEmployment;
    this.relevance = -1; //for searching later
  
    Students.push(this); //Add the student object in our
    //array when it's created
}

//Now to create new student objects we can just do this:

new Student ("Errietta Kostala", 18, 1, 100, "Web Developer");
//names are completely random below this line
new Student ("Guy Flores", 19, 1, 73.5, "Web Developer");
new Student ("Vincent Davidson", 20, 2, 89.3, "Retail");
new Student ("Janet Ellis", 18, 1, 69, "None");
new Student ("Robbie Clark", 21, 2, 92, "Funeral house employee");
new Student ("Robert Caruso", 24, 3, 63, "Self-employed");
new Student ("Michael Taylor", 23, 3, 86, "None");

//This has already populated our Students array
//We can access array elements as usual:

var erry = Students[0];
console.log (erry.name, erry.age,
erry.year, erry.average, erry.employment);

//Now, we'd like to be able to sort and search our objects.
//Ideally we want to be able to choose whether to
//sort ascending or descending.
//We'll also be swapping from ascending to
//descending and vice-versa automatically when you sort
//by the same thing twice.
//We'll initialize some values here so that we have them available.

var currentSort = -1; //What we're currently sorting by.
//-1 will mean nothing for us.
//In cases like these, I just initialize my values with a value
//that's impossible (such as a negative number in a
//program that only works with positive integers) or
//I know I won't be using.

var descending = false; //Are we using descending order?

//Now time for the real fun: make the sorting function!
           
function sortBy(num, forceDesc) {
/* we just use `num` here as a convenient
way to say what we want to sort by. 0 will be `name`, etc.
These values are completely arbitrary and could be anything. */

    if (currentSort === num) descending = !descending; 
/* If we're sorting twice with the same value, flip the
`descending` boolean. This will make it from true to false and vice-versa */
    else descending = false;
//default to ascending search otherwise..
    
    if ( forceDesc !== undefined )
//however, if we've defined the forceDesc variable, use that no matter what.
        descending = forceDesc;
    
    switch (num) {
        case 0:
            //Student name
            Students.sort(
                
                function (stud1, stud2) {
//We want to do an alphabetical sort. The Sort function
//takes an optional function argument that lets you define
//the sorting behavior. It should return a negative
//value if the first object is smaller, 0 if they're
//equal, or a positive value if the first object is bigger.
//localeCompare does an alphabetical
//comparison that returns values with the same logic, so we need
//to use that for a working alphabetical sort.
                    
                    return (descending ?
                          stud2.name.localeCompare(stud1.name) : 
                          stud1.name.localeCompare(stud2.name));
                }
            );
            break;

At this time you might be thinking: `wat`?
Allow me to clarify this code.
You can use the sort() function to sort an array. By default,
it does an alphabetical, ascending sort. For example:

var a = new Array (1, 11, 2);
a.sort();

You guessed it, this will leave our array as is.
However you are able to sort numbers,
or pretty much anything.
The sort function takes an optional
function argument that lets you define its behaviour.
The function takes two arguments, a and b.
It should execute an operation such as:
1) If a > b, a positive integer is returned.
2) If a = b, 0 is returned.
3) If a < b, a negative integer is returned. So, if we wanted to sort our numeric array above with a numeric sort, we could simply do this:

a.sort ( function ( a, b ) { return a - b; } );

Since subtraction's return value is exactly in the
format we want it to be!
This would sort our array the way we wanted it: [1, 2, 11]
If you want to sort with the reverse order,
all you have to do is subtract a from b instead:

a.sort ( function ( a, b ) { return b - a; } );

Would return the array sorted in descending order.

Makes sense so far!
But how would you define a custom sorting behaviour for
alphabetical values? For a normal array with alphabetical
elements you might just not care: the default sorting
behaviour is alphabetical ascending, and you can just
reverse() the array if you want a descending sort.
However, we're not sorting Strings or numbers, but objects.
Therefore, we will have to define a custom behaviour.
I wasn't sure of how to do this myself,
since obviously you can't subtract strings.
But freenode's ##javascript provided the answer!

var alphabet = [ "a", "c", "z", "b" ];
alphabet.sort ( function ( a, b ) {
                    return a.localeCompare(b);
              });

And tadah! It works perfectly.
Descending sort?
You probably guessed it:

var alphabet = [ "a", "c", "z", "b" ];
alphabet.sort ( function ( a, b ) {
                    return b.localeCompare(a);
              });

The reason why this works, is because
String1.localeCompare (String2) returns:
1 if String 1 is bigger, 0 if they're equal, -1
if String 1 is smaller.
Yep. Exactly the kind of return value sort() expects!
So now you should be able to understand the
above sorting code, and in fact, the rest of it, without my help.

        case 1:
            //student age
            Students.sort(
                
                function (stud1, stud2) {
                    return (descending ? 
                           stud2.age - stud1.age :
                           stud1.age - stud2.age);
                }
            );
            break;
        case 2:
            //year
            Students.sort(
                
                function (stud1, stud2) {
                    return (descending ? 
                            stud2.year - stud1.year :
                            stud1.year - stud2.year);
                }
             );
            break;
        case 3:
            //average mark
            Students.sort(     
                function (stud1, stud2) {
                    return (descending ?
                    stud2.average - stud1.average :
                    stud1.average - stud2.average);
                }
            );
            break;
        case 4:
            //employment. Back to string comparison!
            Students.sort(    
                function (stud1, stud2) {
                    return (descending ?
                    stud2.employment.localeCompare(stud1.employment) : 
                    stud1.employment.localeCompare(stud2.employment));
                }
            );
            break; 
        case 5:
            //relevance. for searching
            Students.sort(    
                function (stud1, stud2) {
                    return (descending ?
                    stud2.relevance - stud1.relevance : 
                    stud1.relevance - stud2.relevance);
                }
            );
            break;
    }
    
    currentSort = num;
    //finally, we just need to remember what we sorted by,
    //so we do descending sort if we sort by it again.
}

Feel free to play around now by using console.log - see the value of
the Students array before and after calling sortBy, sort by the same
value twice and see how they become descending, change that behaviour by
using sortBy (value, true) or (value, false) etc.

When you're ready to move on comes the next part, searching.
The code basically accepts values (names, average marks) and increases
the 'relevance' value for everything that matches. It's
really straight-forward.

function calculateRelevance ( name, age, year, average, employment ) {
    for (var i = 0; i < Students.length; i++) {
        var relevance = 0;
        var student = Students[i];

        if ( student.name == name ) {
            ++relevance;
        }

        if ( student.age == age ) {
            ++relevance;
        }
        
        if ( student.year == year ) {
            ++relevance;
        }

        if ( student.average == average ) {
            ++relevance;
        }

        if ( student.employment == average ) {
            ++relevance;
        }

        student.relevance = Math.round ( relevance / 4 * 100 );
    }

    sortBy ( 5, true ); //automatically sort by relevance, descending.
}


There's not much to explain there. It calculates how relevant each student is to your search, then sets the object's 'relevance' property. It then sorts by it.

To test it, do something like

calculateRelevance ("Errietta Kostala", 18, 1, 100, "Web Developer")

And take a look at your Students array. You should see that the first object has 100% relevance, then relevance decreases.
Change values, play around, and see the results!

That's it!
Hopefully, you've just seen a bit of OOP in javascript, and created an application that allows
you to sort and search objects by their parameters.

Your homework:
Create an HTML front end for this code.
Modify the search code to only return something if there's 100% match; better yet give the search a parameter to modify this behavior
Add more functionality, do case-insensitive search,
or do whatever you think will improve it 🙂

Promised full code: Download full code

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    This site uses Akismet to reduce spam. Learn how your comment data is processed.