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

My component reference seems to have gone missing in angular2

Trying to load my Angular 2 app, I encountered this error: https://i.stack.imgur.com/FmgZE.png Despite having all the necessary files in place. https://i.stack.imgur.com/kj9cP.png Any suggestions on how to resolve this issue? Here is a snippet from ap ...

The seamless flow of web design

Seeking guidance on creating a responsive web page. I have a functional website that looks great on my 13" MacBook, but encounters distortion at different screen sizes. What steps are necessary to ensure it appears crisp and appealing on any device? Should ...

Is it possible to use Docxtemplater.js in a browser without familiarity with Node, Browserify, or npm?

I'm trying to get Docxtemplater.js to function properly on a browser. Unfortunately, I lack knowledge in areas such as Node.js, Browserify.js, "npm", "bower", and other technical aspects commonly found in modern JavaScript libraries. While I do inten ...

Ways to dynamically apply styles to the component tag depending on the visibility of its content

Consider a scenario where you have a component with logic to toggle the visibility of its contents: @Component({ selector: 'hello', template: `<div *ngIf="visible"> <h1>Hello {{name}}!</h1></div>`, styles: [`h1 { fo ...

Experience the magic of a customized cursor that disappears with a simple mouse movement in your website,

I have been experimenting with designing a custom cursor for my website. After finding a design I liked, I made some adjustments to suit my needs. However, an issue I encountered is that when I scroll, the custom cursor also moves away from its original po ...

Using AJAX to submit a form to a CodeIgniter 3 controller

I am working on adding a notification feature and need to run an ajax query through the controller when a button is clicked. Here's the script I'm using: $('#noti_Button').click(function (e) { e.preventDefault(); ...

What is the best way to capture the output of a script from an external website using Javascript when it is returning simple text?

Recently, I decided to incorporate an external script into my project. The script in question is as follows: <script type="application/javascript" src="https://api.ipify.org"> </script> This script is designed to provide the client's IP ...

Accessing an array of objects within nested objects results in an undefined value

I am facing an issue with my JavaScript object that is retrieved from MySQL. The object has a property which contains an array of other objects, as demonstrated below: parentObject = { ID: "1", Desc: "A description", chi ...

Ways to automatically update property value in MongoDB once a particular date is reached

Is it feasible to schedule a future date for a document in MongoDB, such as 30 days from the current date, and then automatically update another property of the document when that future date arrives? For instance: creating an event document setting the ...

Geocomplete Plugin without Google Branding

I've implemented the jQuery Geocomplete Library. This is what I have accomplished so far- $(function() { $("#find_product_location").geocomplete( { map: "#product_location", mapOptions: { mapTypeId : 'roadmap',//roadmap, satellite,hybrid ...

Transfer PHP's uniqid() function to real-time using JavaScript with jQuery

Seeking a compact JavaScript(jQuery) code snippet to achieve this: date("r",hexdec(substr(uniqid(),0,8))); Your assistance is highly appreciated. Thank you. ...

What could be the reason for the handleOpen and handleClose functions not functioning as expected?

I am facing an issue with my React component, FlightAuto, which contains a dropdown menu. The functionality I'm trying to achieve is for the dropdown menu to open when the user focuses on an input field and close when they click outside the menu. Howe ...

Issue locating the bottom of the scroll bar

My attempt to detect when the scroll reaches the bottom of a div involves using this code: $('.scrollpane').scroll(function(){ if ($(this).scrollTop() + $(this).height() === $("#results").height()) { alert('scroll at bottom&a ...

Error encountered during Yarn installation process: The tunneling socket was unable to be established due to a connection refusal on localhost at port 80

I have a Next.js app that needs to be built on our company servers before deployment. We use a proxy, and I've configured yarn to use the proxy as well. yarn config set proxy http://xx.xxx.xx:xxxx yarn config set httpsProxy http://xx.xxx.xx:xxxx yarn ...

Using webpack to load the css dependency of a requirejs module

Working with webpack and needing to incorporate libraries designed for requirejs has been smooth sailing so far. However, a bump in the road appeared when one of the libraries introduced a css dependency: define(["css!./stylesheet.css"], function(){ &bsol ...

JavaScript's addition function is not functioning properly

Does anyone know how to calculate the sum of these variables? var totalPrice = document.values.T1.value; var pounds = document.values.T2.value; var serviceFee = 5.00 var counter1 = 0; var counter2 = 0; var processing = 0; var shippingCost = 0; var ...

Testing the screen size automatically using Javascript

Hello everyone, I've implemented a JavaScript code that triggers an image to slowly appear and darken the background when a link is clicked. However, on an iPad, the background doesn't completely turn black as intended. The CSS specifies that the ...

The timing calculations in Vue.js do not align with the standard JavaScript version

I am currently working on developing a 'beats per minute' (BPM) calculator, which is similar to the one available here. However, I have noticed that when using the BPM calculator from that link for testing on a particular song, it quickly approxi ...

Is there a way to determine if npm packages are accessing and misusing my system's environment variables?

Apologies if this seems nonsensical. But including a code snippet like this: // to illustrate I'm utilizing a source from https://www.npmjs.com/package/got got.post(maliciousUrl, {json: process.env}) Is it enough to leak environment variables to an u ...

Does the entire state get replaced every time a change is made if the state is immutable?

Is it necessary to replace the entire state if it is immutable? Otherwise, wouldn't mutating the state occur? Are top-level keys maintained as distinct immutable objects? Wouldn't changing anything necessitate replacing the entire state by defin ...