简体   繁体   中英

How to access private properties from an IFFE in javascript

I was playing with the idea of using an IFFE inside a object declaration instead of an init() method that I have to manually invoke at the end of the declaration. The only problem I seem to be having is that I don't know how to access private properties from within the IFFE. Take the following example:

function Obj() {

    this.prop = 'Public property';
    var _prop = 'Private property';

    ( function( that ) {

        console.log( that.prop );
        console.log( that._prop ); // Returns undefined

    } )( this );

}

obj = new Obj();

by passing this into the IFFE I can access the this scope but the private properties do not seem to be assessable through this. I know I could manually pass individual properties in, but I would prefer a solution that allows me access to all private properties.

What is the best way to solve this?

IIFE is the way as the Module Pattern is implemented. (See The Module Pattern )

Any object declared inside a function is isolated from the outer scope, maning that private variables are unaccessible . If you need to modify private objects, you can reconsider using an IIFE .

Now take a look at your code, the variable _prop is declared in the same closure where the IFFE is defined, meaning that you can access that object within the IIFE , eg

function Obj() {
    var _private = 1;

    //IIFE
    (function() {
        console.log("_private: ", _private);
    }());
}

Also, you may create a public method that modifies the private object, eg

function Obj() {
    var _seed = 0;
    this.setSeed = function (seed) {
        _seed = seed;
    };
    this.getSeed = function() {
        return _seed;
    };
}

Or you can define a getter / setter in the instance prototype , but this approach has the disadvantage to have a lower performance, eg

function Obj() {
    var _seed = 0;
    Object.defineProperty(this, "seed", {
        get: function () { return _seed; },
        set: function (seed) {
            //ensure to be a numeric value
            if (+seed || seed === 0) _seed = +seed;
        }
    });
}

Or creating a module with loose augmentation

//begin IIFE
var module = (function (module) {
    var _private = 1;

    function getPrivate() {
        return _private;
    }

    function setPrivate(value) {
        _private = value;
    }

    function printPublicMember() {
        console.log(module.publicMember);
    }

    //public mudule API
    module = {
        "publicMember": "I am public!!",
        "printPublicMember": printPublicMember,
        "getPrivate": getPrivate,
        "setPrivate": setPrivate
    };

    return module;

}(window.module || {}));
//end IIFE

As @jherax said the purpose of using an IFFE is to approximate block level scope in JavaScript so accessing a private property outside of an IFFE defeats the purpose of having one.

However you could create an API of sorts by returning an object which points to the properties in question. Used improperly this is a bit of a hack and is generally discouraged.

function Obj() {

this.prop = 'Public property';
var _prop = 'Private property';

  ( function( that ) {

    console.log( that.prop );
    console.log( that._prop ); // Returns undefined

  } )( this );
  return {
    accessPoint: _prop //gives you a getter of sorts to _prop
  };
}

obj = new Obj();
obj.accessPoint;

Because:

var _prop = 'Private property';

creates a local variable and

    console.log( that._prop ); // Returns undefined

is attempting to access the _prop property of that (aka this ). Variables are not object properties*. Use:

    console.log( _prop ); // Returns Private property
  • Well, variables are properties of a VariableEnvironment which belongs to a LexicalEnvironment , a kind of object (in ECMA-262 ed 3 it was called a variable object ) but you can't access those directly in the way you can access variables as properties of the global or window object.

The IIFE inside your constructor has no meaning whatsoever. It is exactly equivalent to just writing its contents directly. The purpose of an IIFE is to create an enclosed scope with local variables, which you don't have.

In what way is this IFFE supposed to avoid having to call some init function? The constructor is already an init function in its own way.

The reason you can't access that._prop from within your IIFE is that there is no instance property called _prop . There is a local variable called _prop , To access it, simply say _prop , not this._prop or that._prop .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM