JavaScript - 带有可选参数对象的函数?

11
我需要一个函数,它的参数是一个对象。如果我不传入任何参数,则会加载默认值。
类似这样的代码:
function loadMap(args) { //args is an object and its optional

   //this is what I want to do, test args and load defauts if necesary
   /*
   pseudocode:
   if args.latitude is not set then
       give it a default value

   if args.longitude is not set then
       give it a default value

    end pseudocode */

   alert("Latitude is "+args.latitude );
   alert("Longitude is "+args.longitude );
}

//outputs the default values
loadMap();

//outputs custom values
loadMap({latitude: "x.xxxx", longitude: "-x.xxxx"});

//and should work too and output one default and one custom value
loadMap({latitude: "x.xxxx"});

我在这个问题 (Is there a better way to do optional function parameters in Javascript?) 中找到了这个解决方案,但它需要使用jQuery:http://jsfiddle.net/xy84kwdv/
这几乎是我想要的,但我不想依赖于jQuery函数。
8个回答

34
当然,这个问题现在已经超过三年了(2018-03-02)。我搜索了一下这个话题,但我得到的大部分问题和排名靠前的答案似乎都已经过时了,比如thisthisthis或者this
目前,很多浏览器支持ES6/ECMAScript 2015(第六版ECMAScript)。为了兼容性,你可以使用WebpackJs(或其他打包工具)和BabelJs(或其他编译器)将你的ES6代码编译打包成ES5。而针对这个问题的ES6版本答案可能是对象解构
function drawES2015Chart({size = 'big', cords = {x: 0, y: 0}, radius = 25} = {}) {
    console.log(size, cords, radius);
    // do some chart drawing
}

drawES2015Chart({cords: {x: 18, y: 30}, radius: 30});

function fn(requiredArg, {optionalArg = 'Default Value', a = 1, b ={some: 'object'}} = {}){
    // Do with destructured values: requiredArg, optionalArg, a, and b.
    console.log(requiredArg, optionalArg, a, b);
}

因此,针对您的问题,将会是:

function loadMap({latitude = "x.xxxx", longitude = "-x.xxxx"} = {}) {
    console.log('latitude is:', latitude, 'and longitude is:', longitude);
    console.log(`latitude is: ${latitude}, and longitude is: ${longitude}`);
}

// Call the function.
loadMap({latitude: "1.2345", longitude: "-6.7890"});

5
太好了!谢谢!根据您发布的MDN链接:我想知道为什么需要在右侧使用空的{}。根据文档:您也可以编写函数而不使用右侧分配。但是,如果省略右侧分配,则调用该函数时将查找至少一个参数,而在当前形式中,您可以仅调用drawES2015Chart()而不提供任何参数 - Jose A

9
你是否正在寻找类似以下内容的信息:
function loadMap(args) { 
    args = args || {}; 
    args.latitude = args.latitude || "X.XXX"; 
    args.longitude = args.longitude || "Y.YYY"; 
    alert(args.latitude);
    alert(args.longitude);
}; 

loadMap({latitude:"custom_latitude"});

正如您所看到的,如果您只传递一个自定义值并将其余部分留空,则该代码不会按预期运行。 - JuanBonnett
我测试过了,它完美地运行着...代码很干净,没有像其他10000个算法那样复杂...你的解决方案是迄今为止最好的! - JuanBonnett
1
这将会破坏 loadMap({latitude: 0}) - Barmar
啊,是的...我们在谈论0就像FALSE一样...没关系,我们可以解决它。 - JuanBonnett
@Barmar 您是对的,我没有考虑到它对于纬度和经度是必需的。我同意可以使用一个简单的函数检查所有参数是否为未定义,但允许为零来测试它。但显然OP已经满意了,所以我会保留它原样。 - html_programmer
1
没问题...我可以用一些三元操作来解决! - JuanBonnett

4
这使得参数对象变成可选的,并且使单个属性也变成可选的:
var defaults = { latitude: x, longitude: y };
function loadMap(args) {
    args = args || {};
    for (var key in defaults) {
        if (!(key in args)) {
            args[key] = default[key];
        }
    }
    ...
}

我添加了一条注释,但我没有好好阅读你的答案...这种方法似乎也可以,而且非常简洁。 - JuanBonnett

1

0

如何在JavaScript中重载函数? 请查看对原帖的第二个答案,它提供了一种不使用jQ的替代方法。

注意:如果args传递但评估为true,则Kim的代码会导致逻辑错误。 更好的解决方法:     optionalArg =(typeof optionalArg ===“undefined”)?“defaultValue”:optionalArg;


1
不要发布仅包含链接的答案。将问题标记为重复。 - Barmar

0

Fisher的回答应该被接受。此外,如果您想重命名任何解构变量同时仍保持默认值,可以这样做:

function findByCoordinates({coordinates: cords = {x: 0, y: 0}} = {}) {
  console.log(cords);
  // Some calculation...
}

0
遇到了这个问题,因为我想要一个具有许多属性的默认配置对象。所以,在函数参数中进行解构是不可行的。 Spread语法确实有一些注意事项。但是,复杂对象不太可能作为可选参数传递。
let defaultArgs = { lat: 'x.xxxx', lng: 'x.xxxx' };
function loadMap(args) {
  let { lat,lng } = { ...defaultArgs, ...args };
  console.log(`Lat: ${lat} Lng: ${lng}`)
}
loadMap();
loadMap({ lat: 1.2345 });
loadMap({ lat: 1.2345, lng: 1.2345 });

控制台日志:
Lat: x.xxxx Lng: x.xxxx
Lat: 1.2345 Lng: x.xxxx
Lat: 1.2345 Lng: 1.2345

-1

过度,引入完整的对象克隆(ECMAScript 5.1)

function cloneOwnProperties(A, B, overwrite) { // this is shallow
    var i, p;
    if (!(A instanceof Object)) {
        if (undefined === A) A = {};
        else throw new TypeError('cloneOwnProperties called on non-object');
    }
    if (!B) B = {};
    p = Object.getOwnPropertyNames(A);
    for (i = 0; i < p.length; ++i)
        if (overwrite || !(p[i] in B))
            Object.defineProperty(B, p[i], Object.getOwnPropertyDescriptor(A, p[i]));
    return B;
}

// and for completeness
function cloneObject(obj_in, clone_seal, clone_frozen) {
    var obj_out;
    if (!(obj_in instanceof Object))
        throw new TypeError('cloneObject called on non-object');
    obj_out = Object.create(Object.getPrototypeOf(obj_in));
    cloneOwnProperties(obj_in, obj_out, true);
    if (clone_seal && Object.isSealed(obj_in)) Object.seal(obj_out);
    if (clone_frozen && Object.isFrozen(obj_in)) Object.freeze(obj_out);
    return obj_out;
}
// back on topic

现在您可以使用它来设置一些默认值

function foo(bar) {
    bar = cloneOwnProperties(bar, {
        fizz: true,
        buzz: false
    }, true);
    return bar;
}

foo({buzz: 'user_value'}); // {fizz: true, buzz: "user_value"}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接