我可以从另一个函数中重新定义JavaScript函数吗?

时间:2012-05-10 13:52:47

标签: javascript function scope

我想将函数引用“go”传递给另一个函数“redefineFunction”,并在“redefineFunction”中重新定义“go”。根据Johnathan Snook的说法,函数是passed by reference,所以当我将它传递给redefineFunction()时,我不明白为什么go()没有被重新定义。有什么东西我不见了吗?

// 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/

8 个答案:

答案 0 :(得分:8)

Pedants会告诉你JavaScript是纯粹的值传递,但我认为only clouds the issue传递(传递对象时)是引用到那个对象。因此,当您修改对象的属性时,您正在修改原始对象,但如果您完全替换该变量,那么您实际上是放弃了对原始对象的引用。

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

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

redefineFunction('go');

否则,您必须返回新功能并在主叫方分配。

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

go = makeNewFunction();

答案 1 :(得分:2)

JS中没有“通过引用传递”。有时会传递引用,但它们是按值传递的。差别很微妙,但很重要 - 首先,它意味着虽然您可以随意操作引用的对象,但您无法可靠地替换对象(读取:更改引用本身)以任何方式调用者将看到(因为引用是通过值传递的,因此仅仅是原始引用的副本;尝试重新分配它会以与arg是数字或字符串相同的方式中断)。 / p>

有些牛仔会假设你正在重新定义一个全局函数,并通过名称搞乱它来绕过传值的限制,但这会导致第二个问题,即你决定不使用全局函数。

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

答案 2 :(得分:1)

Snook错了。而且我认为(@ josh3736 :)指出JavaScript中的所有内容都是按价值传递的。 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#和MOST语言以这种方式工作。这就是为什么当你真正希望通过引用传递某些内容时,C#有一个“ref”关键字。

答案 3 :(得分: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

答案 4 :(得分:0)

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

如果您更改redefineFunction以返回该功能,然后将其指定为go(go = redefineFunction()),它将按预期工作。

答案 5 :(得分: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

答案 6 :(得分: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”] =“你好那里”。 这是一个非常有用的知识。

答案 7 :(得分: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

希望它有所帮助!