Is it possible to create a special object type which by default refers to one of its property values?

Say I created this object from a constructor function SpecialObject:

specialObj = {
  propDefault: [1, 2, 3],
  prop2: "Some string",
  prop3: function(...) {...},
  ...
}

I want that when I refer to specialObj in my code, specialObj.propDefault is retrieved instead of the entire object, e.g. I can do the below without getting a “not a function” error:

specialObj.reduce(...);

You would probably need to re- implement reduce for this special object. Generally, I’d recommend against this sort of thing though. It’s better to use myObj.arrayProp.reduce(...) or make a myObj.reduceArrayProp(...)

1 Like

You mean against re-implementing a built in method (which I understand why) or against creating this special object type (if it’s even possible)? Thanks

I’d generally be against re-implementing reduce for this special object. It’d just confuse readers.

I’d do something like

specialObj = {
  arrProp: [1, 2, 3],
  reduceArrProp: function(callback) {
    return this.arrProp.reduce(callback);
  },
  ...
}

Or however the syntax works out

1 Like

Oh I have no intention of re-implementing a built in method and was only using reduce() as an example.

I’m purely wondering if it’s possible to create an object which, when referred to, will automatically retrieve one of it property values instead the entirety of the object itself.

It could be similar to how toString() is automatically called when an object is to be represented as a text value, but in my case, I’m hoping to have perhaps the below method to be called automatically all the time:

SpecialObj.prototype.getPropDefault = function () {
  return this.propDefault;
}

I’m not aware of any such ability in JS (or other languages for that matter)

1 Like

Do you mean that you have an object called foo and if I use foo in an expression, it evaluates to one of the properties instead of the object itself?

Why? What value would that have? For that matter, how would you access the object at that point or any of the other data in it?

2 Likes

Right. It sound like the sort of feature that is cool to think about but I’m not smart enough to reason about while debugging.

Yes. Precisely.

I guess similar to how e.g. strings, numbers and arrays behave - they can be referred to directly yet they can also call their own methods.

This isn’t how strings or arrays behave though. Those are both just regular objects with methods defined on them.

OK. I just thought of a better way to describe my intention:

Say I want to add an often used function as a prototype method to the Array type but I don’t want to tamper with Array.prototype, so I create a special Array type (maybe by somehow “cloning” the entire Array prototype chain, or by adding another prototype layer down the chain, or through some other means) which behave the same as the standard Array type except I can freely change the special Array type’s prototype methods without worrying about the sort of tampering mentioned above.

Can this be done somehow?

PS Since two experienced developers don’t seem to have had this need, I realise I may be overcomplicating some rudimentary programming practice. If this is actually the case, please do tell. Thanks

Yes, you can subclass an Array to create your own array type and add any special methods you want. I could be wrong, but I think this is what you are asking?

Here’s another example.

4 Likes

Yes! This is what I’m looking for. Thank you.
BH I already know extends, so I was indeed overcomplicating the matter :sweat_smile:

Note that this is still overcomplicating things, and I don’t think is what you want. Putting aside the fact it’s very unlikely you need to do this: If you subclass Array, Array doesn’t get the stuff you attach to the new class. To use it, you would need to always use MySubclassedArray instead of Array. And re the original example, it won’t do anything if you pass it an object, it’ll still error, because Object doesn’t have the functionality you’re talking about.

But

:wink:

2 Likes

My original example is actually a worse description of my intention; my later array example better describes what I was trying to do :sweat_smile:

But proxy - neat! :+1:

There’s almost no point extending the built-in Array unless you have some very specific use-case (or just for experimentation). It’s not going to give you something particularly useful because it’s just going to be a pain to make use of it. So

class MyArray extends Array {}

There we go, a subclassed Array. However, you can’t now use [] to create your arrays, you need to do:

const myArr = new MyArray(1, 2, 3, 4, 5);

So maybe you add a function to sorta do that:

class MyArray extends Array {
  static fromArray(arr) {
    return new MyArray(...arr);
  }
}

I mean, it actually needs the constructor adjusting because if you pass fromArray an array with one element, and that element is a number n, then it’ll create you a new MyArray with n empty slots, but anyway…

Also these don’t work, you don’t get static methods inherited, you would need to reimplement them (basically what I did above)

MyArray.from([1,2,3])
MyArray.of(1, 2, 3)
MyArray.isArray([1, 2, 3])

Much easier to just polyfill:

if (!Array.prototype.destructiveFart) {
  Array.prototype.destructiveFart = function () {
    for (let i = 0; i < this.length; i++) {
      this[i] = "fart";
    }
  };
}

edit: here’s the Proxy from before as well:

function secretStuff(obj) {
    let handler = {
      get(target, propKey, receiver) {
        if (propKey in Array.prototype) {
          const defaultArr = target.default;
          return function(...args) {
            let result = target.default[propKey](...args);
            console.log(`
  I think you're trying to run an array method!
  Running ${propKey.toUpperCase()} method on the default array ${JSON.stringify(target.default)}
  
  Result: ${JSON.stringify(result)}
                                  `);
            return result;
          };
        } else {
          console.log(`
  I don't think this is an array method!
  You're probably trying to access some normal property!
  
  Result: ${JSON.stringify(target[propKey])}
                              `);
          return target[propKey];
        }
      }
    };
    return new Proxy(obj, handler);
  }
1 Like

I feel like this is a lot of work to solve a problem that … Wait, it’s not clear to me what problem this is trying to solve. It’s clear to me what problems it is creating, I just don’t understand what it is solving.

3 Likes

Yeah, I’m still unsure of what problem is trying to be solved here. I can understand the temptation to add stuff, it seems like a good idea when you first learn about it. But noone really does that now for v good reasons, not least because doing it produces really confusing code. Much easier to just write a function.

1 Like

Yeah, I can understand the motive of, “Hey, I wonder if I could do this…” That kind of curiosity can be a good thing. But it can also be a bad thing if people end up going down the wrong rabbit hole.

2 Likes

Yep. What exactly are you trying to do @gaac510 ?