javascript creating a module to extend a nested object

Currently, I am working on a JavaScript module that includes an object of default options. Here is a snippet of the code:

 var myModule = function() {

  // Define option defaults
  var defaults = {
    foo: 'bar',
    fooObject: {
      option1: [],
      option2:true,
      option3: false,
    }
  }

  // Update options by merging defaults with the provided arguments
  if (arguments[0] && typeof arguments[0] === "object") {
    this.options = mergeDefaults(defaults, arguments[0]);
  }
}

When calling my module like this:

var moduleInstance = new myModule({
  foo: 'some value',
  fooObject: {
    option1: [1, 2, 3]        
  }
});

moduleInstance.options.foo; //will return an array [1, 2, 3]

However,

moduleInstance.options.fooObject; //will only contain option1

I understand why that happens since option2 and option3 are not defined initially. I am struggling to find a solution for this without relying on jQuery or other frameworks.

Edit: Potential Solution

I managed to address this issue in the following way: http://jsfiddle.net/optionsit/sgmme5dy/

In the loop where I check for hasOwnProperty...

I added this if statement:

if(typeof properties[property] === 'object'  && typeof  properties[property].nodeType === 'undefined' )

This allows me to differentiate between objects and DOM elements (as some top-level values are DOM elements) and iterate through their children to replace them if they are set in the arguments.

While it may not be the most elegant solution, it serves my needs. Feel free to suggest a better approach. I appreciate your input.

Thank you for your assistance

Answer №1

To achieve the desired result, it is important to implement a recursive call for your extendDefaults method:

function extendDefaults(source, properties) {
    var property;

    for (property in properties) {
        if (properties.hasOwnProperty(property)) {
            if (typeof properties[property] === 'object' && typeof properties[property].nodeType === 'undefined') {
                extendDefaults(source[property], properties[property]);
            } else {
                source[property] = properties[property];        
            }
        }
    }

    return source;
}

You can find an updated fiddle demonstrating this aspect here: http://jsfiddle.net/sgmme5dy/3/

It is crucial to note that this function may encounter issues with null values and Date properties due to their types being classified as objects. To address this concern, simply include the following condition within the if statement:

if (typeof properties[property] === 'object' && properties[property] !== null && !(properties[property] instanceof Date) && typeof properties[property].nodeType === 'undefined')

Additionally, do keep in mind that Arrays are also considered of type object. In light of these complexities, it might be more efficient to utilize existing extend functions available. For instance, jQuery offers $.extend, while lodash/underscorejs provides _.assign. Alternatively, there are standalone libraries such as node-deep-extend for those not utilizing the aforementioned libraries.

Answer №2

It appears that your code is overwriting the entire fooObject, which may not be desired. Depending on what you're trying to achieve, there are various solutions available. One approach could be to implement an additional method for appending new elements to the existing fooObject instead of replacing it entirely within the "constructor" function.

 function extendDefaults(source, properties) {
   var property;
   for (property in properties) {
       if (properties.hasOwnProperty(property)) {
           source[property] = properties[property];
       }
   }
   return source;
 }


var myModule = function () {

   // Setting default options
   var defaults = {
       foo: 'bar',
       fooObject: {
           option1: [],
           option2: true,
           option3: false,
       }
   }

   this.options = extendDefaults({}, defaults);

   // Extending defaults with provided arguments
   if (arguments[0] && typeof arguments[0] === "object") {
       this.options = extendDefaults(this.options, arguments[0]);
   }
}

var moduleInstance = new myModule({
   foo: 'some value',
});

moduleInstance.options.fooObject.option1 = [1, 2, 3];


console.log(moduleInstance.options.fooObject);

console.log(moduleInstance.options.foo);

Link to Example

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue with Jquery Drag and Drop functionality, navigate to a different page

I am trying to incorporate a page with js from quotemedia.com using Jquery. When I insert the js into the sortable, and then drag and drop the element containing the js, it suddenly switches to full page display. This issue occurs in Firefox, but IE works ...

The absence of the function crypto.createPrivateKey is causing issues in a next.js application

For my next.js application, I am utilizing the createPrivateKey function from the crypto module in node.js. However, I encountered an issue as discussed in this thread: TypeError: crypto.createPrivateKey is not a function. It seems that this function was a ...

Managing errors in React Router on the server-side

I am currently working on an isomorphic application using react-router and express. My goal is to implement custom error pages that will be displayed in case of server-side errors, rendering errors, or when a page is not found. However, I am facing difficu ...

