Implementing deep comparison in Javascript

I was reading through Eloquent JavaScript and one of the exercises is to write a function deepEqual that takes two values and returns true only if they are the same value or are objects with the same properties, where the values of the properties are equal when compared with a recursive call to deepEqual.

Let’s get started.

Note that both UnderscoreJS and Lodash have a toEqual method that can be used if you’re using one of these libraries.

JavaScript has both strict and type–converting comparisons.

The == operator compares objects by identity. === and !== are strict comparison operators. For strict equality the objects being compared must have the same type and:

  • Two strings are strictly equal when they have the same sequence of characters, same length, and same characters in corresponding positions.
  • Two numbers are strictly equal when they are numerically equal (have the same number value). NaN is not equal to anything, including NaN. Positive and negative zeros are equal to one another.
  • Two Boolean operands are strictly equal if both are true or both are false.
  • Two objects are strictly equal if they refer to the same Object.
  • Null and Undefined types are == (but not ===). [I.e. (Null==Undefined) is true but (Null===Undefined) is false]

Comparison Operators – MDN

Two objects are strictly equal if they refer to the same Object. In other words,  two distinct objects are never equal for either strict or abstract comparisons.

var obj1 = { 'key': 'value'}, ob2 = { 'key': 'value' }
obj1 === obj2 // false

To find out whether values should be compared directly or have their properties compared, we can use the typeof operator. If it produces “object” for both values, we should do a deep comparison. However we have to watch out for one major gotcha in JavaScript, because of a historical accident, ​typeof null also produces “object”.

With that, to test whether you are dealing with a real object will look something like typeof x == "object" && x != null. Let us write a function for that:

function isObject (obj) {
    if (typeof obj != "object" || obj == null) {
        return false
    }

    return true
}

Next test is to see whether both objects have the same properties. To be equal, both objects should have the same set of properties and each of these properties should contain the same value.

We can use Object.keys to go over the properties to test whether both objects have the same set of property names and whether those properties have identical values. One way to do that is to ensure that both objects have the same number of properties (the lengths of the property lists are the same).

if (Object.keys(obj1).length != Object.keys(obj2).length) {
    return false
}

And then, looping over one of the object’s properties to compare them, making sure the other actually has a property by that name. If they have the same number of properties and all properties in one also exist in the other, they have the same set of property names.  We compare the values of each property by letting the function recursively call itself in the for/in loop.

for (let prop in x) {
    if (!deepEqual(x[prop], y[prop])) {
        return false
    }
}

Returning the correct value from the function is best done by immediately returning false when a mismatch is found if not returning true at the end of the function.

Putting everything together, we have:

function deepEqual(x, y) {
    if (x === y) {
        return true
    } else if (isObject(x) && isObject(y)) {
        if (Object.keys(x).length != Object.keys(y).length) {
            return false
        }

        for (let prop in x) {
            if (!deepEqual(x[prop], y[prop])) {
                return false
            }
         }

        return true
    }
}

function isObject (obj) {
    if (typeof obj != "object" || obj == null) {
        return false
    }

    return true 
}

Testing the function:

let obj = {here: {is: "an"}, object: 2}

deepEqual(obj, obj) // true
deepEqual(obj, {here: 1, object: 2}) // false
deepEqual(obj, {here: {is: "an"}, object: 2}) // true

One more improvement we could make is to make the isObject function private.  It not used outside this function and unnecessarily gets added to the global scope.

We can hide a “private” function inside a function of this kind by placing one function declaration inside of another. The inner function is not hoisted out into the global scope, so it is only visible inside of the parent function. With that:

function deepEqual(x, y) {
    if (x === y) {
        return true
    } else if (isObject(x) && isObject(y)) {
        if (Object.keys(x).length != Object.keys(y).length) {
            return false
        }

        for (let prop in x) {
            if (!deepEqual(x[prop], y[prop])) {
                return false
            }
        }

        return true
    }

    function isObject (obj) {
        if (typeof obj != "object" || obj == null) {
            return false
        }

        return true
    }
}

Lastly, this StackOverflow question about determining equality of two JavaScript objects is a really great learning resource, do read.

 

Advertisements

Edit me

Just saw an interesting bit of JavaScript that allows anyone to edit the content of a web page from IE or Firefox.

This is a JavaScript trick that runs on the client side and does not have any effects on the actual file on the server. With this, you can change the text of a web page to your heart’s content.

Once you visit a page you are interested in modifying, enter the following JavaScript in the address or location bar all in one line.

javascript:document.body.contentEditable='true';document.designMode='on'; void 0

This should turn the web page into a editor. Try it out.

