Crockford's system for safeguarded entities

Despite the abundance of questions and resources related to "Javascript: The Good Parts," I am struggling to comprehend a specific sentence in the book. On pages 41-42, the author defines the serial_maker function as follows:

var serial_maker = function (  ) {

// This function produces an object that generates unique strings. Each unique string consists of a prefix
// and a sequence number. The generated object includes 
// methods for setting the prefix and sequence
// number, as well as a gensym method for producing unique
// strings.

    var prefix = '';
    var seq = 0;
    return {
        set_prefix: function (p) {
            prefix = String(p);
        },
        set_seq: function (s) {
            seq = s;
        },
        gensym: function (  ) {
            var result = prefix + seq;  
            seq += 1;
            return result;
        }
    };
};

var seqer = serial_maker();
seqer.set_prefix('Q');
seqer.set_seq(1000);
var unique = seqer.gensym(); // the value of unique will be "Q1000"

The author further explains:

The methods within this function do not utilize this or that. Consequently, the integrity of the sequer remains intact. It is impossible to access or alter the values of prefix and seq except through approved methods.

I am puzzled about how to use this and/or that to breach this encapsulation. Can someone shed some light on this issue?

Thank you

Answer №1

Take a look at the code snippet below:

var generator = function () {
    return {
        prefix: '',
        sequence: 0,

        set_prefix: function (p) {
            this.prefix = String(p);
        },
        set_sequence: function (s) {
            this.sequence = s;
        },
        generate_unique_code: function (  ) {
            var result = this.prefix + this.sequence;
            this.sequence += 1;
            return result;
        }
    };
};

The intended use of this generator is as follows:

var myGenerator = generator();
myGenerator.set_prefix('correct');
myGenerator.set_sequence(1000);

However, in the above version, you could also do the following:

var myGenerator = generator();
myGenerator.prefix = 'incorrect';
myGenerator.sequence = -500;

Or even this:

delete myGenerator.prefix;

Since both prefix and sequence are exposed as properties of the generator object, they can be accessed and modified by any code that has access to the object.

In JavaScript, properties are always public unless specific features like Object.defineProperty() are used to restrict access.

Prior to arrow functions being introduced, a common issue was with functions defined as methods not being able to access their original context. Consider this example:

var ButtonHandler = {
    message: 'Hello!',

    initialize: function() {
        for (let button of document.querySelectorAll('button')) {
            button.onclick = function() {
                alert(this.message);
            }
        }
    }
};

ButtonHandler.initialize();

In this case, the alert will show "undefined" instead of "Hello!". This is because the this keyword inside the click event function refers to the button element itself, not the ButtonHandler.

To resolve this issue, arrow functions were introduced:

button.onclick = () => {
    alert(this.message);
}

With arrow functions, the this scope is maintained, so ButtonHandler.message will display correctly.

Before arrow functions, developers commonly used the workaround below:

var self = this;
button.onclick = function() {
    alert(self.message);
}

This technique, along with closures, allowed for a limited form of "private" members that object methods could access but were hidden from outside code.

Answer №2

