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

我可以从另一个函数中重新定义JavaScript函数吗?,javascript,function,scope,Javascript,Function,Scope,我想把一个函数引用“go”传递给另一个函数“redefineFunction”,并在“redefineFunction”中重新定义“go”。根据Johnathan Snook的说法,函数是,所以我不明白当我将go()传递到redefineFunction()时,为什么go()没有被重新定义。有什么我遗漏的吗 // redefineFunction() will take a function reference and // reassign it to a new function funct

我想把一个函数引用“go”传递给另一个函数“redefineFunction”,并在“redefineFunction”中重新定义“go”。根据Johnathan Snook的说法,函数是,所以我不明白当我将go()传递到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
​ 或者看看我的小提琴

在JS中没有任何东西是“通过引用传递的”。有时会传递引用,但它们是按值传递的。区别很微妙,但很重要——首先,这意味着尽管可以随意操作引用的对象,但调用方无法以任何方式可靠地替换对象(读取:更改引用本身)(因为引用是按值传递的,因此它只是原始引用的一个副本;尝试重新分配引用时会以与arg是数字或字符串时相同的方式中断)

一些牛仔会认为你正在重新定义一个全局函数,并通过名称来处理它,以绕过传递值的限制,但这会在你决定不使用全局函数时引发问题


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

您不能从函数内部修改变量,因此快速修复方法是返回值并在函数外部赋值,如下所示

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

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

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

否则,您必须返回新函数并在调用端赋值

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

go = makeNewFunction();

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


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

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

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

function go(x) {
    return x;
}

go = redefineFunction();

go(5); // return 15

这在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”和属性:
元素[“value”]=“你好”。
这是一个非常有用的知识。

Snook是错误的。我认为指出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”关键字,当你真的想通过引用传递某个东西的时候。

为什么不使用对象?类似这样:

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

希望有帮助!

当对象通过引用传递时,您有对对象属性的引用,但不能用新对象覆盖原始引用。@zzbov:嗯,您有对对象本身的引用(不仅仅是其属性),你只是不能覆盖对象。@josh3736,是的,基本上我想说的是,你没有指向对象的指针,你就有了对象。假设你真正想做的是替换一个全局函数。如果你想替换其他地方的某个函数,除非你也在上下文中传递。如果你想这样做的话替换一个本地定义的函数…你就完蛋了。谢谢你的通俗解释。JavaScript是一种有趣的语言,我一直在学习新的东西。“你通常不应该有全局函数”我从来没有在我的网页上真正考虑过这一点。什么是全局函数的理想替代方案?将它们封装在一个对象中?我做过一些OO JavaScript,但发现它很麻烦……也许我太习惯C#。@Walter:JS OOP需要一点时间让你头脑清醒。重要的是要意识到没有类。你可以n使构造函数的行为有点像类,语言喜欢鼓励您尝试这样做,但这种幻想在您尝试实际使用它们时就会消失。接受原型模型、duck类型和所有其他有趣的动态内容,事情就会变得更有意义。@WalterStabosz,我的首选方法是将代码封装在匿名函数中,从而限制函数/变量的作用域(考虑C#类中的私有成员)。然后,如果需要,可以将公共函数导出到全局作用域。
!function(){var private;function foo(){…};window.bar=function(){foo(private);};}()
--您可以从任何地方调用
bar()
,它将访问您的私有成员……顺便说一句,jQuery就是这样编写的。整个库都在一个自动执行的匿名函数中(其中有许多帮助函数,您无法从外部访问),它将导出
$
。在您的页面中,您无法直接访问jQuery的内部变量和函数,但可以在需要时间接调用它们
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