1

I want to pass getters/setters to a function but can't. Is it even possible to do (or emulate) such thing in JS?

I tried just calling a function with getters/setters but it (pretty obviously) doesn't work, I tried "apply" and "call" and it still (somehow) doesn't work.

function foo(x, y) {
  var i;

  for (i = 0; i < 5; ++i)
    console.log(x, y);
}

var args = [];

Object.defineProperties(args, {
  "0": {
    "set": function() { },
    "get": Math.random
  },

  "1": {
    "set": function() { },
    "get": function() { return new Date().getMilliseconds(); }
  }
});

foo.apply(this, args);

Expected 5 different results, got 5 the same instead.

Ezechiel
  • 21
  • 1
  • 2
  • 1
    I may be misunderstanding, but it seems to me that this program will generate random values for `x` and `y` when you pass in `args` to `foo` via the `apply` method - but that once inside `foo`, those arguments are fixed, and `foo` simply prints out those fixed values 5 times. It would be more interesting to do `foo.apply(null, args)` several times in a row (here the loop inside `foo` is irrelevant), then I guess you'd get different results each time. – Robin Zigmond Jul 23 '19 at 21:33
  • btw, in ES6 it's more idiomatic to call `foo(...args)` rather than using `apply` – Robin Zigmond Jul 23 '19 at 21:42

2 Answers2

1

The problem is that .apply converts your "array" into an arguments object, so your accessors will only be evaluated once.

You can get your example working by directly passing the array to the function:

function foo(arr) {
  for (var i = 0; i < 5; ++i)
    console.log(arr[0], arr[1]);
}

var args = [];
Object.defineProperties(args, {
  "0": {
    "set": function() { },
    "get": Math.random
  },

  "1": {
    "set": function() { },
    "get": function() { return new Date().getMilliseconds(); }
  }
});

foo(args);
Turtlefight
  • 9,420
  • 2
  • 23
  • 40
  • yes, that's more or less what I was just trying to say in my comment. I hadn't experimented with the code yet to be confident enough to turn it into an answer :) – Robin Zigmond Jul 23 '19 at 21:34
0

No, this is not possible. The args array is converted to a list of the individual values in apply, then the values themselves are passed as arguments.

A function parameter never will exhibit a getter functionality. There are some horrible hacks to make identifiers in a certain scope act as getters/setters, but you should never do that and you'd need to do that inside the function anyway.

Your best bet is to expect functions for the x and y parameters, and explicitly call them inside foo.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375