Javascript:用另一个函数重新分配函数

时间:2021-12-23 19:42:22

Let's say I have these two functions:

假设我有这两个函数:

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

Now, if I call foo(), I see Unchanged, as expected. However, if I call fnChanger first, I still see Unchanged:

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

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

Now, I assume this is because foo is not being passed to fnChanger by reference, but I may be wrong.

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

Why does fnChanger not change foo to print Changed!?
Furthermore, how can I get fnChanger to change foo without too much messy syntax?

为什么fnChanger没有改变foo来打印改变了!?此外,如果没有太多凌乱的语法,我如何让fnChanger改变foo?

PS: I'm using node.js to test all this stuff, so that's where the sys.print comes from.

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

2 个解决方案

#1


5  

The assignment to the fn argument just makes that identifier to point to the anonymous function, foo in the outer scope is not affected.

对fn参数的赋值只是使该标识符指向匿名函数,外部作用域中的foo不受影响。

When you pass an object as an argument, one can say "references are passed by value". The assignment just replaces the location where the fn identifier refers to.

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

That's how the evaluation strategy works in JavaScript.

这就是评估策略在JavaScript中的工作方式。

Just before the assignment in the fnChanger functions, the two identifiers, the global foo and the fn argument, point to the same function object:

就在fnChanger函数中赋值之前,两个标识符global foo和fn参数指向同一个函数对象:

                ---------------------------------------------
    foo ----->  |function foo { sys.print('Un changed!'); } |
                ---------------------------------------------
                   ^
                   |
    fn -------------

After the assignment, fn will simply point to the new function:

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

                ---------------------------------------------
    foo ----->  | function foo { sys.print('Unchanged!'); } |
                ---------------------------------------------

                ---------------------------------------
    fn ------>  | function { sys.print('Changed!'); } |
                ---------------------------------------

How could you change it?

你怎么能改变它?

Well, assuming that foo is a function in the global scope, you could do something like this:

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

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

function foo() {
    sys.print('Unchanged');
}

fnChanger(this, 'foo');
foo(); // Changed!

The above will work because in the fnChanger function, we require a base object and a property name, functions declared in the global execution context are bound as properties of the Global object, therefore we can re-assign its value in that way.

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

The line fnChanger(this, 'foo'); should be executed also in the Global scope, it will pass the this value (which refers to the Global object in this scope) and a property name, allowing you to make an assignment to the GlobalObject.foo identifier.

线fnChanger(这个,'foo');也应该在Global范围内执行,它将传递this值(引用此范围中的Global对象)和属性名称,允许您对GlobalObject.foo标识符进行赋值。

If that code were inside a function, there is no way we can get a base object, because in this "Function Code Execution Context", function declarations (variable declarations and function formal parameters also) are bound as properties of a non-accessible object, called the Variable Object (a chain of these Variable Objects, forms the Scope Chain), and if it were the case, the only workaround would be to use eval.

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

More info:

#2


3  

As @CMS pointed out you cannot assign it within the function due to the scope. However you could reassign it like this:

由于@CMS指出由于范围而无法在函数内分配它。但是你可以像这样重新分配它:

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

var foo = function() {
  alert('Unchanged');
}

foo = fnChanger();
foo();

example

#1


5  

The assignment to the fn argument just makes that identifier to point to the anonymous function, foo in the outer scope is not affected.

对fn参数的赋值只是使该标识符指向匿名函数,外部作用域中的foo不受影响。

When you pass an object as an argument, one can say "references are passed by value". The assignment just replaces the location where the fn identifier refers to.

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

That's how the evaluation strategy works in JavaScript.

这就是评估策略在JavaScript中的工作方式。

Just before the assignment in the fnChanger functions, the two identifiers, the global foo and the fn argument, point to the same function object:

就在fnChanger函数中赋值之前,两个标识符global foo和fn参数指向同一个函数对象:

                ---------------------------------------------
    foo ----->  |function foo { sys.print('Un changed!'); } |
                ---------------------------------------------
                   ^
                   |
    fn -------------

After the assignment, fn will simply point to the new function:

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

                ---------------------------------------------
    foo ----->  | function foo { sys.print('Unchanged!'); } |
                ---------------------------------------------

                ---------------------------------------
    fn ------>  | function { sys.print('Changed!'); } |
                ---------------------------------------

How could you change it?

你怎么能改变它?

Well, assuming that foo is a function in the global scope, you could do something like this:

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

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

function foo() {
    sys.print('Unchanged');
}

fnChanger(this, 'foo');
foo(); // Changed!

The above will work because in the fnChanger function, we require a base object and a property name, functions declared in the global execution context are bound as properties of the Global object, therefore we can re-assign its value in that way.

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

The line fnChanger(this, 'foo'); should be executed also in the Global scope, it will pass the this value (which refers to the Global object in this scope) and a property name, allowing you to make an assignment to the GlobalObject.foo identifier.

线fnChanger(这个,'foo');也应该在Global范围内执行,它将传递this值(引用此范围中的Global对象)和属性名称,允许您对GlobalObject.foo标识符进行赋值。

If that code were inside a function, there is no way we can get a base object, because in this "Function Code Execution Context", function declarations (variable declarations and function formal parameters also) are bound as properties of a non-accessible object, called the Variable Object (a chain of these Variable Objects, forms the Scope Chain), and if it were the case, the only workaround would be to use eval.

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

More info:

#2


3  

As @CMS pointed out you cannot assign it within the function due to the scope. However you could reassign it like this:

由于@CMS指出由于范围而无法在函数内分配它。但是你可以像这样重新分配它:

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

var foo = function() {
  alert('Unchanged');
}

foo = fnChanger();
foo();

example