Inheritance through Parasitism in JavaScript

Just finished a Douglas Crockford lecture where he introduced the concept of parasitic inheritance in JavaScript. This involves one constructor calling another to modify the object. The code example he provided is:

function gizmo(id, secret) {
  secret = secret || {};
  secret.id = id;
  return {
    toString: function () {
      return "gizmo " + secret.id;
    }
  };
}

function hoozit(id) {
  var secret = {},
      that = gizmo(id, secret);
  that.test = function (testid) {
    return testid === secret.id;
  };
  return that;
}

var myHoozit = hoozit(20);
console.log(myHoozit.test(20)); //returns true

The code seems pretty straightforward except for one thing - the hoozit function raises confusion. Without setting secret = {}, you won't get a true returned. This puzzles me because in the gizmo function, there's secret = secret || {} which should handle this scenario... but it doesn't.

Why does the short circuit (secret = secret || {}) fail in the gizmo function when no second parameter is passed in the hoozit function (breaks in Chrome and Firefox)??

Answer №1

What is the reason behind the malfunction of the short circuit (secret = secret || {}) in the gizmo function when a second parameter is not passed in the hoozit function (this issue occurs in both Chrome and Firefox)??

The issue lies in the fact that you are unable to access secret within that.test as it does not exist in that particular scope:

function hoozit(id) {
  var that = gizmo(id);
  that.test = function (testid) {
    // 'secret' is not defined in this or any higher scope
    // hence, a reference error occurs
    return testid === secret.id;
  };
  return that;
}

The only existing secret object is local to the gizmo function.


If you define it without passing it to gizmo, then secret = secret || {} will result in creating a new object inside the gizmo function, i.e., secret = {}. This new object can only be accessed within the gizmo function and is unrelated to the secret variable in the hoozit function. The secret object within gizmo is separate from the one in hoozit.

function hoozit(id) {
  var secret = {},      // secret object is created here
      that = gizmo(id);
  that.test = function (testid) {
    // since `secret.id` was never set, the comparison results in `false`
    return testid === secret.id;
  };
  return that;
}

There is no issue with secret = secret || {}, it is functioning as intended.

Answer №2

Here is a more straightforward example to consider:

function Foo(baz){
    baz = baz || {};
    baz.boo = 1;
}

function Bar(baz){
    baz = baz || {};
    Foo(baz);
    return baz;
}

When we invoke Bar(), we pass an object to Foo, which then modifies the object by adding a boo property. Simple and effective!

Now, let's modify our Bar function like this:

function Bar(baz){
    baz = baz || {};
    Foo();
    return baz;
}

The key difference here is that we are not passing an object to Foo. Consequently, Foo creates an object within its own scope, adds a property to it, and then exits. Since this new object is not in the scope of Bar, Bar remains unaware of its existence and cannot access it. As there are no references pointing to this object, it gets removed from memory shortly after.


However, your situation differs slightly due to the involvement of the toString function. This function holds a reference to the object, making it a local variable within its scope once the outer scope has finished execution. If we skipped passing a secret object, it would remain confined within that particular scope unless explicitly exported.

A more sensible approach would be to establish the secret as a property of the original object itself. By doing so, the secret can still be accessed by knowledgeable JavaScript users, leading to smoother code management and integration into inheritance methods.

In case you are unaware, remember that SomeFunction.call allows for multiple arguments. The first argument specifies the value of this within the function, while subsequent arguments consist of regular function parameters.

function gizmo() {
    this.toString = function () {
        return "gizmo " + this.id;
    };
};

function hoozit(id) {
    this.id = id;
    gizmo.call(this); // enables gizmo to interact with this object

    this.test = function (is) {
        return this.id === is;
    };
};

h = new hoozit(1);
console.log(h.test(1)); // true
console.log(h.toString()); // "gizmo 1"

Answer №3

To resolve the issue, ensure that secret = {} is defined.


The error occurs at return testid === secret.id; because secret must be initialized.

The key aspect to note is where secret.id is assigned a value, as all operations are within the function gizmo(). The crucial line is: that = gizmo(id, secret);

In JavaScript, objects are passed by reference when passed as arguments. This implies that any changes made to an object in one function will affect it locally.

If this behavior is not desired, a copy of the argument would be necessary. However, in this scenario, updates to secret in gizmo should also reflect in hoozit, so everything aligns as intended.


An alternative way to express the solution:

function gizmo(secret) {              
   secret = secret || {'id':null};    
   return {
      toString: function () {
         return "gizmo " + secret.id; 
      }
   };
}

function hoozit(id) {
   var secret = {'id':id},           
       that   = gizmo(secret);        

   that.test  = function (testid) {
      return testid === secret.id;
   };

   return that;
}

var myHoozit = hoozit(20);
console.log( myHoozit.test(20) ); //returns true

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