When it comes to creating objects from a function in JavaScript, there are two main approaches that are commonly used:

  • The factory pattern
  • The constructor pattern (especially demonstrated with ES6's class)

Exploring the factory Pattern

The concept of the factory pattern involves creating new objects without relying on the new keyword or establishing a this binding for the newly generated object. Essentially, this approach focuses on generating and returning a fresh object as the output of the function expression, hence its name - factory.

One significant advantage of using factory functions is their ability to implement true private attributes within an object in JavaScript by leveraging closure for encapsulation. Since there is no direct reference to the internal variables like prefix and seq, these properties are effectively hidden. This methodology stands out as the primary method for achieving fully-private encapsulated object attributes in JavaScript, unlike Java's employment of private.

Is there a way to breach the encapsulation barrier imposed by factory functions?

In such cases, transitioning to the Constructor Pattern through converting the function into a constructor proves to be the solution, depicted below using ES6 syntax:

class SerialMaker {
    // Introduces a `this` context linked to the instance
    // However, genuine encapsulation of private properties is absent
    constructor () {
        // PSEUDO-PRIVATE PROPERTIES
        this.__prefix__ = '';
        this.__seq__ = 0;
        // METHODS
        this.set_prefix: function (p) {
            this.__prefix__ = String(p);
        };
        this.set_seq: function (s) {
            this.__seq__ = s;
        };
        gensym: function (  ) {
            var result = this.__prefix__ + this.__seq__;
            this.__seq__ += 1;
            return result;
        };
    }

With this structure, object instances can now be initialized using the new operator

var seqer = new SerialMaker(); // Invokes the constructor to create a new object instance
seqer.set_prefix('Q'); // Modifies only for this specific instance: this.__prefix__
seqer.set_seq(1000); // Updates solely for this particular instance: this.__seq__
var unique = seqer.gensym(); // Generates "Q1000"

While things seem similar thus far, a crucial issue arises...

sequer.__prefix__ // => 'Q' // Unexpected access to privacy!
sequer.__seq__ = 2000 // Direct manipulation without errors

... the protective shield of encapsulation is utterly breached. The integrity of the sequer has been compromised.

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

Modify every audio mixer for Windows

Currently working on developing software for Windows using typescript. Looking to modify the audio being played on Windows by utilizing the mixer for individual applications similar to the built-in Windows audio mixer. Came across a plugin called win-audi ...

I'm experiencing a lack of feedback while implementing jQuery/AJAX with JSONP

Attempting to perform a cross-domain request using jQuery/AJAX, I have the code below; $.ajax({ url: "http://www.cjihrig.com/development/jsonp/jsonp.php?callback=jsonpCallback&message=Hello", crossDomain:true }) .done(function( msg ) { alert( ...

Issues arise when attempting to alter the background image using jQuery without browserSync being activated

I am facing an issue with my slider that uses background-images and BrowserSync. The slider works fine when BrowserSync is running, but without it, the animations work properly but the .slide background image does not appear at all. Can someone help me ide ...

Switch out bootstrap icons for angular material icons

I'm currently in the process of transitioning from using Bootstrap to Angular Material in an existing application. I need assistance with replacing the Bootstrap icons with Angular Material icons. Any help is greatly appreciated. <md-button class= ...

Can you explain the purpose of the "letter:" included in the code and how it is utilized?

g: function testFunction() { return true; } h: function anotherTestFunction() { } i: console.log('test') I'm intrigued by the mystery of this code snippet. As is written, I am executing it in NodeJS version 16 or higher and trying to un ...

Differences in how line breaks are handled in script output have been observed when comparing Atom and Notepad

Currently, I am utilizing a small script that generates a .txt file and inputs some data into it. Strangely, when I open the .txt file in Atom, the content appears on separate lines as I intended. However, when I access the same file in notepad, all the co ...

Is it possible to transform div containers into unique shapes?

I'm working on a design where I want to have two divs that resemble teeth, one on the top half of the page and the other on the bottom half. The concept is to make these mouth piece divs open and close as you scroll with the mouse, revealing the conte ...

Ways to delete a header from the req object in Express

Can anyone help me understand how to remove a header from the req object in Express? I've heard that using res.disable("Header Name") can do this for the res object, but it doesn't seem to work for req.headers. ...

Passing React components between components using dot notation

How can I pass a boolean Parent prop into a child component using dot notation with a functional component? The Component structure is: <Dropdown className="float-right"> <Dropdown.Title>Open menu</Dropdown.Title> <Dropd ...

Encountered an issue when attempting to send data using this.http.post in Angular from the client's perspective

Attempting to transfer data to a MySQL database using Angular on the client-side and Express JS on the server-side. The post function on the server side works when tested with Postman. Here is the code snippet: app.use(bodyParser.json()); app.use(bodyPa ...

Using jQuery Modal Dialog with ASP.NET MVC 2

In my ASP.NET Mvc 2 application, I have a grid of user info. When a user is clicked, a jQuery Modal dialog opens allowing me to edit and save the user's information successfully. I am now looking for assistance on implementing validation on this moda ...

How can we dynamically resize page content to fit varying browser window sizes across different devices with the help of jQuery/JavaScript?

Looking for a solution involving an HTML form that includes a text field and a submit button. The text field is where the user enters a URL, and upon clicking the submit button, they are redirected to that URL. Seeking a way to adjust the size of the new ...

Trigger an event in jQuery when the focus moves away from a set of controls

Within a div, I have three textboxes and am looking for a way to trigger an event when focus leaves one of these inputs without transitioning to another one of the three. If the user is editing any of the three controls, the event should not be triggered. ...

Problem with image title in jQuery mobile

My code seems to be having an issue where the title does not display completely when hovering over it. For example, if the title is set as "The Value", only "The" is shown and not "The Value". Can anyone help me identify the mistake? Thank you in advance ...

Styling JSON data in a jQuery Mobile list display

Currently working on a jQuery Mobile application that aims to achieve a similar output as shown in this image: The HTML code responsible for generating the image is as follows: <ul data-role="listview" data-inset="true"> <li data-rol ...

Tips for including extra items in a JSON String using Angular 2

function execute(req:any): any { var stReq = JSON.stringify(req); // Adding additional item "Cityname": "angular2City" inside req req.Cityname = 'angular2City'; } Now, how can I include the additional item "Cityname": "angular2C ...

Forward the jsp to the servlet before navigating to the following page

Issue: After submitting the JSP form on Page1, it redirects to a server-side JSP page but appears as a blank page in the browser. Instead, I want it to redirect to Page2 which includes a list box that highlights the newly created item. Seeking help with t ...

Avoid refreshing the page when clicking on an anchor tag in Vue.js

I have the code below in my Vue file. The problem I am encountering is that the page reloads whenever I click on the link. I have tried using event.preventDefault() but it did not solve the issue. Can someone please help me identify what I am doing wrong ...

Simultaneously updating the states in both the child and parent components when clicked

In my code, I have two components: the parent component where a prop is passed in for changing state and the child component where the function is called. The function changes the state of the parent component based on an index. changeState={() => this ...

How to retrieve JSON data in Angular.js

I'm having trouble accessing a json file in angular.js with the code below. I keep getting an error message and could really use some help! Here is my module : angular.module("demoApp", ['demoApp.factory','demoApp.controllers']); ...