为javascript函数设置默认参数值

Set a default parameter value for a JavaScript function

我希望一个javascript函数具有可选参数,我将其设置为默认值,如果未定义该值,则使用该参数(如果传递该值,则忽略该参数)。在Ruby中,您可以这样做:

1
2
3
def read_file(file, delete_after = false)
  # code
end

这在javascript中有效吗?

1
2
3
function read_file(file, delete_after = false) {
  // Code
}

从ES6/ES2015开始,默认参数在语言规范中。

1
2
3
function read_file(file, delete_after = false) {
  // Code
}

只是工作。

参考:默认参数-MDN

Default function parameters allow formal parameters to be initialized with default values if no value or undefined is passed.

还可以通过销毁来模拟默认命名参数:

1
2
3
4
5
// the `= {}` below lets you call the function without any parameters
function myFor({ start = 5, end = 1, step = -1 } = {}) { // (A)
    // Use the variables `start`, `end` and `step` here
    ···
}

前ES2015

有很多方法,但这是我的首选方法——它可以让你传递任何你想要的东西,包括假或空。(typeof null =="object")

1
2
3
4
5
function foo(a, b) {
  a = typeof a !== 'undefined' ? a : 42;
  b = typeof b !== 'undefined' ? b : 'default_b';
  ...
}


1
2
3
4
function read_file(file, delete_after) {
    delete_after = delete_after ||"my default here";
    //rest of code
}

它将delete_after的值赋值给delete_after,如果它不是一个假值,否则它将赋值给字符串"my default here"。有关更多详细信息,请查看DougCrockford的语言调查,并查看有关运算符的部分。

如果你想传递一个虚假的值,即falsenullundefined0"",这种方法就不起作用。如果您需要传入错误的值,则需要使用TomRitter答案中的方法。

当处理一个函数的多个参数时,通常允许使用者传递对象中的参数参数,然后将这些值与包含函数默认值的对象合并是很有用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function read_file(values) {
    values = merge({
        delete_after :"my default here"
    }, values || {});

    // rest of code
}

// simple implementation based on $.extend() from jQuery
function merge() {
    var obj, name, copy,
        target = arguments[0] || {},
        i = 1,
        length = arguments.length;

    for (; i < length; i++) {
        if ((obj = arguments[i]) != null) {
            for (name in obj) {
                copy = obj[name];

                if (target === copy) {
                    continue;
                }
                else if (copy !== undefined) {
                    target[name] = copy;
                }
            }
        }
    }

    return target;
};

使用

1
2
3
4
5
// will use the default delete_after value
read_file({ file:"my file" });

// will override default delete_after value
read_file({ file:"my file", delete_after:"my value" });


我发现像这样简单的东西更简洁易读。

1
2
3
4
5
6
7
function pick(arg, def) {
   return (typeof arg == 'undefined' ? def : arg);
}

function myFunc(x) {
  x = pick(x, 'my default');
}


在EcmaScript 6中,您实际上能够准确地写下您拥有的内容:

1
2
3
function read_file(file, delete_after = false) {
  // Code
}

如果不存在delete_afterundefined,这会将delete_after设置为false。今天,您可以将ES6功能与Babel等蒸腾器一起使用。

有关更多信息,请参阅MDN文章。


默认参数值

使用ES6,您可以使用JavaScript中最常见的一个习惯用法来设置函数参数的默认值。多年来我们这样做的方式应该很熟悉:

1
2
3
4
5
6
7
8
9
function foo(x,y) {
 x = x || 11;
 y = y || 31;
 console.log( x + y );
}
foo(); // 42
foo( 5, 6 ); // 11
foo( 5 ); // 36
foo( null, 6 ); // 17

这种模式是最常用的,但当我们传递如下值时是危险的

1
2
foo(0, 42)
foo( 0, 42 ); // 53 <-- Oops, not 42

为什么?因为0 is falsyx || 11 results in 11不是直接传给0的。为了解决这个问题,有些人会这样更详细地写支票:

1
2
3
4
5
6
7
function foo(x,y) {
 x = (x !== undefined) ? x : 11;
 y = (y !== undefined) ? y : 31;
 console.log( x + y );
}
foo( 0, 42 ); // 42
foo( undefined, 6 ); // 17

现在我们可以检查一个很好的有用语法,它是从ES6开始添加的,用于简化默认值对缺少参数的分配:

1
2
3
4
5
6
7
8
9
10
11
12
function foo(x = 11, y = 31) {
 console.log( x + y );
}

