MDN bind方法Polyfill中arguments切片返回时消失的原因探究
解惑MDN bind方法Polyfill的参数疑问
嘿,我来帮你理清这个困惑!首先咱们先把MDN上经典的bind polyfill里你疑惑的核心代码段贴出来:
if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) { if (typeof this !== 'function') { throw new TypeError('Function.prototype.bind - 要绑定的目标不是可调用函数'); } // 这里的arguments是调用bind时传入的参数(除了第一个oThis) var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { // 你疑惑的三元运算符就在这里 return fToBind.apply( // 判断是否用new调用绑定后的函数,决定this指向 this instanceof fNOP ? this : oThis, // 合并bind时的预设参数和调用绑定函数时的实时参数 aArgs.concat(Array.prototype.slice.call(arguments)) ); }; // 处理原型链继承 if (this.prototype) { fNOP.prototype = this.prototype; } fBound.prototype = new fNOP(); return fBound; }; }
你误解的核心:两个arguments不是一回事!
你觉得“错误拼接了重复的arguments”,其实是没注意到这两个arguments属于不同的函数作用域:
- 第一个
arguments(aArgs对应的那个):是你调用bind方法时传入的参数,比如func.bind(obj, 1, 2),这里的arguments是[obj, 1, 2],aArgs通过slice(1)拿到的是[1,2]——也就是你预设要传给原函数的参数。 - 第二个
arguments(concat里的那个):是你调用绑定后的函数时传入的参数,比如boundFunc(3,4),这里的arguments是[3,4]——也就是调用时临时传入的参数。
为什么没看到多余参数?
这段代码里的aArgs.concat(...)是把「bind时的预设参数」和「调用绑定函数时的实时参数」合并成一个数组,传给原函数。比如上面的例子,合并后是[1,2,3,4],原函数拿到的就是这组正确的参数,根本没有多余的内容。
关于你提到的“防止arguments泄露”
早期JS环境中,arguments对象和函数作用域强绑定,直接持有它可能导致内存泄漏或者意外的作用域穿透。用Array.prototype.slice.call(arguments)把它转成普通数组,既可以安全地操作参数,也避免了这些潜在问题——这就是你说的“安全特性”,它并没有掩盖什么bug,反而让代码更健壮。
举个实际测试例子
咱们写段代码验证一下:
function logArgs(...args) { console.log('拿到的参数:', args); } // 用上面的polyfill绑定预设参数 const boundLog = logArgs.bind(null, '预设参数A', '预设参数B'); // 调用绑定后的函数,传入实时参数 boundLog('实时参数X', '实时参数Y');
运行后控制台会输出:拿到的参数: ["预设参数A", "预设参数B", "实时参数X", "实时参数Y"],完全符合预期,没有多余参数。
所以你觉得的“bug”其实是对两个不同arguments的作用域误解啦~
内容的提问来源于stack exchange,提问作者user5389726598465
相关产品推荐
相关产品推荐

