简体   繁体   中英

Inner function does not return changes to variable assigned in outer function

I am attempting to modify the masterCounter variable within the timeKeyAdditionCheck function. Within the timeKeyAdditionCheck function, I successfully assign a value to masterCounter , but this change is not reflected within the scope of getEventsWithTime . When timeKeyAdditionCheck is complete, the value of masterCounter returns to null.

What changes do I need to make with timeKeyAdditionCheck function?

let masterCounter = null;
let userTracker = {}; 

let timeKeyAdditionCheck = ('hour') => {
    assert((range == 'minute' || range == 'hour'), "In calcArrayof... range value needs to equal 'minute' or 'hours'")
    
    if (masterCounter == null) {
        masterCounter = [{timerange: event.timestamp, totalusercount: 0, totalvalidatorcount: 0, totaletherdeposited: 0}]
    }
    if (event.timestamp > (masterCounter[masterCounter.length - 1] + 3599)) {
        
            let differenceInTime = event.timestamp - (masterCounter[masterCounter.length - 1] + 3599);
            let timeKeysNeeded = Math.ceil(differenceInTime / 3600);
        
            i = 0;
            while (i < timeKeysNeeded) {
                
                let newEntry = masterCounter[masterCounter.length - 1];
                newEntry.timerange = newEntry.timerange + 3600;
                masterCounter.push(newEntry);
                i++;
            }
        }
}
(async () => {
    let events = await getEventsWithTime(3085928,3089928);
    
    for (event of events) {
        timeKeyAdditionCheck('hour');
        checkNewUsers();
        addValidatorsAndEth();    
    }

    convertToCsv(masterCounter)
    console.log(masterCounter)
  })()

Because masterCounter is not declared within timeKeyAdditionCheck (it's assigned there, but not declared there), masterCounter is implicitly declared as a Global variable. But, in getEventsWithTime , you do declare masterCounter so that declaration "hides" the Global one and is treated as a completely separate variable.

You need masterCounter to be declared in a higher scope than either of the two functions so that both can have access to it, or you could pass masterCounter to the getEventsWithTime function as an argument.

 // By declaring the variable in a higher scope than either of the functions // that need access to it, both can find it and use it. let masterCounter = null // later turns into an array let timeKeyAdditionCheck = (event, range, masterCounter) => { assert((range == 'minute' || range == 'hour'), "In calcArrayof... range value needs to equal 'minute' or 'hours'") if (masterCounter == null) { masterCounter = [{timerange: event.timestamp, totalusercount: 0, totalvalidatorcount: 0, totaletherdeposited: 0}] } if (event.timestamp > (masterCounter[masterCounter.length - 1] + 3599)) { let differenceInTime = event.timestamp - (masterCounter[masterCounter.length - 1] + 3599); let timeKeysNeeded = Math.ceil(differenceInTime / 3600); i = 0; while (i < timeKeysNeeded) { let newEntry = masterCounter[masterCounter.length - 1]; newEntry.timerange = newEntry.timerange + 3600; masterCounter.push(newEntry); i++; } } } let getEventsWithTime = async (firstBlock, lastBlock, range) => { try { let userTracker = {}; let events = await depositContract.getPastEvents('DepositEvent', {fromBlock: firstBlock, toBlock: lastBlock}) // 2845084 2846000 for (event of events) { let results = await web3.eth.getBlock(event.blockNumber); event.timestamp = results.timestamp; timeKeyAdditionCheck(event, range, masterCounter); checkNewUsers(event, userTracker, masterCounter); addValidatorsAndEth(event, userTracker, masterCounter); } convertToCsv(masterCounter) console.log(masterCounter) } catch(error) { console.log(error); } }

Also, see this post of mine , which explains the "scope chain" and illustrates this issue in more detail.

You should declare masterCounter in a scope which contains both functions that are going to use it.

For example, you could declare masterCounter immediately preceding when you declare either function (assuming they are in the same scope).

A sign that your declarations are incorrect is the check to see if masterCounter is null. For it to be shared outside of these functions, it can never be null when the function attempts to access or set it.

The reason I wasn't getting the expected output for masterCounter was because, in the timeKeyAdditionCheck function, I thought I was making a copy of the object in the masterCounter array, but I actually created a reference instead. Here is the moment in my code when I unintentionally created a reference instead of a copy:

let newEntry = masterCounter[masterCounter.length - 1];

When I thought I was adding a unique object to the array, I was instead adding the reference to that same object at the end of the array.

I fixed it using the following code:

while (i < timeKeysNeeded) {
                
   let lastObjectRef = masterCounter[masterCounter.length - 1];
   let newEntry = Object.assign({}, lastObjectRef)
   newEntry.timerange = newEntry.timerange + 60;
   masterCounter.push(newEntry);
   i++;
}

I used Object.assign() to create a copy of the last object in the array instead of creating another reference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM