【问题标题】:Javascript Function-Pointer AssignmentJavascript 函数指针赋值
【发布时间】:2011-01-20 12:42:55
【问题描述】:

考虑这个 javascript 代码:

var bar = function () { alert("A"); }
var foo = bar;
bar = function () { alert("B"); };
foo();

运行此代码时,我得到“A”。这种行为是 javascript 规范的一部分吗?我可以依赖它吗?

【问题讨论】:

    标签: javascript function-pointers


    【解决方案1】:

    是的,这是预期和设计的。

    您的问题基本上是:foo 是否将 bar 引用为另一种语言的指针或引用?

    答案是否定的:分配时bar被分配给foo

    【讨论】:

    • 当函数不是原始类型时,为什么要传递值的副本?
    • 只是为了澄清这个答案的最后一句话,记住'bar的值'是'指向函数的指针',而不是函数本身。因此,在foo = bar 之后, foo 接收到该指针的按值复制,因此 foo 和 bar 都指向独立函数对象。
    【解决方案2】:

    这是将变量分配给未命名的函数,而不是指向函数的指针

    【讨论】:

      【解决方案3】:

      是的,您已经创建了指向原始“A”函数的指针。当您重新分配 bar 时,您正在重新分配它,但您仍然会单独留下对旧函数的任何引用。

      所以要回答您的问题,是的,您可以信赖它。

      【讨论】:

        【解决方案4】:

        是的,变量引用函数这一事实没有什么特别之处,不涉及别名。

        var bar = 1;
        var foo = bar;
        bar = "something entirely different";
        // foo is still 1
        

        【讨论】:

          【解决方案5】:

          是的,这是正确的行为。

          //create variable bar and assign a function to it
          var bar = function () { alert("A"); }
          //assign value of bar to the newly created variable foo
          var foo = bar;
          //assign a new function to the variable bar
          //since foo and bar are not pointers, value of foo doesn't change
          bar = function () { alert("B"); };
          //call the function stored in foo
          foo();
          

          【讨论】:

            【解决方案6】:

            那些不是函数指针(JS 本身没有指针)。 JS 中的函数可以是匿名的,并且是第一类对象。因此

            function () { alert("A"); }
            

            创建一个匿名函数,在执行时提醒“A”;

            var bar = function () { alert("A"); };
            

            将该函数分配给 bar;

            var foo = bar;
            

            将 foo 赋给 bar,即函数“A”。

            bar = function () { alert("B"); };
            

            将 bar 重新绑定到匿名函数“B”。这不会影响 foo 或其他函数“A”。

            foo();
            

            调用存储在foo中的函数,也就是函数“A”。


            实际上在有功能点的语言中,例如C 它也不会影响foo。我不知道你从哪里得到重新分配“B”的想法。

            void A(void) { printf("A\n"); }
            void B(void) { printf("B\n"); }
            typedef void(*fptr_t)(void);
            fptr_t foo = A;
            fptr_t bar = foo;
            bar = B;
            foo(); // should print "A"
            

            【讨论】:

              【解决方案7】:

              您将匿名函数的值分配给变量而不是指针。
              如果你想玩指针,你可以使用通过引用传递的对象,而不是复制。

              这里有一些例子:

              “obj2”是“obj1”的引用,你改变“obj2”,“obj1”就改变了。它会提醒false:

              var obj1 = {prop:true},
                  obj2 = obj1;
              obj2.prop = false;
              alert(obj1.prop);
              

              “prop”指向一个不是对象的属性,“prop”不是指向这个对象的指针而是一个副本。如果更改“prop”,则“obj1”不会更改。它会提醒true:

              var obj1 = {prop:true},
                  prop = obj1.prop;
              prop = false;
              alert(obj1.prop);
              

              “obj2”是对“obj1”的“subObj”属性的引用。如果“obj2”改变了,“obj1”就改变了。它会提醒false:

              var obj1 = {subObj:{prop:true}},
                  obj2 = obj1.subObj;
              obj2.prop = false;
              alert(obj1.subObj.prop);
              

              【讨论】:

              • 谢谢。这些例子是我想从阅读这个线程中得到的。 :-)
              【解决方案8】:

              我在这里有点晚了,但我想我还是会给出答案并充实一些东西。

              在处理规范时,在讨论 JavaScript(或 ECMAScript)的内部时,最好不要考虑指针和内存引用。变量是内部环境记录,按名称而不是内存地址存储和引用。您的赋值语句在内部和设计上所做的是查找环境记录名称(“foo”或“bar”)并将值分配给该记录。

              所以,

              var bar = function () { alert("A"); }
              

              正在为环境记录“bar”赋值(匿名函数)。

              var foo = bar;
              

              在内部调用 GetValue("bar"),它检索与记录“bar”相关联的值,然后将该值与记录“foo”相关联。因此,之后 bar 的原始值仍然可以使用,因为它现在与 foo 相关联。

              因为 JavaScript 通过字符串而不是内存地址引用正是您可以这样做的原因:

              someObject["someProperty"]
              

              根据属性名查找值。

              【讨论】:

                【解决方案9】:

                在其他示例中,没有按值传递;一切都是通过引用传递的。

                bar 和 foo 都是指针

                javascript 中所有非原始对象的变量/句柄都是指针;指针是 JavaScript 原生的,它们是默认的。

                var bar = function () { alert("A"); } //bar is a pointer to function1
                var foo = bar;  //pointer copied; foo is now also a pointer to function1
                bar = function () { alert("B"); };  //bar points to function2
                foo();  //foo is still a pointer to function1
                

                如果您认为它们是复制品,您将遇到隐藏的错误和错误。如果您使用复杂的对象,尤其如此。例如

                function person(name){this.name = name}
                var john = new person("john")
                var backup = john
                backup.name //john
                john.name = "jack"
                backup.name //jack, NOT john
                

                要真正在 javascript 中复制非原始元素,需要的工作不仅仅是 a = b。 例如:

                function person(name){  this.name = name}
                var john = new person("john")
                var backup = new Object()
                backup = JSON.parse(JSON.stringify(john))
                backup.__proto__ = john.__proto__   //useful in some cases
                john.name = "jack"
                backup.name //john
                

                【讨论】:

                • 感谢您澄清这一点,当我被告知“功能”不是原始时,我在网上搜索时感到困惑。
                • 这个答案应该可以证明为什么我们应该学习更多的计算机科学和更少的编程......
                • 这个答案是完全错误的。我知道这已经过时了,但显然人们仍然在跌跌撞撞。 Javascript 没有任何指针的概念。 Javascript 使用引用,这与指针明显不同。
                • 怎么样?例如,在 C++ 中,它们的不同之处在于您必须使用解引用运算符来获取指针指向的对象,而引用不需要解引用。但是,在 JS 中(就像在 Java 中一样),所有指针对开发人员都是隐藏的。没有明确的取消引用。所以......我不明白为什么指针和引用会有什么不同。 “在引擎盖下”它是一个值,它是对内存中具有指向的值的位置的查找。不管你称它为指针还是引用都没有关系。
                【解决方案10】:

                我想补充一点,这也适用于预定义的命名函数:

                function myfunc() { alert("A"); }
                var bar = myfunc;
                var foo = bar;
                bar = function () { alert("B"); };
                foo();
                

                这将做同样的事情,表明函数名称的行为类似于数组名称(指针)。

                【讨论】:

                  【解决方案11】:

                  对于代码中的每个 FunctionDeclaration f,按源文本顺序执行:

                  令 fn 为 FunctionDeclaration f 中的标识符。

                  令 fo 为实例化 FunctionDeclaration f 的结果,如第 13 条所述。

                  设 funcAlreadyDeclared 为调用 env 的 HasBinding 具体方法并传递 fn 作为参数的结果。

                  如果 funcAlreadyDeclared 为 false,则调用 env 的 CreateMutableBinding 具体方法,将 fn 和 configureBindings 作为参数。

                  参考文献

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-01-23
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-01-02
                    • 2021-12-14
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多