设置 JavaScript 函数的默认参数值

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

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

这可以在 JavaScript 中使用吗?

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

答案

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

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

正常工作。

参考: 默认参数 - MDN

如果传递任何值未定义,则默认函数参数允许使用默认值初始化形式参数。

您还可以通过解构模拟默认的命名参数

// 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 之前的版本

有很多方法,但这是我的首选方法 - 它使您可以传递任何想要的信息,包括 false 或 null。 ( typeof null == "object"

function foo(a, b) {
  a = typeof a !== 'undefined' ? a : 42;
  b = typeof b !== 'undefined' ? b : 'default_b';
  ...
}
function read_file(file, delete_after) {
    delete_after = delete_after || "my default here";
    //rest of code
}

如果它不是false值,则将其分配给delete_after的值delete_after ,否则它将分配字符串"my default here" 。有关更多详细信息,请查看Doug Crockford 对语言的调查,并查看关于 “运算符” 的部分

如果要传入一个false值(即falsenullundefined0"" ,则此方法不起作用。如果您需要传入假值,则需要使用Tom Ritter 的 answer 中的方法。

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

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;
};

使用

// 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" });

我发现类似这样的简单内容个人更为简洁易读。

function pick(arg, def) {
   return (typeof arg == 'undefined' ? def : arg);
}

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

在 ECMAScript 6 中,您实际上将能够准确地写出您拥有的东西:

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

如果不存在或undefined它将delete_after设置为false 。您现在可以将诸如Babel这样的编译器与 ES6 功能一起使用。

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

默认参数值

使用 ES6,您可能会执行JavaScript最常见的习惯用法之一,即为功能参数设置默认值。多年来我们这样做的方式应该看起来很熟悉:

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

这种模式最常用,但是当我们传递诸如

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

为什么?因为0 is falsy ,所以x || 11 results in 11 ,而不是直接传递的 0。要解决此难题,有些人会改为更详细地编写支票,如下所示:

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开始添加的一种很有帮助的语法,以简化默认值对缺失参数的分配:

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 !== undefined ? x : 11比常见的成语x || 11

默认值表达式

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

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)

function foo( x =
 (function(v){ return v + 11; })( 31 )
) {
 console.log( x );
}
foo(); // 42

该解决方案适用于 js:

function read_file(file, delete_after) {
    delete_after = delete_after || false;
    // Code
}

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

function read_file(file, delete_after)
{
    if(delete_after === undefined) { delete_after = false; }
}

作为更新... 使用 ECMAScript 6,您可以像下面这样在函数参数声明中最终设置默认值:

function f (x, y = 7, z = 42) {
  return x + y + z
}

f(1) === 50

如参考-http://es6-features.org/#DefaultParameterValues

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

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

parseInt 具有可选的第二个参数function parseInt(s, [ radix =10])但是 map 调用带有三个参数的parseInt :( elementindexarray )。

我建议您将所需的参数与可选的 / 默认值的参数分开。如果您的函数采用 1,2 或 3 个必需参数(默认值没有意义),请将它们设置为函数的位置参数,则所有可选参数都应作为单个对象的命名属性。如果您的函数需要 4 个或更多,则通过单个对象参数的属性提供所有参数可能更有意义。

在您的情况下,我建议您编写如下的 deleteFile 函数:( 编辑, instead注释 )...

// 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);

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

作为一位长期的 C ++ 开发人员(Rookie 到 Web 开发的新手:)),当我第一次遇到这种情况时,我在函数定义中进行了参数分配,就像在问题中提到的那样,如下所示。

function myfunc(a,b=10)

但是请注意,它在所有浏览器中均无法正常工作。对我来说,它适用于我的桌面上的 chrome,但不适用于 android 上的 chrome。如上文所述,更安全的选择是 -

function myfunc(a,b)
    {
    if (typeof(b)==='undefined') b = 10;
......
    }

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