JavaScript: Property descriptors are ignored when passed to a function

66 Views Asked by At

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.

2

There are 2 best solutions below

1
Turtlefight On

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);

0
Bergi On

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.