未加星标

Fancy Function Parameters

字体大小 | |
[前端(javascript) 所属分类 前端(javascript) | 发布者 店小二03 | 时间 2019 | 作者 红领巾 ] 0人收藏点击收藏

This article was written by Jake Dohm .

When you're first learning javascript one of the first things you learn about is functions, and when you're learning about functions one of the first things you learn about is parameters. But, just because function parameters are so fundamental doesn't mean there isn't room for progress and improvement!

Consider coming across the following line of code in a project that you didn't write, or hadn't worked on in a year.

renderList(['one', 'two'], true, undefined, '#5ad')

Seeing this code, would you have any idea what this function is doing? From a high level perspective, all we can tell is that the function renders a list ― but the rest of the arguments passed don't make a lot of sense without reading the function code to figure out what the parameters are, and how the function is using them.

What if I told you there was a better way? In this article, I'll be refactoring the renderList function to make its declaration, and uses, cleaner and more readable.

The Starting Point The Function function renderList(list, ordered, color, bgColor) { // set defaults for optional parameters if(typeof ordered === undefined) ordered = true if(typeof color === undefined) color = '#1e2a2d' if(typeof bgColor === undefined) color = 'transparent' /* code to render list would go here :wink: */ } Calling the Function // with all arguments renderList(['one', 'two'], true, '#c0ffee', '#5ad') // with only one "optional" argument (bgColor) renderList(['one', 'two'], undefined, undefined, '#5ad') In the code above, there are three main problems to address:

When calling the function, it's unclear what the last three arguments are doing . You can tell they're meant to configure how the list appears, but you can't tell how the list will appear without finding and reading the renderList function.

As you can see in the second example of calling the function, a situation may arise where you'll have to pass in undefined for optional parameters. For example, if you want to pass the last argument bgColor without specifying ordered and color , you have to manually pass in undefined . This can be confusing, especially to less experienced developers.

At the top of our function declaration we're having to check if the optional parameters are defined, and assign them default values if they're not. This works just fine, but it's messy, and thanks to ES6 there's an established way to do this.

Naming Our Parameters (Solving Problems #1 & #2)

JavaScript doesn't allow you to name your parameters. This used to be a hard problem to solve, but ES6 introduced a feature which allows us to simulate named params in JS! This powerful feature is called object destructuring. I won't go into depth on how it works, but I recommend taking a further look into destructuring if you're not familiar (here's a fantastic resource on destructuring from Wes Bos: https://wesbos.com/destructuring-objects )

Now, let's name some params!

// original function function renderList(list, ordered, color, bgColor) { // some things } renderList(['one', 'two'], true, '#c0ffee', '#5ad') // with named params function renderList({ list, ordered, color, bgColor }) { // some things } renderList({ list: ['one', 'two'], ordered: true, color: '#c0ffee', bgColor: '#5ad' })

Okay, let's break down what we did:

See in the second example how there are curly braces just inside of the parentheses?That is destructuring! So while it looks like we're accepting four parameters, it's actually one parameter (an object) that we're destructuring four variables from. The best part is, this doesn't change the way any of our function code works!

Then, when we call our function, instead of passing four ordered parameters we pass an object with keys (names) and values.

That wasn't too hard, was it? This simple change makes it much clearer what each argument is doing when we call our function. What you may not have guessed is that changing to this method of accepting params also solved problem #2!

// before renderList(['one', 'two'], undefined, undefined, '#5ad') // after renderList({ list: ['one', 'two'], bgColor: '#5ad' })

Now that we're naming our parameters, and not relying on order, we'll never have to pass in undefined for optional parameters again.

Note: if you ran the "after" example above, the "ordered" and "color" params would be set to undefined because when we destructure the values if no matching key is found the variable is set to undefined .

Naming our parameters solved problems #1 and #2, but it also introduced added complexity. In refactoring our parameters to be named, we've added a slight bit of unnecessary code when we call our function without any of the optional params.

// before renderList(['one', 'two']) // after renderList({ list: ['one', 'two'] })

This definitely isn't the end of the world, but I really like the "before" syntax better than the "after" syntax, and this is a problem we can solve!

By moving "list" out of the object into a separate parameter, we can have the best of both worlds! Our function will now accept two parameters: The list, and an optional settings object which we'll destructure.

// before function renderList({ list, ordered, color, bgColor }) { // some things } renderList({ list: ['one', 'two'] }) renderList({ list: ['one', 'two'], ordered: true, color: '#c0ffee' }) // after function renderList(list, { ordered, color, bgColor } = {}) { // some things } renderList(['one', 'two']) renderList(['one', 'two'], { ordered: true, color: '#c0ffee' })

One quick note, before we move on: You may have noticed that in the "after" function declaration there's an = {} after the second parameter (which is destructured). What is this doing? We're setting the "default" value for the second parameter to be an empty object. Why are we doing it? If nothing is passed in as the second parameter, the value of it would be undefined . Now normally this isn't a problem, except that we're attempting to destructure variables from the second parameter, and you obviously can't destructure anything from undefined . In short, we're doing the (almost) equivalent of the following:

const { ordered, color, bgColor } = paramTwo || {}; Setting Defaults for Our Options (Solving Problem #3)

Okay, so we've done a lot **already. The good news is this last part is very simple! Here's a quick refresher on what we're trying to accomplish. We're attempting to clean up the code in our original function that checks to see if our optional parameters are undefined, and sets them to default values if they are. Fortunately, there's a built-in pattern for this too.

Very similarly to how we were able to set a default to a parameter, destructuring also allows us to set defaults for variables we're attempting to destructure from an object. This allows us to remove the semi-complex code that we were using before, and set defaults in a declarative manner.

// before function renderList(list, { ordered, color, bgColor } = {}) { // set defaults for optional parameters if(typeof ordered === undefined) ordered = true if(typeof color === undefined) color = '#1e2a2d' if(typeof bgColor === undefined) color = 'transparent' /* ... */ } // after function renderList(list, { ordered = true, color = '#1e2a2d', bgColor = 'transparent' } = {}) { /* ... */ }

This saves us between 1 and 5 lines, depending on if you wrap the options like I did, but the more important improvement here is that you can understand exactly what each parameter's value will be without trying to figure out the "if" statements.

Wrapping Up

With that, we're done! Here is the final refactored code:

The Function function renderList(list, { ordered = true, color = '#1e2a2d', bgColor = 'transparent' } = {}) { /* ... */ } Calling the Function // simple use renderList(['love', 'patience', 'pain']) // with all arguments renderList(['one', 'two'], { ordered: true, color: '#c0ffee', bgColor: '#5ad' }) // with only one optional argument (bgColor) renderList(['one', 'two'], { bgColor: '#5ad' })

Hopefully we can all agree that the function is now simpler to use, and it's declaration is much easier to understand! If you have any questions about any of the steps of the refactor, or anything else, check out the articles below for more information or reach out via Twitter (@jakedohm).

Further Reading

Object Destructuring: https://wesbos.com/destructuring-objects

Default Function Parameters: https://dev.to/runosaduwa/default-functions-es6-gbo

Want more?Check out how to set up a Node.js app in VS Code .


Fancy Function Parameters

Emily Freeman

The contributors to JavaScript January are passionate engineers, designers and teachers. Emily Freeman is a developer advocate at Kickbox and curates the articles for JavaScript January.

本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程

代码区博客精选文章
分页:12
转载请注明
本文标题:Fancy Function Parameters
本站链接:https://www.codesec.net/view/628318.html


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 前端(javascript) | 评论(0) | 阅读(99)