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

Data binding and flow in VueJS

Two way data binding means that UI fields are bound to model data dynamically such that when a UI field changes, the model data changes with it and vice-versa.

One way data flow means that the model is the single source of truth. Changes in the UI trigger messages that signal user intent to the model (or “store” in React). Only the model has the access to change the app’s state.

The effect is that data always flows in a single direction, which makes it easier to understand.

One way data flows are deterministic, whereas two-way binding can cause side-effects which are harder to follow and understand.

vue logoIn Vue, All props form a one-way-down binding between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around. This prevents child components from accidentally mutating the parent’s state, which can make your app’s data flow harder to understand.

In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value. This means you should not attempt to mutate a prop inside a child component. If you do, Vue will warn you in the console.

However, there could be use cases where it would be necessary to mutate a prop:

  1. The prop is used to pass in an initial value; the child component wants to use it as a local data property afterwards. In this case, it’s best to define a local data property that uses the prop as its initial value:
    props: ['initialCounter'],
    data: function () {
      return {
        counter: this.initialCounter
      }
    }
  2. The prop is passed in as a raw value that needs to be transformed. In this case, it’s best to define a computed property using the prop’s value:
    props: ['size'],
    computed: {
      normalizedSize: function () {
        return this.size.trim().toLowerCase()
      }
    }
    

 

Highly Critical Security Vulnerability Found in Firefox 3.5

Secunia reports of a new, unpatched, and highly critical security hole in Firefox 3.5 (possibly in other versions, too) that allows attackers to execute arbitrary code on the victim’s computer.

The vulnerability is caused due to an error when processing JavaScript code handling; for example, one could use simple HTML “font” tags to cause a memory corruption and then run arbitrary code.

Until Mozilla addresses this vulnerability, here’s a temporary fix: Type about:config in Firefox‘ address bar, and set “javascript.options.jit.content” to “false.”

Read the details about this security issue here.

Highly Critical Security Vulnerability Found in Firefox 3.5

Posted using ShareThis Follow me on twitter

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.

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.