Skip to main content

Copying an Object in JavaScript

The Setup

var default = { param1: "one", param2: "two", param3: [] },
    working = default;

// Fill form fields from working data
// User modifies form fields
// Save form fields in working data
// Perform calculation based on working data
// User clicks a button to reset the form to default state

function reset(){
  working = default;
  // Fill form fields from working data
  // Perform calculation based on working data
}

The Problem

The form was not being reset to the default data, but instead did not change at all.

When I debugged, I noticed that the data in default was identical to the data in working, even though I never assign any values to default after initialization.

The Cause

Little did I know, that assigning an object in JavaScript actually only assigns the reference, and does not create a new copy of the object.

The Solution

The object needs to be copied, rather than simply assigned. Based on a quick Google search, there is no built-in method to do this. But I did find a great post on Stack Overflow explaining the issue and how to copy one object to another.

I ended up using the function provided by A. Levy, which I'll post here for convenience (Though I removed the Date section, since I would not be needing it).

function clone(obj) {
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, var len = obj.length; i < len; ++i) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

I had actually just written a similar function to recursively step through an object and convert it to an array, so I could have written this myself, however the code was right there in the article that explained why I was having this problem, and so much easier to just copy and paste. Plus I didn't know about the hasOwnProperty method, which makes this code better than mine would have been.

Lesson Learned

Unless you want to assign a pointer to an object, you will need to clone, or copy, the object into the new variable.

Use the hasOwnProperty method when looping through the properties of an object to only copy local attributes

Comments

Popular posts from this blog

Be Careful Using SASS @extend, CSS3 Selectors, and IE8

I recently ran into a situation where some of my styles were broken in Internet Explorer 8. What makes this different from all the other times my styles broke in IE8 was that, as far as I could tell, it was correct. Consider the following code: %highlighted { background-color: #ff0; color: #333; } .keyword.is-active { @extend %highlighted; padding: 10px; text-transform: uppercase; } No problem, right? Then why isn't it working? I wasn't sure, until I looked at the compiled CSS and saw something like this: .some-list:nth-child(2n), .is-highlighted, .keyword.is-active { background-color: #ff0; color: #333; } .keyword.is-active { padding: 10px; text-transform: uppercase; } Since IE8 doesn't support the css selector nth-child , it ignores the entire rule . Without looking at the final output, there's no way of knowing if this will happen ahead of time. So what can you do? Well,...

SASS Mixin for Creating CSS Triangles

I feel like one of the most common shapes that we can reliably create with CSS vs images is the triangle. One of the reasons for this is that it works as far back as IE7 (IE6 works, but doesn't support background-color: transparent ). Another is how frequently a little triangle icon can be used (e.g., ascending/descending buttons, expanding menus, open/close state, etc.) I'm not going to cover the techniques of creating triangles with CSS . That's been done already , and probably better than I would do it. What I'm going to share with you, is a little SASS mixin that I've been using to generate triangles. See the Pen SASS Triangles by Thomas Pietrosanti ( @Rykus0 ) on CodePen . I'm using a SASS placeholder ( %triangle-base ) as a base to contain the common styles. This makes it easy to extend without generating tons of extra code each time I want to make a triangle. When this compiles, it creates a rule that applies to all of th...

CSS line-height Units Explained

In Chris Coyier's recent article, " Fun with line-height! ", he mentions that we often use unitless values for line-height so that it's proportional to the font size. This is only part of the story, and I was reminded of a Stack Overflow question that got me investigating more about how line-height worked with regards to the various CSS units. If you're declaring the line-height on each element, you won't notice any difference. But if you're not crazy and using the first C of CSS (that's 'Cascading', by the way), then the inherited line-height might not work the way you expect. Disclaimer: This is my understanding after doing some research and testing. I may not be completely correct. TL;DR When using a relative unit (em, %), the line-height is calculated based on the font size of the element where the line-height is defined. This line-height is then inherited, unchanged, by each of its descendants. So we end up with a line...