【JS】关于`引用传递`和`值传递`所踩过的坑

342 阅读2分钟

哈哈,昨天晚上debug三个小时,到晚上快11点还没搞明白是哪儿出了问题,今早一起来脑子清醒点了,一眼就看出问题所在:这喜欢捉弄人的引用传递值传递

talk is cheap, show me your code

先上代码:

const wordSquares = (words) => {
    const n = words[0].length;
    let results = [], squares = [];

    const buildTrie = (words) => {
        let root = {};

        for(let i = 0; i < words.length; i++){
            let node = root;

            for(const c of words[i]){
                if(!node[c]) node[c] = {"#": []};
                node = node[c];
                node["#"].push(i);  //?
            }
        }

        return root;
    };

    let trie = buildTrie(words);

    const getWordsWithPrefix = (prefix) => {
        let node = trie;
        for(const c of prefix){
            if(!node[c]) return [];
            node = node[c];
        }
        let ret = [];
        for(const index of node["#"]){
            ret.push(words[index]);
        }
        
        return ret;
    };

    const backtracking = (step, squares) => {
        if(step == n){
            results.push(squares); 
            /* console.log(results); */
            return;
        }

        let prefix = squares.map(word => word[step]).join("");
        let cdds = getWordsWithPrefix(prefix);

        for(const cdd of cdds){
            squares.push(cdd);
            backtracking(step + 1, squares);
            squares.pop();
        }
        
    };

    for(const word of words){
        squares = [word];
        backtracking(1, squares);
        /* console.log(results); */
    }

    return results;
};

该代码是LC-425的题解,我在做这道题的时候JS的题解只有一个(哈哈,没办法,只能说明开会员的人不多),而且解法是哈希表+DFS,但我想找一个字典树+DFS的思路。所以我就去瞧了一眼官方题解的python代码,然后根据它的逻辑重构出JS的代码。

好家伙,这一重构不要紧,很快啊,刷的干出来,但就是不给你AC,你气不气。

然后我就找bug,找了一晚上,第二天早上才发现问题所在:

const backtracking = (step, squares) => {
        if(step == n){
                results.push(squares); //我在这儿打印results,发现和预期结果是一致的,但是最后results却又不是正确结果
            /* console.log(results); */
            return;
        }

        let prefix = squares.map(word => word[step]).join("");
        let cdds = getWordsWithPrefix(prefix);

        for(const cdd of cdds){
            squares.push(cdd);
            backtracking(step + 1, squares);
            squares.pop();
        }
        
    };

我对results一个Ctrl + F,奇怪,我代码里就这个backtracking回溯函数在改变results啊,为什么结果变了啊。

。。。反正我过了好几遍逻辑最后才发现是引用传递的问题:

results.push(squares);

就是这一行代码,应该改成:

results.push([...squares]);

改成这样意味着什么,大家都懂。

哈哈,可恶,一个小问题,疏忽了啊。

数组,对象,都是引用,在赋值的时候是引用传递,它的值会变动,因为在内存中的只有一个实际的对象给你改,其他人拿到的都是引用,要各位注意。

如果还不明白,看看下面这个例子:

let a = [1,2,3], b = ["ax", "in", "g"];
a.push(b);
console.log(a, b);

b.pop();

console.log(a, b);

想想两次打印结果是啥。

哈哈,没错,a的值会随b改变。