我以为我有一个this引用传递到Javascript闭包中的私有函数,我想错了

I thought I had a this reference passed into a private function in a Javascript closure, I thought wrong

本文关键字:函数 错了 Javascript 引用 this 有一个 我以为 闭包      更新时间:2023-09-26

我认为代码解释得很好。我使用闭包来保持称为reverseAll私有的方法。reverseAll是递归的,但我认为你不需要担心这个。我试图在reverseAll函数中引用this.head,但我发现它是undefined。所以我传递了一个对this.head的引用,并通过递归调用继续传递它。唉,这不是命中注定的。我可以把reverseAll方法从闭包中拉出来,我将有一个对this.head的引用。但我想知道为什么我传递的this.head引用不是"引用的副本"或"指针的副本",如果你喜欢Javascript,当你将对象传递给函数时。顺便说一下,this.headnode对象。

这里是代码(引用jQuery是因为Stackoverflow片段"IDE"失败时,行var obj = new LinkedList();,所以我添加了一个文档。准备好了,jQuery不需要任何其他原因:

function LinkedList() {
    this.head = null;
};
LinkedList.prototype = (function () {
    function reverseAll(current, prev, theHead) {
        if (!current.next) { //we have the head
            console.log('ending recursion, new head!!');
            console.log('we have a refence to this.head in theHead or so I thought:');
            console.log(theHead);
            theHead = current;
            theHead.next = prev;
            console.log('theHead has a new "pointer":');
            console.log(theHead);
            return;
        }
        var next = current.next;
        current.next = prev;
        //keep passing the theHead reference through recursion
        reverseAll(next, current, theHead);
    };
    return {
        constructor: LinkedList,
        reverse: function () {
            console.log('clone head to iterate and change');
            console.log('but also pass in reference of this.head obj as this.head is a node obj and this.head will be undefined in reverseAll()');
            var headClone = JSON.parse(JSON.stringify(this.head));
            reverseAll(headClone, null, this.head);
        }
    }
})();
LinkedList.prototype.add = function(value) {
    var node = {
        value: value,
        next: null
    };
    var current;
    if (this.head === null) {
        this.head = node;
    } else {
        current = this.head;
        while (current.next) {
            current = current.next;
        }
        current.next = node;
    }
    return node;
}
LinkedList.prototype.remove = function(node) {
    var current, value = node.value;
    if (this.head !== null) {
        if (this.head === node) {
            this.head = this.head.next;
            node.next = null;
            return value;
        }
        //find node if node not head
        current = this.head;
        while (current.next) {
            if (current.next === node) {
                current.next = node.next;
                return value;
            }
            current = current.next;
        }
    }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(function() {
    var obj = new LinkedList();
    
    for (var i = 1; i <= 10; i++) {
        obj.add(i);
    }
    console.log('about to call obj.reverse()!');
    console.log('obj.head:');
    console.log(obj.head);
    obj.reverse();
    console.log('obj instance obj.head after reverse call, it has not changed!!:');
    console.log(obj.head);
});
</script>

当前实现的实际问题在于赋值theHead = current。这对LinkedList的实例没有任何影响。一个简单的修复方法是将this作为reverseAll(current, prev, instance)的最后一个参数传递,并将有问题的赋值更改为:

instance.head = current;
current.next = prev;

然而,我相信一个更好的代码设计将有助于避免这个问题。把reverseAll放在reverse里面。首先,它属于这里,因为它没有任何其他用途,其次,您甚至不需要将this传递给它,只要使用名称替代var self = this;,就可以从闭包中使用它。在其他地方使用后一种模式是明智的,因为它有助于避免小错误:

function LinkedList() {
    this.head = null;
}
LinkedList.prototype.reverse = function() {
    var self = this;
    var reverseAll = function(current, prev) {
        var exitCondition = !current.next;
        var next = current.next;
        current.next = prev;
        if (exitCondition) {
            self.head = current;
            return;
        }
        reverseAll(next, current);
    };
    // FIXME this is ugly, but unrelated, so keep it
    var headClone = JSON.parse(JSON.stringify(self.head));
    reverseAll(headClone, null);
};
// remove and add prototypes as in the original

节点

> a = new LinkedList();
LinkedList { head: null, reverse: [Function] }
> a.add(1);
{ value: 1, next: null }
> a.add(2);
{ value: 2, next: null }
> a
LinkedList {
  head: { value: 1, next: { value: 2, next: null } },
    reverse: [Function] }
> a.reverse();
undefined
> a
LinkedList {
  head: { value: 2, next: { value: 1, next: null } },
    reverse: [Function] }
> 

您的成员值this.head将被您在返回对象中定义的函数覆盖!

head: function() 
{
  return this.head;
}

被添加到原型。

然后实例化LinkedList,原型用于扩展this。这一点。然后将Head替换为function。

最好是将函数重命名为gehead,例如