1

I'm trying to build a method that will automatically create get and set functions on all properties within an object. Ideally, when somebody updates the property within an object I want to trigger dirty data to update in the interface.

Problem: when looping through the properties of the object, the set function of the last property seems to be applied to all previous properties. I cannot figure out why this occurs since the property is clearly unique in each instance (I've created a _prop version based on the original property name).

I've created a fiddle with some barebones code. https://jsfiddle.net/rcmwxzvL/6/

Here is the code for those non-fiddlers out there; this one has console commands that show the _prop values being set. Strange!

var superhero = {
        id: 0,
        firstname: 'Duck',
        lastname: 'Darkwing'
    };
    
    for (property in superhero)
    {
        var propertyName = property.toString();
    
        // Store initial value in '_var' before overwriting it with get/set
        this['_' + propertyName] = superhero[property];
    
        Object.defineProperty(superhero, propertyName, {
            set: function(value) {
                this['_' + propertyName] = value;
            },
            get: function() {
                return this['_' + propertyName];
            }
        });
    }
    console.log('--- Initial Value of test ---');
    console.log(superhero);
    console.log('-----------------------------');
    
    superhero.firstname = 'Kal';
    superhero.lastname = 'El';
    
    console.log (superhero.firstname + ' ' + superhero.lastname);

The output in the last console is: El El when it is supposed to be Kal El

The output of console.log(superhero);:

firstname: "El"
id:(...)
lastname:(...)
_firstname:"Duck"
_id:0
_lastname:"El"
get firstname:ƒ ()
set firstname:ƒ (value)
get id:ƒ ()
set id:ƒ (value)
get lastname:ƒ ()
set lastname:ƒ (value)

My end goal is to create a very simple library that can automatically data bind all properties in an object to HTML interface elements. I have the mapping piece written, I just can't get the interface to update when properties inside an object are accessed directly due to the issue above.

Thanks; appreciate any help the community can provide.

  • `var` in javascript is functionally scoped, so in your example properyName is always going to equal `lastName` after the loop. – Keith Jun 29 '18 at 15:55

1 Answers1

1

You need to change

var propertyName = property.toString();

to

let propertyName = property.toString();

otherwise whenever you update propertyName it will change that for all properties since the scope created by var allows for a single reference only (functional scope) whereas if you create it with let, each loop step will have its own reference (block scope).

var superhero = {
        id: 0,
        firstname: 'Duck',
        lastname: 'Darkwing'
    };
    
    for (property in superhero)
    {
        let propertyName = property.toString();
    
        // Store initial value in '_var' before overwriting it with get/set
        this['_' + propertyName] = superhero[property];
    
        Object.defineProperty(superhero, propertyName, {
            set: function(value) {
                this['_' + propertyName] = value;
            },
            get: function() {
                return this['_' + propertyName];
            }
        });
    }
    console.log('--- Initial Value of test ---');
    console.log(superhero);
    console.log('-----------------------------');
    
    superhero.firstname = 'Kal';
    superhero.lastname = 'El';
    
    console.log (superhero.firstname + ' ' + superhero.lastname);
connexo
  • 53,704
  • 14
  • 91
  • 128
  • Man... unreal, I've spent like four hours wracking my brain on this and you solve it in like 30 seconds. You. Are. Awesome! Sure enough... changing three characters generated the expected output. I'm still wrapping my head around the scope problem you noted, but I think now that I know what it is I can fiddle around some more to get a better grasp. Thanks again! – ImagineEverything_Brad Jun 29 '18 at 16:05