这是合法的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吗?将参数传递给函数并让它改变它们的主要内容,如果未能解决你的问题,请参考以下文章

如何将参数传递给控制器 构造函数?这是正确的做法吗?

将任意数量的参数传递给Javascript函数[重复]

使用AJAX将参数传递给PHP函数

如何将无限参数和一个或两个参数传递给 JavaScript 函数? [复制]

将参数传递给javascript中的函数

JavaScript:如何将多个参数传递给对象成员内的回调函数?