What possible reasons could there be for my vue project failing to load the JavaScript file?

I encountered an issue with my login page and script.js file while setting up my project. Strangely, my Vue application is not loading the JavaScript file as expected. The console displays this error message: https://i.sstatic.net/QG0hL.png The error seem ...

Node replication including a drop-down menu

Is there a way to clone a dropdown menu and text box with their values, then append them to the next line when clicking a button? Check out my HTML code snippet: <div class="container"> <div class="mynode"> <span class=& ...

Implementing swipe functionality to Bootstrap carousel

This is the code snippet I am working with: <div class="container"> <div id="myCarousel" class="carousel slide" data-ride="carousel" data-interval="3000"> <!--Indicators--> <ol class="carousel-indicators"> ...

Display the list of cities associated with the country chosen in the form

I am currently working with the repository found at https://github.com/country-regions/country-region-data/blob/master/data.js to create a mapping of countries and their related cities. I'm seeking guidance on how to achieve this task effectively. My ...

Tips for concealing JavaScript code while inspecting elements with AngularJS

Is it possible to display minified JavaScript code when using Angular and inspecting elements? ...

Prioritize loading CMS content before mounting the React component

I am facing a challenge with importing my post from ButterCMS to React due to the async issue. import React, { useState } from "react" import Butter from "buttercms" import gradient from "../../images/TealLove.jpg" export default () => { const butt ...

Displaying HTML elements in a specific order using ng-repeat

Upon receiving the json message, my goal is to display it in HTML in a specific order. Within the json message, the position value indicates the desired order of elements, with 0 representing the first element in the array. At times, the json message may ...

Can a function be called from outside its parent function?

I was pondering the possibility of calling a function from outside its parent function: var $element = $( '.element' ); function myFunction( element ) { var width; function onResize() { width = element.width(); } onResi ...

Spin the Three.js camera in a circular motion along the Y-axis

I'm feeling a bit puzzled about this one :S I've written a code that allows my camera to rotate only halfway. I can move the camera along half of a circle using mousemove events, but I actually want it to be able to complete a full rotation :) ...

Tips for embedding a file within a text box in HTML and enabling users to make direct edits

I am currently working on a feature that allows users to open a .txt or .html file from their file explorer and paste the contents into a textarea for editing and saving purposes. My question is whether it's possible to read the file content and auto ...

What is the solution for resolving an Optional chaining Error in a React project?

Currently, I am delving into the world of react redux while simultaneously constructing an app. One interesting aspect that caught my attention is optional chaining in user authentication. However, this method seems to be throwing an error message. You may ...

Enrolling JavaScript documents and connected inline programming

I need a solution for dealing with two arrays. The first array consists of URLs pointing to JavaScript files that I want to register using $.getScript(url); Next, the second array contains inline JavaScript commands that should be registered with $("html ...

WordPress CSS & JS files failing to enqueue properly

My attempt to integrate my CSS and JS files with WordPress has not been successful. Although my CSS works through the Custom CSS tab, this is not an ideal solution. Below is the code from my functions.php file for your reference. Can you help me troublesho ...

The component "SafeAreaViewRN" could not be located within the UIManager

Upon attempting to open a bundle on my Android device, I encountered the following error message: A warning was displayed stating that the app was accessing a hidden field in android's view accessibility delegate. Additionally, an Invariant Violati ...

Every time Fetch() is called in Node.js, a fresh Express session is established

Here is a snippet of code from a webshop server that includes two APIs: ./login for logging in and ./products to display products. The products will only be displayed after a successful login. The server uses TypeScript with Node.js and Express, along wit ...

What is the best way to horizontally align my divs and ensure they stack properly using media queries?

My layout is not working as expected - I want these two elements to be side by side in the center before a media query, and then stack on top of each other when it hits. But for some reason, it's not behaving the way I intended. I've tried to ce ...

Exploring the topic of AngularJS unit testing and working with httpBackend timeouts

I have experience in the testing world, particularly with TDD using tools like mocha, sinon, chai, and nodejs. Recently, I've been finding AngularJS testing a bit challenging to grasp and implement. Currently, I am trying to test the simplest method ...

Having difficulties injecting a Service into a TypeScript Controller

I recently started working with TypeScript and I created a controller where I need to inject a service in order to use its methods. However, I am facing an issue where I am unable to access the service functions and encountering an error. Error TypeError ...

The functionality of returning false on ajax response does not effectively prevent the form from submitting

I'm encountering an issue where the return false statement doesn't seem to work when using an AJAX call. The form is still getting submitted successfully despite trying to prevent it with a conditional check on the response from the AJAX request. ...

The result of the $.post() request is back

In my current code, I am using a jQuery $.post function like this: $.post('/test', json_data, function(data) { result = data }); This function is being used in a validation process where the return value (data) contains either true or false ...