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

本文深入探讨了JavaScript中arguments对象的特性及其与函数参数引用的关系,揭示了直接修改arguments对象可能导致的错误,并提供了安全操作arguments对象的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本系列作为Effective JavaScript的读书笔记。

 

arguments对象只是一个类似数组的对象,但是它并没有数组对象提供的方法,比如shiftpush等。因此调用诸如:arguments.shift()arguments.push()是错误的。

 

Item 20Item 21中,知道了函数对象上存在callapply方法,那么是不是可以利用它们来让arguments也能够利用数组的方法呢:


function callMethod(obj, method) {
	var shift = [].shift;
	shift.call(arguments);
	shift.call(arguments);
	return obj[method].apply(obj, arguments);
}

但是以上的方法在下面的应用场景中存在问题:


var obj = {
	add: function(x, y) { return x + y; }
};
callMethod(obj, "add", 17, 25);
// error: cannot read property "apply" of undefined

发生错误的原因是:

arguments对象并不是函数参数的一份拷贝。函数声明的参数和arguments保存的对象存在着引用关系。比如在上面callMethod函数的例子中,声明了两个参数objmethod

obj引用的就是arguments[0]

method引用的就是arguments[1]

 

而在调用了两次shift.call(arguments)之后,arguments由原来的:

[obj, "add", 17, 25]变成了[17, 25]

 

所以obj的引用从obj本身变成了17method的引用从"add"变成了25。很显然17[25]得到的结果是undefined,因为根据JavaScript的运算规则,17首先会被转换为Number对象,而这个对象之上并没有25这个属性。

 

上述例子想表达的就是,函数中声明的参数和arguments之间的联系很脆弱,每个声明的参数实际上只是对arguments对象中对应位置的一个引用。

 

值得注意的是,在ES5strict mode中,函数声明的参数并不会引用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

正因为在strict和非strict模式下,函数声明的参数和arguments的关系不一致,所以为了避免出现问题,不去修改arguments对象才是最安全的做法。

 

如果确实需要修改arguments对象,那么可以首先赋值一份arguments对象:


var args = [].slice.call(arguments);

slice方法不接受任何参数的时候,就会执行复制操作,得到的args也是一个真正的数组对象。同时,args和函数声明的参数之间也没有任何联系了,对它进行操作是安全的。使用这种方式重新实现上面提到过的callMethod函数:


function callMethod(obj, method) {
	var args = [].slice.call(arguments, 2);
	return obj[method].apply(obj, args);
}

var obj = {
	add: function(x, y) { return x + y; }
};
callMethod(obj, "add", 17, 25); // 42

总结:

  1. 永远不要修改arguments对象
  2. 使用[].slice.call(arguments)得到arguments对象的一份拷贝,然后对拷贝进行修改

☆ 资源说明:☆ [Addison-Wesley Professional] Effective JavaScript 编写高质量JavaScript代码的68个有效方法 (英文版) [Addison-Wesley Professional] Effective JavaScript 68 Specific Ways to Harness the Power of JavaScript (E-Book) ☆ 图书概要:☆ In order to truly master JavaScript, you need to learn how to work effectively with the language’s flexible, expressive features and how to avoid its pitfalls. No matter how long you’ve been writing JavaScript code, Effective JavaScript will help deepen your understanding of this powerful language, so you can build more predictable, reliable, and maintainable programs. Author David Herman, with his years of experience on Ecma’s JavaScript standardization committee, illuminates the language’s inner workings as never before—helping you take full advantage of JavaScript’s expressiveness. Reflecting the latest versions of the JavaScript standard, the book offers well-proven techniques and best practices you’ll rely on for years to come. Effective JavaScript is organized around 68 proven approaches for writing better JavaScript, backed by concrete examples. You’ll learn how to choose the right programming style for each project, manage unanticipated problems, and work more successfully with every facet of JavaScript programming from data structures to concurrency. ☆ 出版信息:☆ [作者信息] David Herman [出版机构] Addison-Wesley Professional [出版日期] 2012年12月06日 [图书页数] 240页 [图书语言] 英语 [图书格式] PDF 格式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值