20

This is my use case

getSomeFields(persons, fields){

    let personsWithSpecificFields = [];

    _.each(persons, (person) => {

        let personSpecificFields = {};

        _.each(fields, (field) => {
            // here im thinking to modify the field to match the method name 
            // ( if something like __call as in php is available)
            // e.g. field is first_name and i want to change it to getFirstName
            personSpecificFields[field] = person[field]();

        });

        personsWithSpecificFields.push(personSpecificFields);
    });

    return personsWithSpecificFields;
}

Here is my person class

import _ from 'lodash';

export default class Person{

    // not working..
    __noSuchMethod__(funcName, args){
        alert(funcName);
    }

    constructor( data ){
        this.init(data);
    }

    init(data) {
        _.each(data, (value, key) => {
           this[key] = value;
        });
    }
}

I have gone through Monitor All JavaScript Object Properties (magic getters and setters), tried to implement this JavaScript getter for all properties but no luck.

I know i can do this by just writing another method which will transform my first_name to getFirstName and give it a shot. But is there any way to do this in ECMA-6 way like in class.

thanks.

Community
  • 1
  • 1
rummykhan
  • 2,603
  • 3
  • 18
  • 35
  • An object instance is simply any object. Functions are objects. As such, functions can also have properties, which can also be other methods. If you want a "callable object", make it a function. – deceze Feb 15 '17 at 08:39
  • Good: You searched SO for other solutions. Bad: You found one and stopped reading after the first answer. When you do ES6 anyway, try the `Proxy` solution. – Boldewyn Feb 15 '17 at 08:45
  • @Boldewyn let me try it sir, – rummykhan Feb 15 '17 at 08:46
  • [mdn: __NoSuchMethod__](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/noSuchMethod) is obsolete – barbsan Feb 15 '17 at 08:46

2 Answers2

43

You can use a proxy to detect access to a property that your object does not have, and deal with it -- this comes close to PHP's __call:

var person = new Person();
// Wrap the object in a proxy
var person = new Proxy(person, {
    get: function(person, field) {
        if (field in person) return person[field]; // normal case
        console.log("Access to non-existent property '" + field + "'");
        // Check some particular cases:
        if (field == 'first_name') return person.getFirstName;
        // ...
        // Or other cases:
        return function () {
            // This function will be executed when property is accessed as a function
        }
    }
});

You could even do this in the constructor of your class:

class Person {
    constructor(data) {
        this.init(data);
        return new Proxy(this, {
            get: function(person, field) {
                if (field in person) return person[field]; // normal case
                console.log("Access to non-existent property '" + field + "'");
                // Check some particular cases:
                if (field == 'first_name') return person.getFirstName;
                // ...
                // Or other cases:
                return function () {
                    // This function will be executed when property is accessed as a function
                    return 15; // example
                }
            }
        });
    }
    // other methods ...
    //
}

The nice thing about proxies is that the returned object is still considered an instance of the original class. With the above code, the following will be true:

new Person() instanceof Person
Dillan Wilding
  • 1,030
  • 2
  • 12
  • 28
trincot
  • 317,000
  • 35
  • 244
  • 286
  • sir, get is working fine for fields but not for methods – rummykhan Feb 15 '17 at 09:59
  • It works also for methods, but be careful to not call them in the proxy, but to return a function reference only. For instance, note how I did not add parentheses after `person.getFirstName` in the example code. Methods are in essence also properties, they just happen to be of the function type. – trincot Feb 15 '17 at 10:09
2

There are no special __methods() in Javascript like in PHP, so all you have are those getters, setters, toString() and valueOf().

You could give Object.defineProperty() a shot, because with that you can dynamically create getters like so:

Object.defineProperty(obj, 'first_name', {
   get: function () { return … }
});

mdn

The result is similar to:

var obj = {
  get first_name () { return … }
}

If you need to call method of an object, you can also do it like that:

var prop = 'getFirstName',
    result = obj[prop]();

What also can be done in a for loop.

philipp
  • 15,947
  • 15
  • 61
  • 106