JavaScript位置参数实现原理及过程解析


Posted in Javascript onSeptember 14, 2020

1.什么是位置参数?

JavaScript:为什么命名参数比位置参数更好

你一定很熟悉位置参数,即使你第一次听到这个名字。

function greet(firstName, lastName) { 
 console.log(`Hello ${firstName} ${lastName}`); 
} 

// 预期用法 

greet('Michael', 'Scott'); 

const fName = 'Harry'; 
const lName = 'Potter'; 
greet(fName, lName); 

// 错误用法 

const firstName = 'Erlich'; 
const lastName = 'Bachman'; 
greet(lastName, firstName);

greet函数接受两个参数:firstName和lastName。调用者必须确保firstName是第一个参数,lastName是第二个参数。这里重要的一点是,参数的名称没有任何意义,唯一重要的是参数传递的顺序。

这种熟悉的方法称为位置参数。通常,在你传递一个或两个参数的情况下,这很好,因为它很难弄乱参数的顺序。但是如果你必须调用一个需要6个参数的函数,那就很难记住传递参数的顺序。你不希望传递密码来代替用户名参数。

2. 位置参数问题

位置参数很简单,但是你将面临一些挑战。

(1) 不能跳过中间参数 /

假设你已经更改了greet函数,使其现在需要3个参数:firstName、middleName和lastName。由于许多人没有中间名,因此你希望将MiddleName设为可选参数,仅使用firstName和lastName调用greet函数的唯一方法是此方法。

greet('Aditya', null, 'Agarwal'); 
// Correct 
greet('Aditya', 'Agarwal'); 
// Incorrect

你不能只提供firstName和lastName。当可选参数的数量增加到5个时,这个问题变得更加明显。现在,你必须提供5个null才能在这些参数之后提供参数。

(2) 将类型添加到位置参数不那么干净

如今,为你的实用程序添加类型变得非常普遍。使用位置参数,你别无选择,只能将类型与函数定义一起内联。这可能会使代码有点模糊,如果我们可以在一个块中声明所有参数的类型定义,那就更好了。

(3) 引起细微的错误

位置参数包装了很多隐性行为,这可能是造成微妙bug的原因。我们来看一个常见的JS技巧问题

const numbers = ['1', '4', '8', '10'];
console.log(numbers.map(parseInt));

// 你可能会认为结果将是:
[1, 4, 8, 10]

// 这是实际的输出:
[ 1, NaN, NaN, 3 ]

惊讶吗?这种奇怪的输出的原因隐藏在位置参数的隐性背后。你会看到map和parseInt函数在显而易见的情况下隐藏了它们的一些秘密。

让我们再次查看代码 number.map(parseInt)。

这里到底发生了什么?

  • 我们在numbers数组上运行map函数。
  • map获取数组的第一项并将其传递给parseInt。
  • 现在,对于数组中的第一项(即1),它将执行 parseInt(1)。对...?错误!!!

实际上,map将三个参数传递给其回调函数。第一个是数组中的当前项目,第二个是项目的索引,第三个是整个数组。这本身没有问题,但真正的问题在于后一部分。

numbers.map(parseInt) 与 numbers.map((item) => parseInt(item)) 不同。你可以假设,由于回调函数仅接受item参数并将其传递给parseInt,因此我们可以跳过附加步骤。但是两者是不同的:在前者中,我们将所有数据从map传递到parseInt,而在后者中,我们仅传递项。

你可能不知道,但是parseInt的第二个参数称为基数。默认情况下,基数的值为10(以10为底,因为人类遵循十进制进行计数)。该代码出了问题,就是我们将当前项目的索引作为基数值传递给parseInt。这些是发生的实际函数调用:

parseInt('1', 0, [...]);
parseInt('4', 1, [...]);
parseInt('8', 2, [...]);
parseInt('10', 3, [...]);

现在我们知道了问题,我们如何才能做得更好?

3. 位置参数的替代

如果一个函数可以通过名字就知道它期望的参数是什么呢?这样即使你误传了额外的数据给它,它也只会使用它需要的东西。

让我们对parseInt进行包装。下面是一个简单的实现。

// 实现 
function myCustomParseInt(objArgs) { 
 return parseInt(objArgs.item, objArgs.radix); 
} 

// 使用 
const num = myCustomParseInt({ item: '100', radix: 10 });

myCustomParseInt仅接受一个参数,它是一个对象。这个对象可以有两个键:item 和 radix。让我们使用我们的自定义函数与map。必须有一个中间步骤,将回调收到的args发送到myCustomParseInt。

const numbers = ['1', '4', '8', '10'];

const result = numbers.map((item, index) => myCustomParseInt({ item, index }));

console.log(result); // [ 1, 4, 8, 10 ]

请注意,即使我们将索引传递给myCustomParseInt也不会造成任何问题。那是因为myCustomParseInt只会忽略它。将对象传递给函数的这种模式称为命名参数,它比位置参数更明确。

要更改基数,我们必须显式传递基数键。这意味着如果要解析以2为底的字符串,则必须转到文档并查看参数(基数)的确切名称。如果我们盲目地传递任何其他键,它将无济于事。这对我们来说很棒,因为它避免了意外行为。

(1) 具有解构的命名参数

不久前,JavaScript获得了称为解构的功能,让我们在myCustomParseInt实现中使用它。

// 位置参数 
function myCustomParseInt(item, radix) { 
 return parseInt(item, radix); 
} 

// 命名参数旧的实现 
function myCustomParseInt(objArgs) { 
 return parseInt(objArgs.item, objArgs.radix); 
} 

// 命名参数解构 
function myCustomParseInt({ item, radix }) { 
 return parseInt(item, radix); 
}