foo(); // 42
foo( 5, 6 ); // 11
foo( 0, 42 ); // 42
foo( 5 ); // 36
foo( 5, undefined ); // 36 <-- `undefined` is missing
foo( 5, null ); // 5 <-- null coerces to `0`
foo( undefined, 6 ); // 17 <-- `undefined` is missing
foo( null, 6 ); // 6 <-- null coerces to `0`

函数声明中的x = 11比更常见的习惯用法x || 11更像x !== undefined ? x : 11

默认值表达式

Function默认值可以不仅仅是简单的值,如31;它们可以是任何有效的表达式,甚至是function call

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function bar(val) {
 console.log("bar called!" );
 return y + val;
}
function foo(x = y + 3, z = bar( x )) {
 console.log( x, z );
}
var y = 5;
foo(); //"bar called"
 // 8 13
foo( 10 ); //"bar called"
 // 10 15
y = 6;
foo( undefined, 10 ); // 9 10

如您所见,默认值表达式的计算比较缓慢,这意味着只有在需要时才运行它们——也就是说,当参数的参数被省略或未定义时。

默认值表达式甚至可以是内联函数表达式调用-通常称为立即调用的函数表达式(IIFE)

1
2
3
4
5
6
function foo( x =
 (function(v){ return v + 11; })( 31 )
) {
 console.log( x );
}
foo(); // 42

该解决方案在JS中对我有效:

1
2
3
4
function read_file(file, delete_after) {
    delete_after = delete_after || false;
    // Code
}


只需使用与未定义的显式比较。

1
2
3
4
function read_file(file, delete_after)
{
    if(delete_after === undefined) { delete_after = false; }
}

作为更新…使用ECMAScript 6,您可以在函数参数声明中最终设置默认值,如下所示:

1
2
3
4
5
function f (x, y = 7, z = 42) {
  return x + y + z
}

f(1) === 50

如-http://es6 features.org/defaultParameterValues所引用


作为一个长时间的C++开发人员(新手到Web开发:),当我第一次遇到这种情况时,我做了函数定义中的参数赋值,就像它在下面提到的那样。

1
function myfunc(a,b=10)

但要注意,它不能在浏览器中始终如一地工作。对我来说,它可以在我的桌面上使用Chrome,但不能在Android上使用Chrome。更安全的选择,正如上面提到的那样-

1
2
3
4
5
    function myfunc(a,b)
    {
    if (typeof(b)==='undefined') b = 10;
......
    }

这个答案的目的不是重复其他人已经提到的相同的解决方案,而是通知函数定义中的参数分配可以在某些浏览器上工作,但不依赖于它。


我强烈建议在JavaScript中使用默认参数值时要格外小心。当与更高阶函数(如forEachmapreduce结合使用时,通常会产生错误。例如,考虑这一行代码:

1
['1', '2', '3'].map(parseInt); // [1, NaN, NaN]

parseInt有一个可选的第二个参数function parseInt(s, [radix=10]),但是map用三个参数(element、index和array)调用parseInt

我建议您将所需参数从可选/默认值参数中分离出来。如果函数接受1、2或3个没有默认值意义的必需参数,则将它们作为函数的位置参数,任何可选参数都应作为单个对象的命名属性。如果函数取4个或更多,那么通过单个对象参数的属性提供所有参数可能更有意义。

在您的情况下,我建议您这样编写您的deletefile函数:(根据instead的注释进行编辑)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// unsafe
function read_file(fileName, deleteAfter=false) {
    if (deleteAfter) {
        console.log(`Reading and then deleting ${fileName}`);
    } else {
        console.log(`Just reading ${fileName}`);
    }
}

// better
function readFile(fileName, options) {
  const deleteAfter = !!(options && options.deleteAfter === true);
  read_file(fileName, deleteAfter);
}

console.log('unsafe...');
['log1.txt', 'log2.txt', 'log3.txt'].map(read_file);

console.log('better...');
['log1.txt', 'log2.txt', 'log3.txt'].map(readFile);

运行上面的代码片段说明了未使用参数的默认参数值背后隐藏的危险。


对于任何有兴趣在Microsoft Edge中使用There代码的人,不要在函数参数中使用默认值。

1
2
3
function read_file(file, delete_after = false) {
    #code
}

在该示例中,边缘将引发一个错误"expecting")'"

为了避开这种使用

1
2
3
4
5
6
7
function read_file(file, delete_after) {
  if(delete_after == undefined)
  {
    delete_after = false;
  }
  #code
}

截至2016年8月8日,这仍然是一个问题。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
function helloWorld(name, symbol = '!!!') {
    name = name || 'worlds';
    console.log('hello ' + name + symbol);
}

helloWorld(); // hello worlds!!!

