How do I make a property / method invokable or not?

I want to achieve this functionality:

  • I have an object var obj = {};

  • I have three properties on objects obj.zero

    and obj.one

    &obj.binaryString

    • obj.zero

      and obj.one

      - methods, and obj.binaryString

      - string

When I bind properties, I want them to add their corresponding digit to binaryString

. For example:

obj.one.zero.zero.one

=> does obj.binaryString

=1001

obj.one.zero.one.one.zero

=> does obj.binaryString

=10110

I got the above features:

function Binary () {
    var obj = { binaryString: '' };

    Object.defineProperty(obj, 'zero', {
        get: function() {
            obj.binaryString += '0';
            return obj;
        }
    });

    Object.defineProperty(obj, 'one', {
        get: function() {
            obj.binaryString += '1';
            return obj;
        }
    });

    return obj;
}

var binary = new Binary();
binary.one.zero.zero.one  // => obj.binaryString becomes '1001'

      

Now I want to exit completed binaryString

, plus and additionalString

which I have accomplished with the code below:

// placed inside Binary constructor function
Object.defineProperty(obj, 'log', {
    get: function() {
        return function(additionalString) {
            console.log(obj.binaryString + additionalString);
        };
    }
});

      

So, with this current code, I can do this:

binary.one.zero.one.zero.one.log(' is the answer');
// logs out `10101 is the answer`

      

What I want to do is get rid of log

and make the methods one

and zero

invokable or not, so I can achieve this function:

binary.one.one.zero.one(' is the result')
// => logs out `1101 is the result`

      

How can i do this?

I suppose this would be similar functionality to how Chalk works:

chalk.blue.bold('Hello world!');
// `blue` is not invoked here but it adds the color blue to the style

chalk.blue('Hello world!');
// `blue` IS invoked here.  It adds blue to the style and returns the stylized string

      

+2


source to share


2 answers


Just create a function obj as and print whatever you want.



function Binary () {
    var obj = function(msg){ console.log(msg+this.binaryString ) };
    obj.binaryString = ''

    Object.defineProperty(obj, 'zero', {
        get: function() {
            obj.binaryString += '0';
            return obj;
        }
    });

    Object.defineProperty(obj, 'one', {
        get: function() {
            obj.binaryString += '1';
            return obj;
        }
    });

    return obj;
}

var binary = new Binary();
binary.one.zero.zero.one.zero(" is the result ")
      

Run codeHide result


+3


source


I would like to point out that what you are doing is a very bad / dangerous idea: abuse of read properties to mutate the object itself is causing problems. You may not see it now, but it will lead to pain and heartache along the line in the form of hard-to-find errors and intricate patterns.

What you can do is not that dangerous, instead of mutating the object itself, return a new instance Binary

on every call #one

or #zero

. For example:

function Binary(s) {
  this.binaryString = s || ''
}
Object.defineProperty(Binary.prototype, 'zero', {
  get: function() {
    return new Binary(this.binaryString + '0')
}})
Object.defineProperty(Binary.prototype, 'one', {
  get: function() {
    return new Binary(this.binaryString + '1')
}})

      

This is the approach taken by Mel and will be much safer and less error prone.

UPDATE

After thinking about your problem and seeing your question, I think the best approach at all is to not use classes at all. You can solve this problem with a pure functional approach. It is immutable, it is safe and I find it less confusing. Here it is in ES5:



function bin(str) {
  if(!str) str = ''
  function f(msg) { return str + ' ' + msg }
  return Object.defineProperties(f, {
    zero: {
      get: function() {
        return bin(str + '0')
      },
    },
    one: {
      get: function() {
        return bin(str + '1')
      },
    },
  })
}

      

And if you can use ES6 (aka ES2015), you can make it much more compact:

function bin(str = '') {
  return Object.defineProperties(msg => `${str} ${msg}`, {
    zero: { get() { return bin(str + '0') } },
    one: { get() { return bin(str + '1') } },
  })
}

      

You would use it like this:

bin().one.zero.one.zero('is the answer') // '1010 is the answer'

      

+1


source







All Articles