你会注意到,只需添加两个花括号,我们就可以得到命名args的好处,你可以将解构视为执行 const item = objArgs.item;。

如果使用 undefined 调用myCustomParseInt,则JS将引发错误。那是因为不允许 undefined.item。为了避免这种情况,我们可以在解构结束时添加 = {}。这样,当我们传递undefined时,它将执行 {}.item 这是有效的JS。这是最终的实现:

function myCustomParseInt({ item, radix } = {}) { 
 return parseInt(item, radix); 
}

通过命名参数模式,我们也可以跳过我们不想提供的参数,因为函数不再依赖于传递参数的顺序。

// 对于位置参数,我们必须在之间添加一个null
function greetPos(firstName, middleName, lastName) {}
greetPos('Aditya', null, 'Agarwal');

// 使用命名参数,你只需提供firstName和lastName。
function greetNamed({ firstName, middleName, lastName } = {}) {}
greetNamed({ firstName: 'Aditya', lastName 'Agarwal' });

总而言之,我要说的是命名参数是一种强大的模式,如今它已变得非常普遍,但是你不必总是使用它们。有时你甚至可以将两者结合在一起。浏览器中的fetch API的用法如下:

// 以url作为位置参数的请求,以及以args做命名参数的选项。 
fetch('https://google.com', { 
 method: 'POST', 
 headers: { 
  'Content-Type': 'application/json', 
 }, 
}); 

// basic GET requests with just positional args 
fetch('https://google.com');

这里的强制参数(API路径)是一个位置参数,然后通过命名参数接受可选的参数。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js中cookie的使用详细分析
May 28 Javascript
深入分析escape()、encodeURI()、encodeURIComponent()的区别及示例
Aug 04 Javascript
JQuery中使用Ajax赋值给全局变量失败异常的解决方法
Aug 18 Javascript
jquery实现勾选复选框触发事件给input赋值
Feb 01 Javascript
js操作css属性实现div层展开关闭效果的方法
May 11 Javascript
vue2的todolist入门小项目的详细解析
May 11 Javascript
jquery append与appendTo方法比较
May 24 jQuery
JavaScript中正则表达式使数字、中文或指定字符高亮显示
Oct 31 Javascript
js 根据对象数组中的属性进行排序实现代码
Sep 12 Javascript
JS Array.from()将伪数组转换成数组的方法示例
Mar 23 Javascript
vue实现一个矩形标记区域(rectangle marker)的方法
Oct 28 Javascript
vue+Element-ui前端实现分页效果
Nov 15 Javascript
swiper自定义分页器的样式
Sep 14 #Javascript
js+canvas实现转盘效果(两个版本)
Sep 13 #Javascript
js实现3D粒子酷炫动态旋转特效
Sep 13 #Javascript
原生JS实现九宫格抽奖
Sep 13 #Javascript
jQuery实现带进度条的轮播图
Sep 13 #jQuery
js+canvas实现画板功能
Sep 13 #Javascript
jQuery实现鼠标拖拽登录框移动效果
Sep 13 #jQuery
You might like
PHP分页显示制作详细讲解
2008/11/19 PHP
php教程之phpize使用方法
2014/02/12 PHP
php中动态调用函数的方法
2015/03/16 PHP
php网页版聊天软件实现代码
2016/08/12 PHP
Zend Framework入门教程之Zend_Session会话操作详解
2016/12/08 PHP
PHP设计模式之命令模式示例详解
2020/12/20 PHP
jquery实现带二级菜单的导航示例
2014/04/28 Javascript
Javascript实现颜色rgb与16进制转换的方法
2015/04/18 Javascript
前端设计师们最常用的JS代码汇总
2016/09/25 Javascript
Angularjs自定义指令实现三级联动 选择地理位置
2017/02/13 Javascript
Vue中引入样式文件的方法
2017/08/18 Javascript
bootstrap日期插件daterangepicker使用详解
2017/10/19 Javascript
浅谈vue,angular,react数据双向绑定原理分析
2017/11/28 Javascript
Vue.extend实现挂载到实例上的方法
2019/05/01 Javascript
Vue基础学习之项目整合及优化
2019/06/02 Javascript
[01:10:49]Secret vs VGJ.S 2018国际邀请赛淘汰赛BO3 第二场 8.24
2018/08/25 DOTA
[48:11]完美世界DOTA2联赛 Magma vs GXR 第二场 11.07
2020/11/10 DOTA
Python3.7 新特性之dataclass装饰器
2019/05/27 Python
Python函数参数匹配模型通用规则keyword-only参数详解
2019/06/10 Python
selenium跳过webdriver检测并模拟登录淘宝
2019/06/12 Python
python中for循环把字符串或者字典添加到列表的方法
2019/07/20 Python
基于matplotlib xticks用法详解
2020/04/16 Python
浅谈keras中loss与val_loss的关系
2020/06/22 Python
使用ITK-SNAP进行抠图操作并保存mask的实例
2020/07/01 Python
基于Python-Pycharm实现的猴子摘桃小游戏(源代码)
2021/02/20 Python
微信html5页面调用第三方位置导航的示例
2018/03/14 HTML / CSS
英国最大的汽车交易网站:Auto Trader UK
2016/09/23 全球购物
建筑工程自我鉴定
2013/10/18 职场文书
留学推荐信写作指南
2014/01/25 职场文书
先进集体事迹材料
2014/02/17 职场文书
法定代表人资格证明书
2014/09/11 职场文书
五好文明家庭事迹材料
2014/12/20 职场文书
爱护环境卫生倡议书
2015/04/29 职场文书
小学教学工作总结2015
2015/05/13 职场文书
24句精辟的现实社会语录,句句扎心,道尽人性
2019/08/29 职场文书
Ajax请求超时与网络异常处理图文详解
2021/05/23 Javascript