5

Is it possible to add a property (with get and set method) to the scope of a file without making it global? (Similar to how let or const would work for a variable declaration)

This is the code I've written so far, It can add a property to the global scope.

var propertyValue;

Object.defineProperty(global, "PropertyValue", {
    get: function () {
        return propertyValue;
    },
    set: function (value) {
        propertyValue = value;
    }
});

console.log(PropertyValue);

Is it possible to make the property only visible to just the file it was declared in. The same thing can be done by declaring a variable and adding all properties there.

var fileProperties;
var propertyValue;

Object.defineProperty(fileProperties, "PropertyValue", {
    get: function () {
        return propertyValue;
    },
    set: function (value) {
        propertyValue = value;
    }
});

console.log(fileProperties.PropertyValue);

But then I still need to type the name of that variable every time I want to get/set a property.

So is there a way to create a property that

  1. Is not fully global
  2. Can be accessed without stating the owner object
  3. Can be recognized by eslint
nick zoum
  • 6,639
  • 5
  • 26
  • 63

3 Answers3

3

A property should be accessed on some object, the only possibilities for an object to be omitted in JavaScript are global properties and with statement.

As the original code shows, this will access a property on global variable, using global variables for local tasks is a bad practice, Using global variables for local tasks is a bad practice:

Object.defineProperty(global, "PropertyValue", {...});

console.log(PropertyValue);

Another way is to use with statement, which is deprecated and won't work in strict mode:

Object.defineProperty(someObject, "PropertyValue", {...});

with (someObject) {
  console.log(PropertyValue);
}

In Node, a script is evaluated in the scope of module wrapper function, this.PropertyValue refers to module.exports.PropertyValue in module scope.

A property can be defined on export object explicitly:

let propertyValue;

Object.defineProperty(exports, "PropertyValue", {
    get: function () {
        return propertyValue;
    },
    set: function (value) {
        propertyValue = value;
    }
});

console.log(exports.PropertyValue);

PropertyValue will be available to other modules when this module is imported. There are usually no good reasons to enforce encapsulation to the point where it starts to make developer's life harder. If PropertyValue isn't intended to be used outside the module, usually it's enough to use Hungarian notation and underscore internal/private property:

Object.defineProperty(exports, "_PropertyValue", { ... });

This way it's still available for testing.

Estus Flask
  • 150,909
  • 47
  • 291
  • 441
  • While this explain how `this` refers to the `exports` object when a containing object hasn't been defined. It still doesn't answer the question. Same thing can be achieved using a new variable and without making the variable public (updated question to include example) – nick zoum Mar 23 '19 at 12:33
  • Yes, the question didn't state the intention clearly. No, this isn't possible. I added the explanation. A reason to use `exports` is that it already exists. – Estus Flask Mar 23 '19 at 13:03
2

If you want scope of variable limited to that file only use this instead of global

var propertyValue;

Object.defineProperty(this, "PropertyValue", {
    get: function () {
        return propertyValue;
    },
    set: function (value) {
        propertyValue = value;
    }
});

console.log(this.PropertyValue); // prints undefined

propertyValue={a:1}
console.log(this.PropertyValue) // prints {a:1}
Vikash Singh
  • 1,767
  • 2
  • 11
  • 26
  • I've tried that, it can't be accessed without stating the owner object and it can't be recognized by eslint. – nick zoum Mar 22 '19 at 08:16
  • well, you can't access without stating owner object because its the property of that object. In terms of es6 if you want to access some property of class you have to use class or instance of it. I think your 2nd point is hypothetical. – Vikash Singh Mar 22 '19 at 08:37
  • You can access it directly when using `global` instead of `this` and you can do the same with `window` and `this` in a browser. – nick zoum Mar 22 '19 at 08:54
  • Accessing a variable from `this` usually confuses most intellisenses even if you have declared it using `jsdoc` – nick zoum Mar 22 '19 at 09:03
  • 1
    global variable is shared across all the files in nodejs whereas variable declared within file has scope limited that file only. I have few sources : 1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this 2. https://stackabuse.com/using-global-variables-in-node-js/ 3. https://stackoverflow.com/questions/43627622/what-is-the-global-object-in-nodejs 4. https://medium.com/quick-code/understanding-the-this-keyword-in-javascript-cb76d4c7c5e8 – Vikash Singh Mar 25 '19 at 05:59
-1

The answer all your questions:

  1. Is not fully global.

  2. Can be accessed without stating the owner object.

  3. Can be recognized by eslint.

is to use const or let statements.

From the documentation of const

Constants are block-scoped, much like variables defined using the let statement. The value of a constant cannot change through reassignment, and it can't be redeclared.

From the documentation of let

The let statement declares a block scope local variable, optionally initializing it to a value.

Community
  • 1
  • 1
Benjie Wheeler
  • 530
  • 3
  • 14
  • Since you have a setter method, I would recommend using `let` depending the type of data you want to store. You could use a specific convention like all upper case letters in the name to denote a file property. – Mak Mar 22 '19 at 01:20
  • 1
    How do you define a property (with `get` and `set` functions) using `let`/`const`? – nick zoum Mar 22 '19 at 07:40