helloWorld('john'); // hello john!!!

helloWorld('john', '(>.<)'); // hello john(>.<)

helloWorld('john', undefined); // hello john!!!

helloWorld(undefined, undefined); // hello worlds!!!

如果要使用最新的ECMA6语法,请使用此选项:

1
2
3
4
5
6
function myFunction(someValue ="This is DEFAULT!") {
  console.log("someValue -->", someValue);
}

myFunction("Not A default value") // calling the function without default value
myFunction()  // calling the function with default value

它叫default function parameters。如果没有传递值或未定义,它允许用默认值初始化形参。注意:它不能与Internet Explorer或旧版本的浏览器一起使用。

为了获得最大可能的兼容性,请使用:

1
2
3
4
5
6
7
function myFunction(someValue) {
  someValue = (someValue === undefined) ?"This is DEFAULT!" : someValue;
  console.log("someValue -->", someValue);
}

myFunction("Not A default value") // calling the function without default value
myFunction()  // calling the function with default value

这两个函数的行为与这些示例中的每一个都完全相同,这取决于这样一个事实:如果调用该函数时没有传递参数值,那么参数变量将是undefined


ES6:正如大多数答案中已经提到的,在ES6中,您可以简单地初始化一个参数和一个值。

ES5:大多数给出的答案对我来说都不够好,因为在某些情况下,我可能不得不向函数传递错误的值,如0nullundefined。要确定某个参数是否未定义,因为这是我传递的值,而不是由于根本没有定义而未定义的值,请执行以下操作:

1
2
3
4
function foo (param1, param2) {
   param1 = arguments.length >= 1 ? param1 :"default1";
   param2 = arguments.length >= 2 ? param2 :"default2";
}


按照语法

1
2
3
function [name]([param1[ = defaultValue1 ][, ..., paramN[ = defaultValueN ]]]) {
   statements
}

可以定义形式参数的默认值。并使用typeof函数检查未定义的值。


1
2
3
4
5
6
function throwIfNoValue() {
throw new Error('Missing argument');
}
function foo(argValue = throwIfNoValue()) {
return argValue ;
}

这里foo()是一个函数,它有一个名为argValue的参数。如果在这里不传递函数调用中的任何内容,那么将调用函数throwifnovalue(),并将返回的结果赋给唯一的参数argValue。这就是如何将函数调用用作默认参数的方法。这使得代码更加简单易读。

此示例取自此处


如果您使用的是ES6+,可以按以下方式设置默认参数:

1
2
3
4
5
function test (foo = 1, bar = 2) {
  console.log(foo, bar);
}

test(5); // foo gets overwritten, bar remains default parameter

如果需要ES5语法,可以按以下方式执行:

1
2
3
4
5
6
7
8
function test(foo, bar) {
  foo = foo || 2;
  bar = bar || 0;
 
  console.log(foo, bar);
}

test(5); // foo gets overwritten, bar remains default parameter

