如何仅使用arguments关键字替代rest参数...val修复JavaScript代码?
问题:如何仅使用
arguments关键字让代码正常运行? 我看到你遇到了一个典型的作用域陷阱问题——用arguments的版本失效,换成rest参数...val就正常,核心原因是内层回调函数的arguments和外层函数的arguments不是同一个东西,再加上var声明的循环变量存在变量提升的问题,导致代码逻辑出错。
问题根源拆解
arguments的作用域冲突:在$('.a').each()的回调函数里,arguments指向的是这个回调自身的参数(jQuery的each回调会传入index和element两个参数),而不是外层func函数的arguments。所以你在回调里写data[arguments[i]]的时候,实际上是在访问回调的arguments,完全不是你传入func('one','two')的那些参数。var循环变量的共享问题:用var i声明的变量是函数级作用域,循环结束后i的值会变成arguments.length(也就是2),当each的回调执行时,i已经是2了,这时候即使能拿到外层的arguments,arguments[2]也是undefined,自然找不到对应的类。
修复后的代码(仅用arguments)
我们只需要做两个小修改:
- 把外层的
arguments转换成数组并保存到一个变量,避免内层回调覆盖arguments的指向 - 用
let声明循环变量i(或者用闭包),确保每次循环的i值被单独保存
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="a"></div> <div class="a b"></div> <div class="a c"></div>
body{ margin:0; padding:0; height:100vh; } .a{ height:50px; width:50px; background:green; margin:20px; }
$(document).ready(function(){ var data = { 'one':'b', 'two':'c', 'three':'d' } function func(){ // 把外层arguments转成数组保存,避免内层回调的arguments覆盖 var args = Array.from(arguments); // 用let声明i,确保每个循环迭代的i都是独立的 for(let i=0;i<args.length;i++){ $('.a').each(function(){ if($(this).hasClass(data[args[i]])){ $(this).css('background','red') } }) } } func('one','two') })
兼容旧环境的写法(不支持Array.from和let)
如果需要兼容更老的浏览器,可以用下面的替代方案:
$(document).ready(function(){ var data = { 'one':'b', 'two':'c', 'three':'d' } function func(){ // 用slice把arguments转成数组 var args = [].slice.call(arguments); for(var i=0;i<args.length;i++){ // 用闭包保存当前的i值 (function(index){ $('.a').each(function(){ if($(this).hasClass(data[args[index]])){ $(this).css('background','red') } }) })(i) } } func('one','two') })
这样修改后,代码就能和用...val的版本一样正常运行了——它会把带有b和c类的绿色方块改成红色。
内容的提问来源于stack exchange,提问作者Ayush Gupta
相关产品推荐
相关产品推荐

