Item 23: Never Modify the arguments Object

Item 23: Never Modify the arguments Object
The arguments object may look like an array, but sadly it does not
always behave like one. Programmers familiar with Perl and UNIX
shell scripting are accustomed to the technique of “shifting” elements
off of the beginning of an array of arguments. And JavaScript’s arrays
do in fact contain a shift method, which removes the first element of
an array and shifts all the subsequent elements over by one. But the

arguments object itself is not an instance of the standard Array type,
so we cannot directly call arguments.shift() .
Thanks to the call method, you might expect to be able to extract the
shift method from an array and call it on the arguments object. This
might seem like a reasonable way to implement a function such as
callMethod , which takes an object and a method name and attempts
to call the object’s method on all the remaining arguments:
function callMethod(obj, method) {
var shift = [].shift;
shift.call(arguments);
shift.call(arguments);
return obj[method].apply(obj, arguments);
}
But this function does not behave even remotely as expected:
var obj = {
add: function(x, y) { return x + y; }
};
callMethod(obj, "add", 17, 25);
// error: cannot read property "apply" of undefined
The reason why this fails is that the arguments object is not a copy
of the function’s arguments. In particular, all named arguments are
aliases to their corresponding indices in the arguments object. So obj
continues to be an alias for arguments[0] and method for arguments[1] ,
even after we remove elements from the arguments object via shift .
This means that while we appear to be extracting obj["add"] , we are
actually extracting 17[25] ! At this point, everything begins to go hay-
wire: Thanks to the automatic coercion rules of JavaScript, this pro-
motes 17 to a Number object, extracts its "25" property (which does
not exist), produces undefined , and then unsuccessfully attempts to
extract the "apply" property of undefined to call it as a method.
The moral of this story is that the relationship between the arguments
object and the named parameters of a function is extremely brittle.
Modifying arguments runs the risk of turning the named parameters
of a function into gibberish. The situation is complicated even further
by ES5’s strict mode. Function parameters in strict mode do not alias
their arguments object. We can demonstrate the difference by writing
a function that updates an element of arguments :
function strict(x) {
"use strict";
arguments[0] = "modified";

return x === arguments[0];
}
function nonstrict(x) {
arguments[0] = "modified";
return x === arguments[0];
}
strict("unmodified"); // false
nonstrict("unmodified"); // true
As a consequence, it is much safer never to modify the arguments
object. This is easy enough to avoid by first copying its elements to a
real array. A simple idiom for implementing the copy is:
var args = [].slice.call(arguments);
The slice method of arrays makes a copy of an array when called
without additional arguments, and its result is a true instance of the
standard Array type. The result is guaranteed not to alias anything,
and has all the normal Array methods available to it directly.
We can fix the callMethod implementation by copying arguments , and
since we only need the elements after obj and method , we can pass a
starting index of 2 to slice :
function callMethod(obj, method) {
var args = [].slice.call(arguments, 2);
return obj[method].apply(obj, args);
}
At last, callMethod works as expected:
var obj = {
add: function(x, y) { return x + y; }
};
callMethod(obj, "add", 17, 25); // 42
Things to Remember
? Never modify the arguments object.
? Copy the arguments object to a real array using [].slice.call(arguments)
before modifying it.

来源:Effective Javascript

时间: 2024-11-04 03:39:21

Item 23: Never Modify the arguments Object的相关文章

Effective JavaScript Item 23 永远不要修改arguments对象

本系列作为Effective JavaScript的读书笔记. arguments对象只是一个类似数组的对象,但是它并没有数组对象提供的方法,比如shift,push等.因此调用诸如:arguments.shift(),arguments.push()是错误的. 在Item 20和Item 21中,知道了函数对象上存在call和apply方法,那么是不是可以利用它们来让arguments也能够利用数组的方法呢: function callMethod(obj, method) { var shi

The method setItems(String) in the type ForTokensTag is not applicable for the arguments (Object)

1. 问题 看到这个错误以为是貌似jsp页面有误,c:forTokens标签用错了?? An error occurred at line: 444 in the jsp file: /WEB-INF/pages/countOrder/viewCountOrderDetails.jsp The method setItems(String) in the type ForTokensTag is not applicable for the arguments (Object) 441: </t

Item 22: Use arguments to Create Variadic Functions

Item 22: Use arguments to Create Variadic FunctionsItem 21 describes a variadic average function, which can process anarbitrary number of arguments and produce their average value. Howcan we implement a variadic function of our own? The fixed-arity v

Object类的源码分析

JDK 1.8中Object 的源码如下: 1 public class Object { 2 3 private static native void registerNatives(); 4 static { 5 registerNatives(); 6 } 7 8 /** 9 * Returns the runtime class of this {@code Object}. The returned 10 * {@code Class} object is the object tha

【前端学习笔记】arguments相关

arguments转数组: (function() { console.log(arguments instanceof Array); // --> false console.log(Object.prototype.toString.call(arguments)); // --> [object Arguments] var args = Array.prototype.slice.apply(arguments); console.log(args instanceof Array)

简单的ListView中item图片异步加载

前言: 在android开发当中,从目标地址获取图片往往都是采用异步加载的方法.当完全加载完图片后在进行显示,也有些是直接将加载的图片一点一点的显示出来. 这两个区别只是对流的处理不同而已.现在就讲讲当图片被完全获取到后在显示的方法. 一,效果图:       初始化:                                                   获取后:                         1.1,效果思路: 初始化的时候默认ImageView显示一张白色的图

一文搞懂List 、List&lt;Object&gt;、List&lt;?&gt;的区别以及&lt;? extends T&gt;与&lt;? super T&gt;的区别

前段时间看<Java编程思想>泛型时对 <? extends T>与<? super T>很懵逼,接着看到泛型与集合的更蒙蔽,随后又翻开<码出高效>时,对这些知识点才恍然大悟,发篇博客记录下 List.List<Object>.List<?> 的三者的区别以及 <? extends T>与<? super T> 的区别 List.List<Object>.List<?> List :完全

Object.equals() 方法

Object.equals() 方法: 1 public class EqualsTest1 { 2 public static void main(String[] args) { 3 //Cat c1 = new Cat(); 4 //Cat c2 = new Cat(); 5 //System.out.println(c1 == c2);//result:false 6 Cat c3 = new Cat(1,2,3); 7 Cat c4 = new Cat(1,2,3);//在重写equa

ES6中Arguments和Parameters用法解析

原文链接 译文 ECMAScript 6 (也称 ECMAScript 2015) 是ECMAScript 标准的最新版本,显著地完善了JS中参数的处理方式.除了其它新特性外,我们还可以使用rest参数.默认值.解构赋值等. 本教程中,我们将详细探索arguments和parameters,看看ES6是如果改善升级它们的. 对比 Arguments 和 Parameters 通常情况下提到 Arguments 和 Parameters, 都认为是可以互换使用的.然而,基于本教程的目的,我们做了明