How to make a property/method invokable or not?

岁酱吖の 提交于 2019-12-11 03:42:10

问题


I want to achieve this functionality:

  1. I have an object var obj = {};
  2. I have three properties on that obj, obj.zero & obj.one& obj.binaryString

    • obj.zero & obj.one are methods while obj.binaryString is a string

When I chain the properties, I want them to add their respective digit to the binaryString. So for example:

obj.one.zero.zero.one => makes obj.binaryString = 1001

obj.one.zero.one.one.zero => makes obj.binaryString = 10110

I have achieved the above functionality with this:

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 log out the 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 the log and make the one and zero methods invokable or not so I can achieve this functionality:

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

How can I do this?

I believe it 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

回答1:


Just Make the obj as function , and print what ever 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 ")



回答2:


I would like to point out that what you're doing is a very bad/dangerous idea: abusing read properties to mutate the object itself is asking for trouble. You may not see it now, but it's going to lead to pain and heartache down the line in the form of difficult-to-find bugs and convoluted patterns.

What you can do is, which is not so dangerous, is instead of mutating the object itself, return a new instance of Binary with every call to #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 Chalk, 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 not to use classes at all. You can solve this problem with a pure function-based approach. It's immutable, it's safe, and I believe it's 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'


来源:https://stackoverflow.com/questions/43923053/how-to-make-a-property-method-invokable-or-not

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!