4

我想将函数引用“go”传递给另一个函数“redefineFunction”,并在“redefineFunction”中重新定义“go”。根据 Johnathan Snook 的说法,函数是通过引用传递的,所以我不明白为什么当我将 go() 传递给 redefineFunction() 时不会重新定义它。有什么我想念的吗?

// redefineFunction() will take a function reference and
// reassign it to a new function
function redefineFunction(fn) {
    fn = function(x) { return x * 3; };
}

// initial version of go()
function go(x) {
    return x;            
}

go(5); // returns 5

// redefine go()
go = function(x) {
     return x * 2;        
}

go(5); // returns 10

// redefine go() using redefineFunction()
redefineFunction(go);

go(5); // still returns 10, I want it to return 15

​ 或者看我的小提琴http://jsfiddle.net/q9Kft/

4

8 回答 8

8

学究会告诉你 JavaScript 是纯值传递,但我认为这只会使问题变得模糊,因为传递的(当传递对象时)是对该对象的引用。因此,当您修改对象的属性时,您正在修改原始对象,但如果您完全替换变量,您实际上放弃了对原始对象的引用。

如果你试图在全局范围内重新定义一个函数:(这是一件坏事;你通常不应该有全局函数)

function redefineFunction(fn) {
    window[fn] = function() { ... };
}

redefineFunction('go');

否则,您必须返回新函数并在调用方分配。

function makeNewFunction() {
    return function() { ... };
}

go = makeNewFunction();
于 2012-05-10T14:01:32.503 回答
2

JS 中没有任何内容是“通过引用传递”的。有时会传递引用,但它们是按值传递的。区别是微妙的,但很重要——一方面,这意味着虽然你可以随意操作一个引用的对象,但你不能以任何调用者的方式可靠地替换对象(阅读:改变引用本身)请参阅(因为引用是按值传递的,因此只是原始引用的副本;尝试重新分配它会以与 arg 是数字或字符串相同的方式中断)。

一些牛仔会假设您正在重新定义一个全局函数并按名称混淆它以绕过按值传递的限制,但这会在您决定不在所有地方都有全局变量时引起问题。

真正的解决方案:返回新函数,让调用者决定如何处理它。(我认为从使用它们的代码中重新定义函数无论如何都是一个非常糟糕的设计决定,但是嗯。我想这可能是有原因的......)

于 2012-05-10T13:59:43.770 回答
1

斯诺克错了。而且我认为指出 JavaScript 中的一切都是按值传递的一点也不迂腐 (@josh3736 :)。Snook 的文章完全错了。传递原语和传递对象的工作方式完全相同。这些是等价的:

var x = 2;
var y = x;
y = 3; //x is STILL 2.

function stuff(y){
  y = 3; //guess what. x is STILL 2
}

stuff(x);

//////////////////

var x = {stuff: 2};
var y = x;
y = {stuff: 3}; //x.stuff is STILL 2

function stuff(y){
  y = {stuff: 3}; //guess what. x.stuff is STILL 2
}

stuff(x);

这个很重要。Java、C# 和大多数语言都以这种方式工作。这就是为什么当你真的想通过引用传递某些东西时,C# 有一个“ref”关键字。

于 2012-05-10T14:15:43.507 回答
0

您不能从函数内部修改变量,因此快速解决方法是返回值并将其分配到函数外部,如下所示

// log() just writes a message to the text area
function log(message) {
    $('#output').val($('#output').val() + message + "\n");
}

// redefineFunction() will take a function reference and
// reassign it to a new function
function redefineFunction() {
   newvalue = function(x) { return x * 3; };
   return newvalue;
}

// initial version of go()
function go(x) {
    return x;            
}

log(go(5)); // returns 5

// redefine go()
go = function(x) {
     return x * 2;        
}

log(go(5)); // returns 10

// redefine go() using redefineFunction()
go = redefineFunction();

log(go(5)); // returns 10, I want it to return 15
于 2012-05-10T14:00:21.917 回答
0

我相信函数是“按值传递的”。如果您将其放入log(f(5));函数redefineFunction中,它将输出 15,但log(go(5))之后调用时会输出 10。

如果您更改redefineFunction为返回该函数,然后将其分配给 go ( go = redefineFunction()),它将按您的预期工作。

于 2012-05-10T14:05:21.597 回答
0

这相当于询问您是否可以通过将任何变量作为参数传递给某个函数来重新定义它。不,您可以重新分配它,呃,重新分配它。在这种情况下,如果你redefineFunction返回一个函数,你可以简单地将它分配给go

function redefineFunction() {
    var fn = function(x) { return x * e; };
    return fn;
}

function go(x) {
    return x;
}

go = redefineFunction();

go(5); // return 15
于 2012-05-10T14:05:49.637 回答
0

这是在 Firefox 中工作的:

function redefineFunction(fn) {
    window[fn] = function(x) {
        return x * 3;
    }
};

function go(x) {
    return x;
};

alert(go(5));

go=function(x) {
    return x * 2;
}

alert(go(5));

redefineFunction('go');

alert(go(5));


秘密是一个名为 go 的全局函数也被称为 window.go 和 window["go"]。
这也可以用于样式:element.style["overflow"] = "hidden" 和属性:
element["value"] = "hello there"。这是一个非常有用的知识。

于 2012-05-10T14:15:29.683 回答
0

为什么不使用对象?像这样的东西:

var o = {
    go: function( x ) {
        return x;
    },

    redefineFunction: function ( fn ) {
        if (typeof fn === 'function') {
            this.go = fn;
        }
    }
}

console.log(o.go(5)); // return 5

var fn = function (x) {
  return x * 2;
};

o.redefineFunction(fn);

console.log(o.go(5));​ //return 10

希望能帮助到你!

于 2012-05-10T14:17:16.043 回答