【问题标题】:Javascript: Re-assigning a function with another functionJavascript:用另一个函数重新分配一个函数
【发布时间】:2011-04-30 12:13:58
【问题描述】:

假设我有这两个功能:

function fnChanger(fn) {
    fn = function() { sys.print('Changed!'); }
}
function foo() {
    sys.print('Unchanged');
}

现在,如果我打电话给foo(),我会看到Unchanged,正如预期的那样。但是,如果我先调用fnChanger,我仍然会看到Unchanged

fnChanger(foo);
foo(); //Unchanged

现在,我假设这是因为 foo 没有通过引用传递给 fnChanger,但我可能错了。

为什么fnChanger 不将foo 改为打印Changed!
此外,我怎样才能让fnChanger 更改foo 而没有太多混乱的语法?

PS:我正在使用 node.js 来测试所有这些东西,所以这就是 sys.print 的来源。

【问题讨论】:

    标签: javascript function closures pass-by-reference


    【解决方案1】:

    fn 参数的赋值只是使该标识符指向匿名函数,外部范围内的foo 不受影响。

    当您将对象作为参数传递时,可以说“引用是按值传递的”。该赋值只是替换了fn 标识符所指的位置。

    这就是 evaluation strategy 在 JavaScript 中的工作原理。

    就在fnChanger函数中的赋值之前,两个标识符,全局foofn参数,指向同一个函数对象:

    --------------------------------------------- foo -----> |function foo { sys.print('未更改!'); } | --------------------------------------------- ^ | fn -------------

    赋值后,fn 将简单地指向新函数:

    --------------------------------------------- 富 -----> |函数 foo { sys.print('未更改!'); } | --------------------------------------------- -------------------------------------- fn ------> |函数 { sys.print('已更改!'); } | --------------------------------------

    你怎么能改变它?

    好吧,假设 foo 是全局范围内的函数,您可以这样做:

    function fnChanger(obj, name) {
        obj[name] = function() { sys.print('Changed!'); };
    }
    
    function foo() {
        sys.print('Unchanged');
    }
    
    fnChanger(this, 'foo');
    foo(); // Changed!
    

    上面的方法会起作用,因为在fnChanger 函数中,我们需要一个基础对象和一个属性名称,在全局执行上下文中声明的函数被绑定为属性全局对象,因此我们可以用这种方式重新分配它的值。

    fnChanger(this, 'foo'); 行也应该在全局范围内执行,它将传递 this 值(指的是此范围内的全局对象)和属性名称,允许您对 @ 进行赋值987654335@标识符。

    如果该代码在函数内部,我们就无法获得基础对象,因为在这个“函数代码执行上下文”中,函数声明(变量声明和函数形式参数也是)被绑定为不可访问对象的属性,称为变量对象(这些变量对象的链,形成范围链),如果是这种情况,唯一的解决方法是使用eval.

    更多信息:

    【讨论】:

    • 是的,我开始怀疑这就是正在发生的事情。感谢您的澄清和链接-我不知道该怎么称呼它或它是如何工作的。我该如何解决这个问题?
    • 好的,我喜欢这种方法。不像我想的那么混乱:传递一个包含要更改的函数的对象。
    【解决方案2】:

    正如@CMS 指出的那样,由于范围的原因,您不能在函数内分配它。但是,您可以像这样重新分配它:

    var fnChanger = function() {
      return function() {
          alert('changed!');
      }
    }
    
    var foo = function() {
      alert('Unchanged');
    }
    
    foo = fnChanger();
    foo();
    

    example

    【讨论】:

    • 是的,想过。不过,我很犹豫是否要在真实代码中返回。一方面,它更干净,但另一方面,它与函数的实际作用不太匹配。
    【解决方案3】:

    有一种优雅的方式来解决它

    function fnChanger(fn_holder) {
        fn_holder["fn"] = function() { console.log('Changed!'); }
    }
    function foo() {
        console.log('Unchanged');
    }
    
    const foo_holder = {fn: foo}
    fnChanger(foo_holder);
    
    foo_holder["fn"]();  // Changed!
    

    简短说明:

    1. 将更高级别的引用 foo_holder 传递给 fnChange,就像哈希(或数组)一样。
    2. 将散列foo_holder["fn"] 中的元素重新分配为新值。这将更改内部引用指向的位置,而不是创建新引用。
    3. 那么您很高兴使用更新后的功能。

    【讨论】:

      【解决方案4】:

      在 Javascript 中,函数是可以被视为另一个变量的第一类对象。但要让函数返回其结果,必须首先调用它。

      当您调用 fnChanger(foo) 时,fn 变量实际上会被 foo() 覆盖。

      但是您没有得到结果,因为该函数从未被调用过。尝试返回它并按照下面给出的调用,您将获得所需的答案。

      function fnChanger(fn) {
        fn = function() {
          console.log('Changed!');
        }
        return fn;
      }
      
      function foo() {
        console.log('Unchanged');
      }
      
      fnChanger(foo)();
      foo();

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-24
        • 2021-12-10
        • 1970-01-01
        相关资源
        最近更新 更多