这是合法的javascript吗?将参数传递给函数并让它改变它们
Posted
技术标签:
【中文标题】这是合法的javascript吗?将参数传递给函数并让它改变它们【英文标题】:Is this legal javascript? Passing arguments to function and having it change them 【发布时间】:2011-09-19 23:38:53 【问题描述】:这合法吗?它适用于所有浏览器吗?
function func1(a, b, c)
//b == 2 here
change_em(arguments);
//b should equal 3 here
function change_em(args)
args[0] = 6;
args[1]++;
args[2] = [];
func1('foo', 2);
如果您想知道,我需要调整函数中的参数。一个宏将是完美的,除了 javascript 没有一个。正确地执行它,即将变量传递给一个函数,然后在一个对象中返回它们,然后在调用者中提取它们几乎与复制/粘贴调整函数一样多的代码。
【问题讨论】:
【参考方案1】:在 EcmaScript 3 和 EcmaScript 5 非严格模式下有效,但在 EcmaScript 5 严格模式下无效。它适用于所有现代浏览器和大多数旧浏览器。它不应该在严格模式下工作,例如在带有 "use strict"
指令的 Firefox 5 中运行时。
来自EcmaScript 5 spec 部分 10.6.11.c.ii
10.6 参数对象
...
如果 strict 为 false 并且 name 不是 mappedNames 的元素,则
将名称添加为映射名称列表的元素。
令 g 为使用参数调用 MakeArgGetter 抽象操作的结果 名称和环境。
令 p 为使用参数调用 MakeArgSetter 抽象操作的结果 名称和环境。
调用 map 的 [[DefineOwnProperty]] 内部方法传递 ToString(indx), 属性描述符 [[Set]]: p, [[Get]]: g, [[Configurable]]: true, false as 论据。
基本上,arguments
对象为每个索引获取一个设置器,以便分配给 arguments[i]
会更改位置 i
处的命名参数的值。规范中有一种语言,反之亦然。
这应该在任何解释器中都可以在非严格模式下工作
(function (x)
alert("x=" + x + ", arguments[0]=" + arguments[0]); // Both should be 0
arguments[0] = 1;
alert("x=" + x + ", arguments[0]=" + arguments[0]); // both should be 1
x = 2;
alert("x=" + x + ", arguments[0]=" + arguments[0]); // both should be 2
)(0);
但是,如果您在 Firefox 5 上使用 use strict 指令运行上述内容,您会得到不同的行为:
(function (x)
"use strict";
alert("x=" + x + ", arguments[0]=" + arguments[0]); // Both should be 0
arguments[0] = 1;
alert("x=" + x + ", arguments[0]=" + arguments[0]); // x=0, arguments[0]=1
x = 2;
alert("x=" + x + ", arguments[0]=" + arguments[0]); // x=2, arguments[0]=1
)(0);
【讨论】:
+1,但最好有一些适用标准的链接 @mike 哇,真快!也很棒的解释,我们中的一些凡人需要它。 ;) @James,是的,规范的带注释的 html 版本做得很好,很容易链接到。 @mike 因此在 OP 示例中,它必须使用arguments[1]
在 change_em()
之后引用 b
或设置 b = arguments[1]
(对于严格模式)。对吗?
@Ariel,不。除了将eval
用作穷人的宏系统外,没有办法做这样的事情。 global_func_code = "(0, function (x) return x + y; )"
然后在要包含new_func
的函数中执行var new_func = eval(global_func_code);
。请注意,0,
是为了解决与 eval
返回 undefined 相关的 IE 错误,而***内容可被视为函数声明或函数表达式。【参考方案2】:
arguments
是一个类似数组的对象,但仍然是一个对象。因此,当您将它作为参数传递给另一个函数时,它将通过引用传递。因此,当您改变任何值时,它们也会在原始 arguments
对象中发生变化。因此,这将按照您的建议进行。据我所知,所有浏览器都支持通过引用传递对象,但是在 EcmaScript 5 严格模式下,参数对象索引命名属性不再动态映射到命名形式参数,因此这不起作用。
【讨论】:
【参考方案3】:请参阅下面的编辑 - 这不适用于这个问题,但仍然是正确的: 在 JavaScript 中,只有复杂类型(对象和数组)通过引用传递。原始类型(字符串、数字和布尔值)按值传递;更改参数只会影响本地函数中的该变量。
var primitive = 1;
var complex = prop: 1 ;
function func1()
change(primitive, complex);
// primitive == 1
// complex == prop: 2
function change(a,b)
a++;
b.prop++;
编辑:我错过了您正在传递
arguments
对象。 A quick test 在 Chrome 13、IE 9、Firefox 4 和 Opera 10.62 中产生相同的结果。
【讨论】:
请再次阅读我的代码。我不是在传递原始类型,而是在传递参数对象。 @Ariel:哎呀,错过了;对不起。【参考方案4】:是的,其中“所有浏览器”是现代、启用 Javascript 的浏览器的合理列表。
【讨论】:
【参考方案5】:因为在调用func1()
时没有传入c
,所以不会包含在参数中。因此在change_em()
中设置args[2] = []
不会同时在父函数中设置c
。
【讨论】:
以上是关于这是合法的javascript吗?将参数传递给函数并让它改变它们的主要内容,如果未能解决你的问题,请参考以下文章