假设我有这两个功能:
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
的来源。
答案 0 :(得分:5)
对fn
参数的赋值只是使该标识符指向匿名函数,外部作用域中的foo
不受影响。
当您将对象作为参数传递时,可以说“引用按值传递”。该分配仅替换fn
标识符所指的位置。
这就是evaluation strategy在JavaScript中的工作方式。
在fnChanger
函数中赋值之前,两个标识符(全局foo
和fn
参数)指向同一个函数对象:
--------------------------------------------- foo -----> |function foo { sys.print('Un changed!'); } | --------------------------------------------- ^ | fn -------------
分配后,fn
将只指向新功能:
--------------------------------------------- foo -----> | function foo { sys.print('Unchanged!'); } | --------------------------------------------- --------------------------------------- fn ------> | function { sys.print('Changed!'); } | ---------------------------------------
你怎么能改变它?
好吧,假设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
值(引用此作用域中的Global对象)和属性名称,允许您创建分配给GlobalObject.foo
标识符。
如果代码在函数内部,我们就无法获得基础对象,因为在这个“函数代码执行上下文”中,函数声明(变量声明和函数形式参数也)绑定为不可访问对象的属性,称为变量对象(这些变量对象的链,形成范围链),如果是这种情况,唯一的解决方法是使用eval
。
更多信息:
答案 1 :(得分:3)
由于@CMS指出由于范围而无法在函数内分配它。但是你可以像这样重新分配它:
var fnChanger = function() {
return function() {
alert('changed!');
}
}
var foo = function() {
alert('Unchanged');
}
foo = fnChanger();
foo();
答案 2 :(得分:0)
有一个优雅的方法来解决它
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!
简短说明:
foo_holder
传递给 fnChange
。foo_holder["fn"]
中的元素重新分配给新值。这将更改内部引用指向的位置,而不是创建新引用。答案 3 :(得分:0)
在 Javascript 中,函数是可以被视为另一个变量的第一类对象。但是要使函数返回其结果,必须先调用它。
当您调用 fnChanger(foo) 时,fn 变量实际上会被 foo() 覆盖。
但是您没有得到结果,因为该函数从未被调用过。尝试返回它并调用如下所示,您将获得所需的答案。
function fnChanger(fn) {
fn = function() {
console.log('Changed!');
}
return fn;
}
function foo() {
console.log('Unchanged');
}
fnChanger(foo)();
foo();