本系列作为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对象的一份拷贝,然后对拷贝进行修改

Effective JavaScript Item 23 永远不要修改arguments对象相关推荐

  1. [Effective JavaScript 笔记]第23条:永远不要修改arguments对象

    arguments对象并不是标准的Array类型的实例.arguments对象不能直接调用Array方法. arguments对象的救星call方法 使得arguments可以品尝到数组方法的美味,知 ...

  2. JavaScript学习(五十七)— arguments对象

    JavaScript学习(五十七)- arguments对象 arguments对象 该对象是函数内部的一个属性,这个属性本身也是一个对象 这个对象是用来管理函数被调用时传过来的实参的 argumen ...

  3. Effective JavaScript Item 37 认识this的隐式指向

    本系列作为Effective JavaScript的读书笔记. CSV数据通常都会被某种分隔符进行分隔.所以在实现CSV Reader时,须要支持不同的分隔符.那么,非常自然的一种实现就是将分隔符作为 ...

  4. Effective JavaScript Item 40 避免继承标准类型

    本系列作为Effective JavaScript的读书笔记. ECMAScript标准库不大.可是提供了一些重要的类型如Array,Function和Date.在一些场合下.你或许会考虑继承当中的某 ...

  5. Effective JavaScript Item 33 让构造函数不再依赖newkeyword

    本系列作为EffectiveJavaScript的读书笔记. 在将function当做构造函数使用时,须要确保该函数是通过newkeyword进行调用的. function User(name, pa ...

  6. Effective C#: Item 1 Always use properties instead of accessible data members

    Effective C#: Item 1 Always use properties instead of accessible data members Item 1: 当设计类时,永远用Prope ...

  7. JavaScript学习系列3 -- JavaScript arguments对象学习

    在实际项目开发中,目前还是很少使用到JavaScript 中的arguments对象,那么它到底是干什么用的呢 arguments是JavaScript中的一个类数组对象,它代表传给一个正在执行的函数 ...

  8. [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

    函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...

  9. 你知道 JavaScript 中的 Arguments 对象都有哪些用途吗?

    JavaScript 中 Arguments 对象的用途总结. 前言 相信我们很多人在代码开发的过程中都使用到过一个特殊的对象 -- Arguments 对象. 在实际开发中,Arguments 对象 ...

最新文章

  1. python在bim中的应用_Revit元素类别——Dynamo Python系列教程(六)
  2. (原)Apache添加完限速模块后的文件
  3. linux 修改ssh banner
  4. [SQLITE_READONLY] Attempt to write a readonly databse (attempt to write a readonly database)
  5. 前端学习(2123):知识回顾
  6. 并发系列(二)----Java内存模型
  7. 9.20 模拟试题
  8. 2018级C语言大作业 - 祖玛
  9. python list append 相关知识点
  10. 题解 洛谷 P1580 【yyy loves Easter_Egg I】
  11. APP开发内容介绍(源代码)
  12. leetcode845. 数组中的最长山脉
  13. linux samba 漏洞 exp,smaba漏洞总结
  14. Excel表格导入CAD后,表格内数字后的小数点怎么消除呢?
  15. 【向生活低头】十分白痴地自动删微博文章脚本
  16. PCB设计中常用class与subclass
  17. 学习乐器的好处(1)
  18. 苹果 WWDC 2019 全记录:iPadOS独立、SwiftUI、Project Catalyst
  19. 阴阳师真八歧大蛇最低配置攻略,蛇黑切
  20. HTTP协议实现文件下载

热门文章

  1. 秒杀抢单系统软件架构优化思路
  2. 当RxJava遇上Retrofit
  3. “二老板”何以疯行互联网?
  4. verilog always语法_Verilog 最全经验总结(建议收藏)
  5. 访问控制模型详细介绍
  6. 名果黑的Mac装机必备
  7. 记录谷歌gn编译时碰到的一个错误“I could not find a “.gn“ file ...”
  8. 打蚊子表情包_蚊子表情包 - 蚊子微信表情包 - 蚊子QQ表情包 - 发表情 fabiaoqing.com...
  9. Centos7下的LibreOffice的搭建及自动化脚本部署
  10. 洛谷 P2071 座位安排 (最大流 + 建图)