Traversing an array of objects in TypeScript and appending to a separate array if not already present

I have been given an array containing objects in the following format: export interface Part { workOrder?: string; task?: string; partNumber?: string; qty?: number; image?: string; name?: string; } My goal is to loop through each object in th ...

Utilizing jquery.validate.min.js for efficient form validation

Here is my JavaScript validate function: $("form[id='form']").validate({ Name: "required", submitHandler: function() { formSubmit(); } }); Not only do I wa ...

How can an additional value be sent to the form validation method?

I have created a form group like this: import { checkPasswordStrength } from './validators'; @Component({ .... export class PasswordComponent { ... this.userFormPassword = this.fb.group({ 'password': ['', [ ...

Struggling with jQuery and the "hash" functionality?

I am encountering issues with jQTouch. The problem arises when I try to use this link: <a href="#site_map" class="swap">Map</a> and initialize jQTouch like this: var jQT = new $.jQTouch({ icon: 'jqtouch.png', ...

Displaying JSON data based on a specific key

My current challenge involves dealing with a JSON string structured like this: {"cat1":"m1","cat2":["d1","d2","d3"],"cat3":["m1","m2","m3","m4"]} As part of my learning process in Javascript and AJAX, I am attempting to display the different values based ...

Ensuring correct association of values to avoid redundancies

There are 5 fields available for users to fill out on this form: Leave Code, From Date, Input Time1, To Date, and Input Time2. These variables are declared as a dates object in the .ts file, as shown below. interface Supervisor { name: string; code: s ...

Receiving a blank request payload despite implementing a body parsing middleware

I am currently working on setting up a login system, and I have a form that sends a post request to my webpack dev server. This server then proxies the request to my actual server. Here is the function responsible for handling the form submission and send ...

Ways to Retrieve JavaScript Variable inside HTML Tags in a JSP

I am currently facing a requirement where I must assign js variables to html input tag ids. For example: <input type='text' id='(here I need js variable)'/> I am aware that one way to achieve this is by creating the entire elem ...

Characteristics of events within the embed element

<div id='aplayer'></div> js $('#note').click(function() { $('#aplayer').html("<embed src=" + music + " onended='test();'" + ">"); }); function test(){ alert ('525'); } audio is ...

What could be causing my React child component to not update when changes are made to an array passed down in props after fetching new data?

My Profile.js component is responsible for fetching activity data related to a specific user from the URL parameter and updating the profileActivity state. This state is then passed down to my child component, ProfileActivity.js, where it should be display ...

Is it possible to easily extract all values associated with a particular key in a nested JSON using JavaScript?

I have a JSON structure that looks like this: [ { cells: [ { id: "1", cellType: 3, widget: { id: 1, description: "myDesc"} }, { id: "2", cellType: 4, widget: { id: 2, description: "myDesc2"} } ] }, { cells: [ { id: "3", c ...

Unable to click on link with JavaScript using Selenium webdriver

<a id="compareCompanies" b:onclick="needsController.showQuotes = true;" href="#">Compare companies</a> Below is the Selenium Webdriver JavaScript code using Mocha: driver.wait(function () { driver.findElement(webdriver.By.id("compareCompa ...

Can user-generated code execute Javascript Promises in its entirety?

Can one fully implement the JavaScript Promise class using only userspace code, without relying on any support from native code (such as the internals of JavaScript) that would typically only be accessible to those working on a JavaScript engine like the V ...

Updating File Owner with Google Drive API - Permission Error 400 "Field 'Permission Type' is mandatory"

I've been utilizing the Google Drive API within Google Apps Script. This particular script is written in sandboxed server-side Javascript, which restricts the use of the Google Client API for Javascript. As a Google Apps super admin, I am authenticat ...

Attempting to conceal the API, however, the backend is throwing an error

view the error image I am currently in the process of developing an NFT search application that is capable of locating the NFTs associated with a specific wallet address. However, I am faced with the challenge of using Alchemy without exposing the API key ...

How to Add Functionality to Angular Apps Without Defining a Route

One unique aspect of my website is the navigation bar. It appears on some pages but not others, so I've created a controller specifically for it. Here's how the navigation bar markup looks: <html ng-app="myApp"> <head> <title& ...

Check for pattern using JavaScript regular expression

Utilizing ng-pattern to validate a regular expression. The pattern must include 3 letters and 2 numbers in a group. For example: G-31SSD or G-EEE43 Currently, the pattern only matches the second example. ng-model="newGroup.groupCode" ng-pattern="/^&bso ...