console.log('---------------------使用arguments参数对所有函数执行操作------------------------');
//完全没有任何显式定义参数的函数
//迭代所有传入参数,然后通过索引标记获取每个元素的值
function sum() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
//调用函数并传入任意数量的参数
if (sum(1, 2) === 3) {
console.log("We can add two numbers.");
}
if (sum(1, 2, 3) === 6) {
console.log("We can add three numbers");
}
if (sum(1, 2, 3, 4) === 10) {
console.log('We can add four numbers.');
}
上述代码中,我们首先定义了一个没有显示声明任何参数的sum函数,尽管如此,我们依然可以通过arguments对象访问所有的函数参数。遍历所有的参数即可计算它们的和。
因此,我们可以调用函数并传入任意数量的参数,接着我们通过测试几种情况。
注意:
我们之前提到过,在大多数情况下可以使用剩余参数(rest parameter)来代替arguments参数。剩余参数是正真的Array实例,也就是说你可以在它上面直接使用所有的数组方法。这点相对于arguments对象而言是个优势,作为练习可以使用剩余参数代替arguments参数。argument参数有一个有趣的特性:它可以作为函数参数的别名。例如,如果为arguments[0]赋一个新值,那么,同时也会改变第一个参数的值。
console.log('-------------argument对象作为函数参数的别名----------------------');
//argument参数有一个有趣的特性:它可以作为函数参数的别名。例如,如果为arguments[0]赋一个新值,那么,同时也会改变第一个参数的值。
//检查person参数的值等于gardener,并作为第一个参数被传入。
function infiltrate(person) {
if (person === 'gardener') {
console.log("The person is a gardener.");
}
if (arguments[0] === 'gardener') {
console.log('The first argument is a gardener');
}
arguments[0] = 'ninja';
//改变argument对象的值也会改变相应的形参
if (person === 'ninja') {
console.log('The person is a ninja now.');
}
if (arguments[0] === 'ninja') {
console.log('The first argument is a ninja.');
}
person = 'gardener';
//这两种方式下,别名都正常工作了。
if (person === 'gardener') {
console.log('The person is a gardener once more.');
}
if (arguments[0] === 'gardener') {
console.log('The first argument is a gardener again.');
}
}
infiltrate("gardener");
这里可以说明arguments对象是如何作为函数参数别名的。我们定义了一个函数infiltrate,它只接收一个参数person,接着我们调用它并传入参数gardener。可以同时通过函数形参person和arguments对象访问到参数值gardener。
if (person === 'gardener') {
console.log("The person is a gardener.");
}
if (arguments[0] === 'gardener') {
console.log('The first argument is a gardener');
}
因为arguments对象是函数参数参数的别名,所以如果改变了arguments对象的值,同时也会影响对应的函数参数
arguments[0] = 'ninja';
//改变argument对象的值也会改变相应的形参
if (person === 'ninja') {
console.log('The person is a ninja now.');
}
if (arguments[0] === 'ninja') {
console.log('The first argument is a ninja.');
}
反之亦然。如果我们更改了某个参数的值,会同时影响参数和arguments对象:
person = 'gardener';
//这两种方式下,别名都正常工作了。
if (person === 'gardener') {
console.log('The person is a gardener once more.');
}
if (arguments[0] === 'gardener') {
console.log('The first argument is a gardener again.');
}
避免使用别名
将arguments对象作为函数参数的别名使用时会影响代码的可读性,因此在JavaScript提供的严格模式中(strict mode)中将无法再使用它。
严格模式
严格模式是在ES5中引入的特性,它可以改变JavaScript引擎的默认行为并执行更加严格的语法检查,一些在普通模式下的静默错误会在严格模式下抛出异常。在严格模式下部分语言特性会被改变,甚至完全禁用一些不安全的语言特性,其中arguments别名在严格模式下将无法使用。
<script type="text/javascript">
"use strict";
console.log('--------使用严格模式避免使用arguments别名---------------');
function infiltrate(person) {
if (person === 'gardener') {
console.log("The person is a gardener.");
}
if (arguments[0] === 'gardener') {
console.log('The first argument is a gardener');
}
//改变第一个参数
arguments[0] = 'ninja';
//Person的参数值没有改变
if (person === 'ninja') {
console.log('The person is a ninja now.');
}
//第一个参数值被改变了
if (arguments[0] === 'ninja') {
console.log('The first argument is a ninja.');
}
}
infiltrate('gardener');
</script>
第一行代码use strict是一个简单的字符串,这将告诉JavaScript引擎,我们希望将下面的代码在严格模式下执行。严格模式将改变程序的执行结果,最终person参数的值和arguments参数的第一个中将不再相同。
//改变第一个参数
arguments[0] = 'ninja';
//Person的参数值没有改变
if (person === 'ninja') {
console.log('The person is a ninja now.');
}
//第一个参数值被改变了
if (arguments[0] === 'ninja') {
console.log('The first argument is a ninja.');
}
但与非严格模式不同的是,这一次arguments对象将不再作为参数的别名。如果想通过arguments[0]='ninja'改变第一个参数的值,这将不会改变person参数。
参考《JavaScript忍者秘籍》