JavaScript: default arguments in automatic getters and setters in closures without eval?

那年仲夏 提交于 2019-12-08 15:42:39

Do you mean something like this:

function myClosure(...vars) {
  const instance =  {};
  vars.forEach(varArg => {
    let name = undefined;
    let value = undefined;
    if (typeof varArg == 'string')
    {
       name = varArg;
    }
    else
    {
       name = Object.keys(varArg)[0];
       value = varArg[name];
    }
 
    instance[name] = function(d) {
      if (!arguments.length) return value;
      value = d;
      return instance;
    };
  })
  return instance;
}

const test = myClosure(
  { "v1": 1 },
  "v2",
  { "v3": 3 },
);
// Print some defaults.
console.log(test.v1());
console.log(test.v2());

test.v1(16).v2(42) // give new values to v1, v2
console.log(test.v1(), test.v2(), test.v3())

Proxies, for the heck of it.

function myClosure(...vars) {
  const instance = vars.reduce((obj, { name, value }) => {
    obj[name] = value;
    return obj;
  }, {});

  let proxy;
  const handler = {
    get: function(target, prop) {
      return (...args) => {
        if (args.length == 0)
          return instance[prop];

        instance[prop] = args[0];

        return proxy;
      };
    }
  };

  proxy = new Proxy(instance, handler);
  return proxy;
}

const test = myClosure(
  { name: "v1", value: 1 },
  { name: "v2" },
  { name: "v3", value: 3 }
);
// Print some defaults.
console.log(test.v1());
console.log(test.v2());
console.log(test.vNew());

test.v1(16).v2(42).vNew(50); // give new values to some variables.
console.log(test.v1(), test.v2(), test.v3(), test.vNew())
Bergi

The gist of that question was as follows: "How can one automatically provide getters and setters for scoped variables in a closure - without the use of the eval statement". There the poster, provided code demonstrating how to do so with eval and the user gave an answer which does not require eval.

No, you cannot do without eval. All the answers here that don't use any form of eval do not access scoped variables, but rather just plain properties - or they create their own local variables.

Providing a default value is rather simple with that:

function myClosure(...args) {
  var instance =  {v3: 2};
//                 ^^^^^ not a `var`
  for (const arg of args) {
    let val = instance[arg];
    instance[arg] = function(d) {
      if (!arguments.length) return val;
      val = d;
      return instance;
    };
  }
  return instance;
}

Note: I am posting my own answer for reference only. I will not be marking this as the answer to the question.

Building off the answer provided by @H.B., I update the answer in the following ways:

  1. getters and setters are made on initialization of the closure itself
  2. make the getter and setter production function a bit more messy to allow for more lazy definition of variables
  3. instance is now a function, not an object

    function myClosure() {
    
      var instance =  function () {
          console.log(this.v1(), this.v2(), this.v3())
      };
    
      var publicVariables =[ 'v1', 'v2', {'v3': 3} ] 
    
      function setup() {
    
    
        var args = Array.prototype.slice.call(arguments);
    
        // if called with a list, use the list, 
        // otherwise use the positional arguments
    
        if (typeof args[0] == 'object' && args[0].length) { args = args[0] }
    
        args.forEach(function(arg) {
            var name, value
            if(typeof arg == 'object') {
            name = Object.keys(arg)[0]
            value = arg[name]
          } else {
            name = arg
            value = undefined
          }
    
          instance[name] = function(d) {
            if (!arguments.length) return value;
            value = d;
            return instance;
          }; // end instance function
        }) // end for each
      } // end setup
      setup(publicVariables)
      return instance; 
    }
    
    var test = myClosure().v1(10).v2(2)
    console.log(test.v1(), test.v2(), test.v3())
    test.v1(20).v3(1)
    console.log(test.v1(), test.v2(), test.v3())
    
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!