Automate and extend Firefox with the Chickenfoot add-on

Tony Patton in his article on Chickenfoot speaks about manipulating the DOM of a webpage through which you can give additional features to a web page.

Chickenfoot is a Firefox add-on that allows you to automate user actions within the browser environment. It also lets you extend the browser interface to provide additional features to a Web page.

Before I delve into how this add-on can make your Web development work easier, I thought I’d take a moment to share the answer to the question I bet you’re asking yourself (I know I was): Why is it called Chickenfoot? Here is the answer from the Chickenfoot site:

“Chickenfoot is a game that you can play with dominoes. Since Chickenfoot does much of its work by manipulating the Document Object Model, or DOM, of a web page, Chickenfoot the Firefox extension is like a toy that lets you play with the DOMinoes of the web.”

Access the full article here

Chickenfoot is available as a free download. When you click the downloaded file, Chickenfoot is installed via the Firefox Add-ons dialog box. After installation, it is available as a sidebar selection (View | Sidebar). After you enable the sidebar, Chickenfoot appears on the left side of the browser adjacent to where pages load.

The top portion of the Chickenfoot sidebar contains a JavaScript editor that allows you to enter JavaScript as you would within a Web page. In addition, you can enter commands from the JavaScript superset that is part of Chickenfoot.

You may enter multiple code windows within the JavaScript editor. There are buttons at the top of the JavaScript editor that you can use to open/save scripts, create new scripts, and execute and stop scripts.

For more information about Chickenfoot scripts, check out the Chickenfoot Script Repository.

Google Doctype

Google Doctype is an open encyclopedia and reference library. Written by web developers, for web developers. It includes articles on web security, JavaScript DOM manipulation, CSS tips and tricks, and more. The reference section includes a growing library of test cases for checking cross-browser and cross-platform compatibility.

Build powerful Web interfaces with a free JavaScript framework

Scriptaculous allows you to easily add powerful AJAX-based user interface features to Web 2.0 applications. Web developer Tony Patton explains why you should use it and describes how to use it.

Scriptaculous is a framework for building dynamic Web 2.0 interfaces. It utilizes another freely available framework called prototype. Scriptaculous simplifies the ins and outs of implementing an AJAX-based Web interface. It allows you to easily add animation and custom data controls, as well as utilities for working with the DOM and JavaScript testing.

Why use it?
AJAX is a great marriage of technologies, but it can be confusing and time-consuming to build AJAX-powered applications from scratch. The scriptaculous framework makes it easy to include AJAX-based features in your applications, plus all of the development and testing has been done, so you can devote your time to more important tasks.

Getting started

The first step in utilizing the scriptaculous framework is downloading and installation. The download is basically a zip file with JavaScript files along with various HTML files for testing and demonstration. The JavaScript source files are the most important. The following list contains an overview:

Keep your developer skills sharp by signing up for TechRepublic’s free Web Development Zone newsletter, delivered each Tuesday.

  • lib\prototype.js: The source for the prototype JavaScript framework.
  • scr\builder.js: Allows you to easily create DOM elements dynamically.
  • src\controls.js; Includes the core components for working with the custom data controls.
  • src\dragdrop.js: Provides the code for utilizing the custom data controls for drag-and-drop related functions.
  • src\effects.js: The Visual Effects library includes all you need to add advanced JavaScript animation to your Web application.
  • src\scriptaculous.js: The base code library for utilizing the scriptaculous framework.
  • src\slider.js: Provides the code for utilizing the slider data control.

The previous list includes the default directory where each file is installed. You can place these JavaScript files anywhere on the Web server, but using the default directories makes it easier to work with the examples.

You may be wondering about the overhead of including these files in a Web page. The complete library (all files in the list) consumes approximately 150KB. The two core files—prototype.js and scriptaculous.js—add up to 50KB. So, all other combinations will be between 50 and 150KB depending on the files used.

By default, scriptaculous.js loads all of the other JavaScript files necessary for effects, drag-and-drop, sliders, and all of the other scriptaculous features. You can limit the additional scripts that get loaded by specifying them in a comma-separated list (via the load command) when loading the scriptaculous JavaScript file.

Once you have downloaded and installed the framework, it is easy to use it within a Web page. The first step is linking to the JavaScript source files within the head portion of the Web page. See Listing A.

The various functions available are accessed via HTML script tags. You can gain a better understanding by examining one of the test files installed with the framework (or an online example). As an example, I loaded the slider_test.html file located in the test\functional directory of a default installation. The complete contents of the file are too much to list here, but I can examine one portion that loads the first slider control on the page—a standard horizontal slider:

