内部函数不会 return 更改外部函数中分配的变量

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

我正在尝试修改 timeKeyAdditionCheck 函数中的 masterCounter 变量。在timeKeyAdditionCheck函数内,我成功给masterCounter赋值,但是这个变化并没有体现在getEventsWithTime的范围内。当timeKeyAdditionCheck完成后,masterCounter的值returns为null。

我需要对 timeKeyAdditionCheck 功能进行哪些更改?

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)
  })()

您应该在包含将要使用它的两个函数的作用域中声明 masterCounter。

例如,您可以在声明任一函数之前立即声明 masterCounter(假设它们在同一范围内)。

您的声明不正确的标志是检查 masterCounter 是否为空。为了在这些函数之外共享它,当函数尝试访问或设置它时,它永远不能为 null。

因为 masterCounter 没有在 timeKeyAdditionCheck 中声明(它在那里赋值,但没有在那里声明),所以 masterCounter 被隐式声明为全局变量。但是,在 getEventsWithTime 中,您确实声明了 masterCounter 以便该声明“隐藏”全局变量并被视为一个完全独立的变量。

您需要在比这两个函数中的任何一个都更高的范围内声明 masterCounter,以便两者都可以访问它,或者您可以将 masterCounter 传递给 getEventsWithTime用作参数。

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

此外, 解释了“范围链”并更详细地说明了这个问题。

我没有得到 masterCounter 的预期输出的原因是,在 timeKeyAdditionCheck 函数中,我认为我正在复制 masterCounter 中的对象数组,但实际上我创建了一个引用。这是我无意中创建引用而不是副本时代码中的时刻:

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

当我以为我是在向数组中添加一个唯一对象时,我却在数组末尾添加了对同一对象的引用。

我使用以下代码修复了它:

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

我使用 Object.assign() 创建数组中最后一个对象的副本,而不是创建另一个引用。