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

Using an external variable within an internal function in TypeScript

I am facing a situation where I have a variable outside of a function that needs to be updated, but I am unable to access it using "this" as it is not reachable at that point in the code. export class GamesDetailPage { details : any = {}; type : St ...

Can you provide guidance on how to specifically specify the type for the generics in this TypeScript function?

I've been diving into TypeScript and experimenting with mapped types to create a function that restricts users from extracting values off an object unless the keys exist. Take a look at the code below: const obj = { a: 1, b: 2, c: 3 } fun ...

Extracting multiline value from a textarea using JavaScript

I'm trying to extract a multiline value from a textarea using JavaScript or jQuery and store it in a cookie. Below is the code snippet I am using: HTML: <textarea id="cont" cols="72" rows="15"> JavaScript: var txt = $('#cont').val( ...

The init function of the controller in Ext JS version 4.1.0 is not being executed

Recently, I started learning javascript and extjs, and while following the extjs 4.1 MVC Architecture tutorial, I ran into an issue. Everything was working fine initially, but when I tried to add the controller to the application, something went wrong. Bot ...

Why are my cursor and my drawing line on opposite sides?

I've been working on a JavaScript drawing app, but I'm facing an issue where the drawn elements are not aligned with my cursor. The positioning seems off, especially when moving to the right or up on the canvas. As I move towards the furthest lef ...

How can I prevent my JSON object from serializing .NET nulls as "null" for object members?

I am currently utilizing WebMethods to retrieve an array of a custom class. When this array is returned from a Jquery .ajax call, it gets serialized into a JSON object that can be utilized with Javascript in my ASP.NET application. The issue I am facing is ...

The previous button on Owl Carousel seems to be malfunctioning after navigating from a different page

In my case, I have two distinct pages: let's call them the first and second pages. On the first page, I utilize an owl carousel slider with a tag that links to a specific slide on the second page's owl carousel slider using an ID. Meanwhile, on ...

Use a function on values that have corresponding keys in a separate array

I am working with a form.value object that looks like this: form.value = { "to_date": "2019-03-21T05:00:00.000Z", "from_date": "2019-03-13T05:00:00.000Z", "is_form": "" "errors":"" } Additionally, I have an array called filterArray: filterArray ...

Watching a live video stream in real-time using WebRTC with React

Here is the HTML code <video ref={videos} autoPlay ></video> <Button onClick={() => navigator.mediaDevices.getUserMedia({audio: true, video: true}).then((mediaStream) => { videos.srcObject = mediaStream; videos.onloadedmetad ...

Can WebDriver (HtmlUnit, Ruby bindings) be configured to bypass JavaScript exceptions?

When attempting to load the page, HtmlUnit throws an exception and crashes my test. caps = Selenium::WebDriver::Remote::Capabilities.htmlunit(:javascript_enabled => true) driver = Selenium::WebDriver.for(:remote, :desired_capabilities => caps) drive ...

What are the best methods for ensuring a website maintains consistent visibility across all different screen sizes?

Recently, I created a website tailored for a viewport size of 1366px by 768px. My goal is to maintain the same design regardless of the browser window size without implementing responsive design techniques. For instance: When viewing the website on a 360 ...

User-triggered event not being emitted back from SocketIO server

In my React frontend, I am using socket.io-client and in the Express backend application, I am utilizing socket.io. There is an event on the server that sends a message to all users in a room when triggered. socket.on('connection', () => { ...

Retrieving data from an anonymous function in AngularJS and outputting it as JSON or another value

Within the following code, I am utilizing a server method called "getUserNames()" that returns a JSON and then assigning it to the main.teamMembers variable. There is also a viewAll button included in a report that I am constructing, which triggers the met ...

Is there a way for me to retrieve the UrlMatcher from ui-router?

While exploring the ui-router documentation, I came across an object called UrlMatcher. This object contains useful methods like exec, but I am struggling to find clear instructions on how to access it. Nevertheless, the documentation page provides a detai ...

Vue.js: Utilizing async/await in Vue.js results in an observer being returned

Currently, I'm attempting to retrieve data from an API and store it in an array. The issue arises when I try to log the response data from the API - the data is displayed just fine. I assign the value of a variable to the data obtained from awaiting t ...

Styling the active selection in nav class with bold attribute in Bootstrap/AngularJs

How can I apply the bold attribute to the currently selected nav bar item? <ul class="nav"> <li role="presentation" ng-repeate="item in items" ng-class="{'active':navLink == item.header}"> </li> &l ...

Slide in parts gradually by scrolling up and down, avoiding sudden appearance all at once

I have implemented a slider on my website using jQuery functions. For scrolling down, the following code snippet is used: jQuery("#downClick").click(function() { jQuery("html, body").animate({ scrollTop: jQuery(document).height() }, "slow"); ...

Is it possible to declare variables using the "this" keyword?

Consider the scenario where this.x=5 is declared and assess the accessibility of all relevant places. <script> $(document).ready(function(){ $("button").click(function(){ this.x=!this.x; $("#div1").fadeTo(400,this.x ? 0.4 : 1); }); }); & ...

JSON Date Format

I'm facing an issue where I am unable to retrieve the current date using new Date() because it is in JSON format. This particular code was written using MVC C#. The date appears as \/Date(1531364413000)\/. The dates stored in the database ...

Using prevState in setState is not allowed by TypeScript

Currently, I am tackling the complexities of learning TypeScipt and have hit a roadblock where TS is preventing me from progressing further. To give some context, I have defined my interfaces as follows: export interface Test { id: number; date: Date; ...