如何在JavaScript对象字面量中按条件添加属性

29

我试图做以下事情以满足代码构建器(特别是Sencha Cmd)的要求。

这就是我需要做的实质。关键因素在于函数体必须以对象文字的返回结束。由于构建器的限制,我无法返回变量。所以,如果参数'includeB'为true,如何在伪代码下面的点处添加属性'b',但如果为false,则完全不添加属性。即b==undefined或b==null是不允许的。

也许这是不可能的。

function create(includeB) {
        // Can have code here but the final thing MUST be a return of the literal.
        // ...
    return {
        a : 1
        // pseudo code:
        // if (includeB==true) then create a property called b 
        // and assign a value of 2 to it. 
        // Must be done right here within this object literal
    }
}

var obj = create(false);
// obj must have property 'a' ONLY

var obj = create(true);
// obj must have properties 'a' and 'b'

感谢您的阅读和考虑,

Murray


1
什么阻止你改变函数返回的对象?这似乎是一个XY问题 - zzzzBov
我无法访问它。构建器正在使用Java应用程序(Sencha Cmd)从文件系统中读取JS。提供的函数是一个测试用例,因为尝试展示完整的真实情况会太令人困惑。测试用例是问题的本质。 - Murrah
可能是有条件地设置JSON对象属性的重复问题。 - rofrol
可能是https://dev59.com/0c6sz4gBFxS5KdRjbLWs的重复。 - djskinner
8个回答

57

如果您可以使用ES6,请使用扩展属性

function create(includeB) {
    return {
        a : 1,
        ...(includeB ? { b: 2 } : {}),
    };
}

这是在许多情况下优雅的语法,但需要Object Rest/Spread,目前(2017-10-29)仅为一些未来ECMAScript版本的第3阶段建议; 与Babel的转换配合良好。 - Thomas Luzat
29
你甚至可以编写 ...(includeB && { b: 2 } ) - marco

5

您已经基本展示了使用构造函数而不是对象字面量的用例:

function CustomObject(includeB) {
    this.a = 1;
    if (includeB) {
        this.b = 2;
    }
}

//has `a` only
var obj1 = new CustomObject(false);

//has `a` and `b`
var obj2 = new CustomObject(true);

在重新阅读了您的问题后,似乎您在修改函数方面的权限有限。如果我正确理解了您的问题,您只能改变脚本的一小部分:

function create(includeB) {
    // modifications may be done here

    // the rest may not change
    return {
        a : 1
    }
}

var obj = create(false);
// obj must have property 'a' ONLY

var obj = create(true);
// obj must have properties 'a' and 'b'

如果是这种情况,你可以简单地跳过函数的后半部分:
function create(includeB) {
    if (includeB) {
        return {
            a: 1,
            b: 2
        };
    }
    return {
        a: 1
    };
}

好的。抱歉耽搁了。我在使用构建器测试这个解决方案。是的!这个语法对于构建器来说是可以接受的。我之前尝试过使用'else'块,但没有想到尝试直接返回。谢谢! - Murrah
要明确的是,这就是让构建工具满意的语法:function create(includeB) { if (includeB) { return { a: 1, b: 2 }; } return { a: 1 }; } - Murrah

1
你不能在JavaScript的文字定义中放置布尔逻辑。所以,如果你的构建器要求返回的对象只能被定义为JavaScript字面量,那么你不能以这种方式有条件地定义属性。
如果您能在函数内创建一个对象,使用逻辑修改该对象,然后返回该对象,那么这就相当容易了。
function create(includeB) {
    var x = {
        a: 1
    };
    if (includeB) {
        x.b = 2;
    }
    return x;
}

您的另一个选择是包装创建函数并在创建函数之外执行它。
function myCreate(includeB) {
    var x = create(includeB)
    if (includeB) {
        x.b = 2;
    }
    return x;
}

或者,你甚至可以透明地包装create函数,这样调用者仍然使用create(),但它的行为已经被改变。

