阅读(1246) (0)

Arguments 对象

2017-06-16 15:16:56 更新

当控制器进入到函数代码的执行环境时,将创建一个 arguments 对象,除非它作为标识符 "arguments" 出现在该函数的形参列表中,或者是该函数代码内部的变量声明标识符或函数声明标识符。

 Arguments 对象通过调用抽象方法 CreateArgumentsObject 创建,调用时将以下参数传入:func, names, args, env, strict。将要执行的函数对象作为 func 参数,将该函数的所有形参名加入一个 List 列表,作为 names 参数,将所有传给内部方法 [[Call]] 的实际参数,作为 args 参数,将该函数代码的环境变量作为 env 参数,将该函数代码是否为严格代码作为strict 参数。当 CreateArgumentsObject 调用时,按照以下步骤执行:

  1. 令 len 为参数 args 的元素个数
  2. 令 obj 为一个新建的 ECMAScript 对象
  3. 按照 8.12 章节中的规范去设定 obj 对象的所有内部方法
  4. 将 obj 对象的内部属性 [[Class]] 设置为 "Arguments"
  5. 令 Object 为标准的内置对象的构造函数 (15.2.2)
  6. 将 obj 对象的内部属性 [[Prototype]] 设置为标准的内置对象的原型对象
  7. 调用 obj 的内部方法 [[DefineOwnProperty]],将 "length" 传递进去,属性描述符为:{[[Value]]: len, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true},参数为 false
  8. 令 map 为表达式 new Object() 创建的对象,就是名为 Object 的标准的内置构造函数
  9. 令 mappedNames 为一个空的 List 列表
  10. 令 indx = len - 1
  11. 当 indx >= 0 的时候,重复此过程:令 val 为 args(维度从 0 开始的 list 列表)的第 indx 维度所在的元素调用 obj 的内部方法 [[DefineOwnProperty]],将 ToString(indx) 传递进去,属性描述符为:{[[Value]]: val, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true},参数为 false如果 indx 小于 names 的元素个数,则令 name 为 names(维度从 0 开始的 list 列表)的第 indx 维度所在的元素如果 strict 值为 false,且 name 不是一个 mappedNames 元素,则将 name 添加到 mappedNames 列表中,作为它的一个元素令 g 为调用抽象操作 MakeArgGetter 的结果,其参数为 name 和 env令 p 为调用抽象操作 MakeArgSetter 的结果,其参数为 name 和 env调用 map 对象的内部方法 [[DefineOwnProperty]],将 ToString(indx) 传递进去,属性描述符为:{[[Set]]: p, [[Get]]: g, [[Configurable]]: true},参数为 false令 indx = indx - 1
  12. 如果 mappedNames 不为空,则将 obj 对象的内部属性 [[ParameterMap]] 设置为 map将 obj 对象的内部方法 [[Get]], [[GetOwnProperty]], [[DefineOwnProperty]], [[Delete]] 按下面给出的定义进行设置。
  13. 如果 strict 值为 false,则调用 obj 对象的内部方法 [[DefineOwnProperty]],将 "callee" 传递进去,属性描述符为;{[[Value]]: func, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true},参数为 false
  14. 否则,strict 值为 true,那么令 thrower 为 [[ThrowTypeError]] 函数对象 (13.2.3)调用 obj 对象的内部方法 [[DefineOwnProperty]],将 "caller" 传递进去,属性描述符为 :{[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},参数为 false调用 obj 对象的内部方法 [[DefineOwnProperty]],将 "callee" 传递进去,属性描述符为 :{[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},参数为 false
  15. 返回 obj

 抽象操作 MakeArgGetter 以字符串 name 和环境记录 env 作为参数被调用时,会创建一个函数对象,当执行完后,会返回在 env 中绑定的 name 的值。执行步骤如下:

  1. 令 body 为字符 "return ",name,";" 的连接字符串
  2. 返回一个按照 13.2 章节中描述的方式创建的函数对象,它不需要形参列表,以 body 作为它的 FunctionBody,以 env 作为它的 Scope,并且 Strict 值为 true

 抽象操作 MakeArgSetter 以字符串 name 和环境记录 env 作为参数被调用时,会创建一个函数对象,当执行完后,会给在 env 中绑定的 name 设置一个值。执行步骤如下:

  1. 令 param 为 name 和字符串 "_arg" 的连接字符串
  2. 令 body 为字符串 " = ;";将 替换为 name 的值,将 替换为 param 的值
  3. 返回一个按照 13.2 章节中描述的方式创建的函数对象,以一个只包含字符串 param 的 list 列表作为它的形参,以 body 作为它的函数体(FunctionBody),以 env 作为它的Scope,并且 Strict 值为 true

 当 arguments 对象的内部方法 [[Get]] 在一个非严格模式下带有形参的函数中,在一个属性名为 P 的条件下被调用时,其执行步骤如下:

  1. 令 map 为 arguments 对象的内部属性 [[ParameterMap]]
  2. 令 isMapped 为 map 对象的内部方法 [[GetOwnPropery]] 传入参数 P 的执行结果
  3. 如果 isMapped 值为 undefined,则令 v 为 arguments 对象的内部默认的 [[Get]] 方法(8.12.3),传入参数 P 的执行结果如果 P 为 "caller",且 v 为严格模式下的 Function 对象,则抛出一个 TypeError 的异常返回 v
  4. 否则,map 包含一个 P 的形参映射表返回 map 对象的内部方法 [[Get]] 传入参数 P 的执行结果

 当 arguments 对象的内部方法 [[GetOwnProperty]] 在一个非严格模式下带有形参的函数中,在一个属性名为 P 的条件下被调用时,其执行步骤如下:

  1. 令 desc 为 arguments 对象的内部方法 [[GetOwnPropery]](8.12.1)传入参数 P 的执行结果
  2. 如果 desc 为 undefined,返回 desc
  3. 令 map 为 arguments 对象内部属性 [[ParameterMap]] 的值
  4. 令 isMapped 为 map 对象的内部方法 [[GetOwnPropery]] 传入参数 P 的执行结果
  5. 如果 isMapped 的值不是 undefined,则将 desc 的值设置为 map 对象的内部方法 [[Get]] 传入参数 P 的执行结果
  6. 返回 desc

 当 arguments 对象的内部方法 [[DefineOwnProperty]] 在一个非严格模式下带有形参的函数中,在一个属性名为 P,属性描述符为 Desc,布尔标志为 Throw 的条件下被调用时,其执行步骤如下:

  1. 令 map 为 arguments 对象的内部属性 [[ParameterMap]] 的值
  2. 令 isMapped 为 map 对象的内部方法 [[GetOwnPropery]] 传入参数 P 的执行结果
  3. 令 allowed 为 arguments 对象的内部方法 [[DefineOwnPropery]](8.12.9)传入参数 P,Desc,false 的执行结果
  4. 如果 allowed 为 false,则如果 Throw 为 true,则抛出一个 TypeError 的异常,否则,返回 false
  5. 如果 isMapped 的值不为 undefined,则如果 IsAccessorDescriptor(Desc) 为 true,则调用 map 对象的内部方法 [[Delete]],传入 P 和 false 作为参数否则如果 Desc.[[Value]] 存在,则调用 map 对象的内部方法 [[Put]],传入 P,Desc.[[Value]] 和 Throw 作为参数如果 Desc.[[Writable]] 存在,且其值为 false,则调用 map 对象的内部方法 [[Delete]],传入 P 和 false 作为参数
  6. 返回 true

 当 arguments 对象的内部方法 [[Delete]] 在一个非严格模式下带有形参的函数中,在一个属性名为 P,布尔标志为 Throw 的条件下被调用时,其执行步骤如下:

  1. 令 map 为 arguments 对象的内部属性 [[ParameterMap]] 的值
  2. 令 isMapped 为 map 对象的内部方法 [[GetOwnPropery]] 传入参数 P 的执行结果
  3. 令 result 为 arguments 对象的内部方法 [[Delete]](8.12.7)传入参数 P 和 Throw 的执行结果
  4. 如果 result 为 true,且 isMapped 不为 undefined,则调用 map 对象的内部方法 [[Delete]],传入 P 和 false 作为参数
  5. 返回 result

 非严格模式下的函数,arguments 对象以数组索引(参见 15.4 的定义)作为数据属性的命名,其数字名字的值少于对应的函数对象初始时的形参数量,它们与绑定在该函数执行环境中对应的参数共享值。这意味着,改变该属性将改变这些对应的、绑定的参数的值,反之亦然。如果其中一个属性被删除然后再对其重定义,或者其中一个属性在某个访问器属性内部被更改,则这种对应关系将被打破。严格模式下的函数,arguments 对象的属性值就是传入该函数的实际参数的简单拷贝,它们与形参之间的值不存在动态的联动关系。

 ParameterMap 对象和它的属性值被作为说明 arguments 对象对应绑定参数的装置。ParameterMap 对象和它的属性值对象不能直接被 ECMAScript 代码访问。作为 ECMAScript 的实现,不需要实际创建或使用这些对象去实现指定的语义。

 严格模式下函数的 Arguments 对象定义的非可配置的访问器属性,"caller" 和 "callee",在它们被访问时,将抛出一个 TypeError 的异常。在非严格模式下,"callee" 属性具有非常明确的意义,"caller" 属性有一个历史问题,它是否被提供,视为一个由实作环境决定的,在具体的 ECMAScript 实作进行扩展。在严格模式下对这些属性的定义的出现是为了确保它们俩谁也不能在规范的 ECMAScript 实作中以任何方式被定义。