<script type="text/javascript">
// <![CDATA[
new Control.Slider('handle1','track1',{
sliderValue:0.5,

onSlide:function(v){$('debug1').innerHTML='slide: '+v},

onChange:function(v){$('debug1').innerHTML='changed! '+v}});

// ]]>

</script>

Using the CDATA section sidesteps issues encountered when using characters like < and > in your JavaScript. The code creates a new Slider control (via the Control class) and sets its initial position to the middle of the control (0.5) and adds handlers for the slide and change events. Also, framework functionality is easily used via onClick events.

A drawback of many freely available (and some commercial) tools is a lack of documentation and examples. The scriptaculous framework includes extensive example code and basic documentation via its Wiki. In addition, a quick Google search yields more help. A good example is the various cheat sheets available that provide a quick reference sheet for using the framework.

The framework includes an extensive set of examples that are included in the functional subdirectory of the test directory. You can dive into the test files to get a good idea of how to use framework functions within your application. In addition, the demos section of the scriptaculous Web site provides great examples.

Comet: Reverse Ajax for streaming data from the server

Daniel Rubio has written an article called “Comet: Reverse Ajax for streaming data from the server,” describing ‘Comet,’ a technology to push events from the server side to a browser client. Comet manages to avoid the issues related to having a browser poll a server to check for new events.

Ajax, or Asynchronous JavaScript and XML, has become a household name in the area of Web applications, this mechanism by which a browser accesses a RESTful Web service and updates its GUI without a screen refresh, has spread from its pioneering roots in on-line maps and calendars to pretty much a standard feature in most new Web applications. However, it was not until recently that a new term was coined to complement this approach, one which is now often dubbed reverse-Ajax, its name: Comet.

The first thing you need to realize is that the data service on the server side needs to be designed to hold state on behalf of browsers clients, a process that can either be very difficult or very easy, depending on the platform and language you are using. Once again, this takes us to the stateless nature of Web applications and the way a browser needs to identify itself constantly either via cookies or session IDs, or what some characterize as the Hollywood principle – “don’t call us we’ll call you” – referring that only a browser is equipped to make calls and never vice-versa.


This last issue takes us down the road of building an asynchronous server application, or if you prefer a fancier name, an HTTP-based event routing bus, or in other words, a latent application on the serverside able to keep track of clients wishing to receive updates, a design very much in line with the messaging systems used in enterprise systems that are based on publish/subscribe channels.


However, since this last mechanism represents a departure from the “bread and butter” approach used in most Web platforms, it is a big reason why most Comet applications today rely on either custom adapted application-servers or embeddable versions that can tackle these issues. In the particular case of Java, Jetty and Grizzly are two servers that currently have out-of-the box support for Comet-type designs, with varying support in other languages like Python and other popular Java servers like Tomcat, for what is technically known as “continuation support,” a paradigm by which applications are shielded from the stateless nature of the Web. Continuation support also is a touted feature of higher-level language Web frameworks written in Smalltalk and Lisp that have this capability.


Turning our attention to the client side of things, a browser can take various routes to stay in contact with these type of server applications. Among these approaches are long-polling, dynamic script tags and inclusively a workaround using IFrames, none are standard approaches by any means, which is yet another reason why many client side Comet designs rely on the use of frameworks to abstract away incompatibilities between browser implementations – similar to Ajax – with one such framework being Dojo, which in itself now serves as both an Ajax/Comet framework.

Of course, the term Comet itself is something to wonder about. AJAX’ meaning is fairly well-known, as “Asynchronous Javascript and XML,” but what about Comet?

As far as the actual term is concerned, Comet emerged as a pun to Ajax’s meaning outside IT circles as a household cleaner. But quirky name or not, Comet is serving the purpose of an umbrella name for delivering data onto browsers as it becomes available on the serverside, a technique that will surely be of the same impact and go hand in hand with what we know today as Ajax.

Google Chart API + some JavaScript = Beautiful Charts

The Google Chart API lets you dynamically generate charts. To see the Chart API in action, open up a browser window and copy the following URL into it:

http://chart.apis.google.com/chart?cht=p3&chd=s:hW&chs=250x100&chl=Hello|World

Press the Enter or Return key and – presto! – you should see the following image:

Yello Line Chart

 

I just happened to notice last week that Google released a nifty Chart API for public use. The Google Chart API returns a PNG-format image in response to a URL. Several types of image can be generated: line, bar, and pie charts for example. For each image type you can specify attributes such as size, colors, and labels.

You can include a Chart API image in a webpage by embedding a URL within an <img> tag. When the webpage is displayed in a browser the Chart API renders the image within the page. (more…)