JavaScript quirk 5: parameter handling

[This post is part of a series on JavaScript quirks.]

The basics of parameter handling in JavaScript are simple, advanced tasks require manual work. This blog post first looks at the basics and then covers advanced topics.

The basics of parameter handling

Two facts form the core of JavaScript parameter handling.
Fact: you can always pass an arbitrary amount of parameters
When calling a function, you can pass as many or as few actual parameters as you want, independently of how many formal parameters are mentioned in the function declaration. Parameters that are missing have the value undefined. Parameters that are too many are ignored. Let’s use the following function for a demonstration:
    function f(x, y) {
        console.log('x: '+x);
        console.log('y: '+y);
    }
You can call this function with arbitrary many parameters:
    > f()
    x: undefined
    y: undefined

    > f('a')
    x: a
    y: undefined

    > f('a', 'b')
    x: a
    y: b

    > f('a', 'b', 'c')
    x: a
    y: b
Fact: all passed parameters are stored in arguments
All passed parameters are stored in the special, “Array-like” (see below for what that means) variable arguments. The following function lets us examine how that variable works.
    function g() {
        console.log('Length: '+arguments.length);
        console.log('Elements: '+fromArray(arguments));
    }
Function fromArray is shown below, it converts arguments to an array so that it can be logged. Using g():
    > g()
    Length: 0
    Elements: 
    > g('a')
    Length: 1
    Elements: a
    > g('a', 'b')
    Length: 2
    Elements: a,b
arguments is always there, no matter how many parameters have been explicitly declared. It always contains all actual parameters.

Has a parameter been passed?

If a caller does not provide a parameter, undefined is passed to the function. Because undefined is falsy [1], you can use an if statement to check whether the parameter “exists” or not:
    function hasParameter(param) {
        if (param) {
            return 'yes';
        } else {
            return 'no';
        }
    }
Thus, you get the same result if you omit a parameter and if you pass undefined:
    > hasParameter()
    'no'
    > hasParameter(undefined)
    'no'
The test works also well for truthy values:
    > hasParameter([ 'a', 'b' ])
    'yes'
    > hasParameter({ name: 'Jane' })
    'yes'
    > hasParameter('Hello')
    'yes'
With falsy values, however, you have to be careful. For example, false, zero and the empty string are interpreted as missing parameters:
    > hasParameter(false)
    'no'
    > hasParameter(0)
    'no'
    > hasParameter('')
    'no'
Still, this pattern has proven itself. You do have to be vigilant, but the code becomes pleasantly compact and it does not matter whether callers omit a parameter, pass undefined or pass null.

Default values for parameters

The following function should accept zero or more parameters. Parameters x and y should have the value 0 if they are missing. A simple way of doing that is:
    function add(x, y) {
        if (!x) x = 0;
        if (!y) y = 0;
        return x + y;
    }
Interaction:
    > add()
    0
    > add(5)
    5
    > add(2, 7)
    9
You can write add() more compactly by using the “or” operator ( ||). This operator returns the first operand if it is truthy and otherwise the second operand. Examples:
    > 'abc' || 'def'
    'abc'
    > '' || 'def'
    'def'
    > undefined || { foo: 123 }
    { foo: 123 }
    > { foo: 123 } || 'def'
    { foo: 123 }
Let’s use || to assign parameter default values:
    function add(x, y) {
        x = x || 0;
        y = y || 0;
        return x + y;
    }

An arbitrary number of parameters

You can also use arguments to accept an arbitrary number of parameters. One example is the following function format() that is modeled after the classic C function sprintf:
    > format('Hello %s! You have %s new message(s).', 'Jane', 5)
    'Hello Jane! You have 5 new message(s).'
The first argument is a pattern in which '%s' marks blanks. The following arguments are filled into those blanks. A simple implementation of format looks like this:
    function format(pattern) {
        for(var i=1; i < arguments.length; i++) {
            pattern = pattern.replace('%s', arguments[i]);
        }
        return pattern;
    }
Note: the loop skips the first parameter ( arguments[0]) and thus ignores pattern.

Enforcing a certain number of parameters

If you want to force a caller to provide a certain number of parameters, you need to check arguments.length, at runtime:
    function add(x, y) {
        if (arguments.length > 2) {
            throw new Error('Need at most 2 parameters');
        }
        return x + y;
    }

arguments is not an array

arguments is not an array, it is only array-like: you can access the i-th parameter via arguments[i] and you can determine how many parameters there are via arguments.length. But you can’t use Array methods such as forEach and indexOf. Further details, along with solutions are discussed in quirk 8. As a preview, the following function converts an array-like value to an array.
    function fromArray(arrayLikeValue) {
        return Array.prototype.slice.call(arrayLikeValue);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值