var oldCreate = create;
create = function(includeB) {
    var x = oldCreate(includeB);
    if (includeB) {
        x.b = 2;
    }
    return x;
}

谢谢。是的,必须在字面上完成。我觉得我可能要求太多了! - Murrah
@Murrah - 我添加了两个选项,让你可以包装创建函数并在现有的create()函数之外添加你的逻辑。 - jfriend00
谢谢。再次,特定情况下的构建器要求是,不论我给它什么函数,它都必须有文字上的返回值。在这个特殊情况下,return x; 是“非法”的。 - Murrah
@Murrah - 我之前的两个建议并没有修改实际的 create() 函数。它可以保持原样,不需要 .b 属性。我是在建议您如何添加一些普通的 JavaScript 代码来包装或修改 create() 函数,以使其按照您想要的方式运行。您不能在项目中添加常规的 JavaScript 吗? - jfriend00

1
我最近也需要做这个问题,并且发现可以在对象定义中使用自调用函数(如果使用ES6)。这类似于被接受的答案,但对其他需要在不先定义构造函数的情况下执行此操作的人可能有用。
例如:
let obj = (() => {
  let props = { a: 1 };
  if ( 1 ) props.b = 2;
  return props;
})();

将对象制作为:{ a: 1, b: 2 }

对于更复杂的对象很方便,可以保持构造连续性:

let obj = {
  a: 1,
  b: (() => {
    let props = { b1: 1 };
    if ( 1 ) props.b2 = 2;
    return props;
    })(),
  c: 3
}

制造对象:
{
  a: 1,
  b: {
    b1: 1,
    b2: 2
  },
  c: 3
}

0
你可以稍后定义它:
var hasA = create(); // has hasA.a

var hasBoth = create();
hasBoth.b = 2; //now has both

或者,使用您在create中的参数:

function create (includeB) {
  var obj = { 
    a : 1
  };
  if (includeB) {
     obj.b = 2;
  }
  return obj;
}

是的,通常我会这样做。就像我说的,在这种情况下由于外部要求,我无法这样做,因为代码生成器基本上正在使用create函数的结果,所以我无法访问它。如果可能的话,必须在伪代码处完成。 - Murrah
@Murrah 你无法在对象内完成这个操作。也许你可以尝试我回答中的第一种选项? - bozdoz
1
@Murrah:对象字面量具有非常特定的语法。这种语法不提供任何条件设置属性的方法。 - Felix Kling
你可以将b设置为一个返回2或undefined的函数 @Murrah - bozdoz
正确的@zzzzBov,但它是一个选项。老实说,问题中给出的示例似乎不足以解决OP试图解决的任何真正问题。 - bozdoz

0
这样怎么样:
function create(includeB) {
    return includeB && { a:1, b:2 } || { a:1 };
}

includeB为真时,create函数将返回{a:1, b:2}。如果includeB为假,则返回or后面的任何内容 - 在这种情况下,是{a:1}对象。 create(true)返回{ a:1, b:2 }create(false)返回{ a:1 }

我认为你正在寻找三元运算符:condition ? true : false; - bozdoz
我不确定这种符号叫什么,但它似乎可以实现OP所要求的功能。 - Blundering Philosopher
我猜这是另一个三目运算符。我本以为它会返回布尔值或一个对象。 - bozdoz

0

以下代码应该可以正常工作。希望这能帮到你。

function create(includeB){

var object = {
    a: 1
};

if (includeB)
    object.b = 2;

return object;

}


谢谢。与上述相同,不能返回一个对象,必须是字面值。 - Murrah

0
如果您想使用一个声明来一次满足同样的需求,而不会有太多冗余代码,您也可以简单地执行以下操作:
var created = function(includeB) {
    var returnObj = { a : 1 };

    if(includeB) { returnObj.b = 2; }

    return returnObj;
}}(); //automatically runs and assigns returnObj to created

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