1

I have this prompt on code wars

"There's no such thing as private properties on a javascript object! But, maybe there are?

Implement a function createSecretHolder(secret) which accepts any value as secret and returns an object with ONLY two methods"

I'm pretty sure it wants me to use closures to achieve this and I have read about how to do this here:

Private variables and closures

https://developer.mozilla.org/en-US/Add-ons/SDK/Guides/Contributor_s_Guide/Private_Properties

This is my code:

function createSecretHolder(secret) {
  return {
    var _secret = secret;
    this.getSecret = function(){
      return _secret;
    }

    this.setSecret = function(secret){
      _secret = secret;
    }
  }
}

However, I get this error:

[eval]:6
 var _secret = secret;
              ^
SyntaxError: Unexpected token =
    at Object. ([eval]-wrapper:6:22)
    at 
    at evalScript (node.js:536:25)
    at startup (node.js:80:7)
    at node.js:906:3

I tried to make an object literal with a private value to hold the value of secret and mostly followed the examples from the sources I listed above. How do I create a closure with ONLY two methods to get and set data and where do I store the value of secret without adding another property?

Community
  • 1
  • 1
user137717
  • 2,005
  • 4
  • 25
  • 48

3 Answers3

2

You are trying to return an object literal, in which you cannot have an assignment statement. To have the closure property, you need to store the variable in the function scope, like this

function createSecretHolder(secret) {
    var _secret = secret;

    return {
        getSecret: function() {
            return _secret;
        },

        setSecret: function(secret) {
            _secret = secret;
        }
    }
}

Now, _secret is in the scope of the getSecret and setSecret functions, because of the closure property. So they can access it.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • Would the same thing work with _secret : secret inside the object literal? MDN says the underscore is just a coding convention and is not enforced by the language. There is nothing stopping anyone from accessing _secret directly, so I don't understand the privacy / protection it supposedly provides. – user137717 Jan 06 '15 at 05:29
  • 1
    @user137717 Since `_` is just a convention, if you have `_secret: secret` in the object literal, it will also be visible to outside world. For example, `createSecretHolder()._secret = 1` would directly assign value to it. That's not we want, right? ;) That is why we take advantage of the closure property. – thefourtheye Jan 06 '15 at 05:33
0

The problem is return keyword actually returns object with a structure which you didn't follow. try this:

function createSecretHolder() {
  var _secret = secret;
return {

    getSecret : function(){
      return _secret;
    }
,
    setSecret : function(secret){
      _secret = secret;
    }
  }
}
Super Hornet
  • 2,839
  • 5
  • 27
  • 55
  • 2
    As a suggestion, it's good to explain what the problem is (along with a solution), rather than just posting an undocumented block of code as an answer. – Christian Jan 06 '15 at 05:24
0

Using _ to prepend a property is a common naming convention JavaScript developers follow to show the intention that the property should not be altered, and it is definitely related to this prompt, but it seems like it is not hinting that it's needed and it may not be required for this challenge specifically.

The SyntaxError you're seeing is related to the _secret initialization being within the object literals rather than outside. Object literal syntax is different from variable declaration & assignment and should be mixed. You can move the var _secret = secret; to outside of and before the return statement (but still inside of the function createSecretHolder). (Super Hornet is right, but his code is missing the secret parameter, so his code would get a Reference error saying that secret is not defined.) While your attempt is slightly more declarative, you can actually do without the const _secret = secret. The first thing that the function does is to pair its argument with its parameter, in this case, declaring secret and assigning the input to it. So it is already "in closures".

Here's my take and it works almost the same, except I like to include the console.log() into my functions that I'm expecting to see a result.

function createSecretHolder(secret) {
  // input: secret 
  // output: object (with only 2 methods) 
  
  return {
    getSecret() { console.log(secret) },
    setSecret(input) { secret = input }
  }
}

const obj1 = createSecretHolder(5);
obj1.getSecret() // => 5
obj1.setSecret(2)
obj1.getSecret() // => 2

Same as:

function createSecretHolder2(secret) {
  return {
    getSecret() { return secret },
    setSecret(input) { secret = input }
  }
}

const obj2 = createSecretHolder2(91);
console.log(obj2.getSecret()) // => 91
console.log(obj2.setSecret(82)) // => undefined
obj2.setSecret('new Secret') // logs nothing, returns undefined
obj2.getSecret() // logs nothing, returns 'new Secret'
yoyoyojoe
  • 103
  • 2
  • 8