在上述语法中,使用OR运算符。OR运算符始终返回第一个值,如果该值可以转换为true,则返回右侧值。当在没有相应参数的情况下调用函数时,JS引擎将参数变量(本例中的bar设置为undefined。然后,undefined转换为false,因此,OR运算符返回值0。


是的,ES6完全支持使用默认参数:

1
2
3
function read_file(file, delete_after = false) {
  // Code
}

1
2
3
const read_file = (file, delete_after = false) => {
    // Code
}

但在ES5之前,您可以轻松做到:

1
2
3
4
function read_file(file, delete_after) {
  var df = delete_after || false;
  // Code
}

也就是说,如果有这个值,就使用这个值,否则,就使用||操作之后的第二个值,该操作执行相同的操作…

注:如果将一个值传递给es6-one,即使该值不稳定,也会被新值替换,如null""。但是,只有当传递的值是真实的,ES5-One才会被替换,这是因为||的工作方式…


如果出于某种原因,您不在ES6上并且正在使用lodash,下面是通过_.defaultTo方法默认函数参数的简明方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var fn = function(a, b) {
  a = _.defaultTo(a, 'Hi')
  b = _.defaultTo(b, 'Mom!')

  console.log(a, b)
}

fn()                 // Hi Mom!
fn(undefined, null)  // Hi Mom!
fn(NaN, NaN)         // Hi Mom!
fn(1)                // 1"Mom!"
fn(null, 2)          // Hi 2
fn(false, false)     // false false
fn(0, 2)             // 0 2
1
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js">

如果当前值为NaN、null或Undefined,则设置默认值。


1
2
3
def read_file(file, delete_after = false)
  # code
end

以下代码可能在这种情况下工作,包括ECMAScript 6(ES6)和早期版本。

1
2
3
4
5
6
7
8
function read_file(file, delete_after) {
    if(delete_after == undefined)
        delete_after = false;//default value

    console.log('delete_after =',delete_after);
}
read_file('text1.txt',true);
read_file('text2.txt');

当调用时跳过函数的参数值时,语言中的默认值起作用,在javascript中,它被分配给未定义的。这种方法在编程上看起来不具有吸引力,但具有向后兼容性。


是的,这被称为默认参数

如果没有传递值或未定义,则默认函数参数允许用默认值初始化形参。

Syntax:

1
2
3
function [name]([param1[ = defaultValue1 ][, ..., paramN[ = defaultValueN ]]]) {
   statements
}

描述:

函数的参数默认为未定义,但是,在某些情况下,设置不同的默认值可能很有用。这是默认参数可以帮助的地方。

在过去,设置默认值的一般策略是测试函数体中的参数值,如果参数值未定义,则赋值。如果调用中没有提供值,则其值将未定义。您必须设置条件检查以确保参数未定义

使用ES2015中的默认参数,不再需要签入函数体。现在您可以简单地在函数头中放置一个默认值。

差异示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// OLD METHOD
function multiply(a, b) {
  b = (typeof b !== 'undefined') ?  b : 1;
  return a * b;
}

multiply(5, 2); // 10
multiply(5, 1); // 5
multiply(5);    // 5


// NEW METHOD
function multiply(a, b = 1) {
  return a * b;
}

multiply(5, 2); // 10
multiply(5, 1); // 5
multiply(5);    // 5

不同的语法示例:

填充未定义的值与其他错误值:

即使在调用时显式设置了该值,num参数的值也是默认值。

1
2
3
4
5
6
7
8
9
10
function test(num = 1) {
  console.log(typeof num);
}

test();          // 'number' (num is set to 1)
test(undefined); // 'number' (num is set to 1 too)

// test with other falsy values:
test('');        // 'string' (num is set to '')
test(null);      // 'object' (num is set to null)

在调用时评估:

默认参数在调用时进行计算,因此与其他一些语言不同,每次调用函数时都会创建一个新对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function append(value, array = []) {
  array.push(value);
  return array;
}

append(1); //[1]
append(2); //[2], not [1, 2]


// This even applies to functions and variables
function callSomething(thing = something()) {
 return thing;
}

function something() {
  return 'sth';
}

callSomething();  //sth

默认参数可用于以后的默认参数:

已遇到的参数可用于以后的默认参数

1
2
3
4
5
6
7
8
9
10
11
12
13
function singularAutoPlural(singular, plural = singular + 's',
                        rallyingCry = plural + ' ATTACK!!!') {
  return [singular, plural, rallyingCry];
}

//["Gecko","Geckos","Geckos ATTACK!!!"]
singularAutoPlural('Gecko');

//["Fox","Foxes","Foxes ATTACK!!!"]
singularAutoPlural('Fox', 'Foxes');

//["Deer","Deer","Deer ... change."]
singularAutoPlural('Deer', 'Deer', 'Deer peaceably and respectfully \ petition the government for positive change.')

函数体内部定义的函数:

Gecko 33(火狐33/Thunderbird 33/Seamonkey 2.30)中介绍。在函数体中声明的函数不能在默认参数内引用并引发引用错误(当前在spidermonkey中为typeerror,请参阅bug 1022967)。默认参数总是先执行,函数体内部的函数声明随后计算。

1
2
3
4
// Doesn't work! Throws ReferenceError.
function f(a = go()) {
  function go() { return ':P'; }
}

默认参数后没有默认值的参数:

在gecko 26(firefox 26/thunderbird 26/seamonkey 2.23/firefox os 1.2)之前,以下代码导致了语法错误。这已在bug 777060中修复,并在以后的版本中按预期工作。参数仍然设置为从左到右,覆盖默认参数,即使以后有没有默认值的参数。

1
2
3
4
5
6
function f(x = 1, y) {
  return [x, y];
}

f(); // [1, undefined]
f(2); // [2, undefined]

具有默认值分配的已破坏参数:

可以使用带有析构函数赋值符号的默认值赋值

1
2
3
4
5
function f([x, y] = [1, 2], {z: z} = {z: 3}) {
  return x + y + z;
}

f(); // 6

是的,这将在JavaScript中工作。您也可以这样做:

1
2
3
4
5
6
7
8
9
10
function func(a=10,b=20)
{
    alert (a+' and '+b);
}

func(); // Result: 10 and 20

func(12); // Result: 12 and 20

func(22,25); // Result: 22 and 25