跳过 JavaScript 函数中的参数

我有一个这样的功能:

function foo(a, b, c, d, e, f) {
}

为了只用 f参数调用这个函数,我知道我应该这样做:

foo(undefined, undefined, undefined, undefined, undefined, theFValue);

有没有不那么冗长的方法?

解决方案 :
我选择了一些建议的解决方案(没有使用 helper 第三个函数)

// zero - ideal one, actually not possible(?!)
foo(f: fValue);


// one - asks a "strange" declaration
var _ = undefined;
foo(_, _, _, _, _, fValue);


// two - asks the {} to be used instead of a 'natural' list of args
//     - users should be aware about the internal structure of args obj
//       so this option is not 'intellisense friendly'
function foo(args){
// do stuff with `args.a`, `args.b`, etc.
}
foo({f: fValue});
81799 次浏览

处理可选参数的一个更好的方法是传递一个对象,您可以查找这个对象的属性:

function foo(options) {
var a = options.a,
b = options.b,
c = options.c,
d = options.d,
e = options.e,
f = options.f;
}


foo({ f: 15 });

你使用 apply:

foo.apply(this, Array(5).concat([theFValue]));

在本例中,5是要跳过的参数数量。

把它包装成一个函数:

function call(fn, skipParams, parameter) {
fn.apply(this, Array(skipParams).concat([parameter]));
}


call(foo, 5, theFValue);

但是,在这种情况下,this的作用域是不同的,因此您可能也需要通过它:

function call(fn, skipParams, parameter, thisArg) {
fn.apply(thisArg, Array(skipParams).concat([parameter]));
}


call(foo, 5, theFValue, this);

同样,这个实现只允许传递1个参数。让我们改进一下:

function call(fn, skipParams, parameters, thisArg) {
fn.apply(thisArg, Array(skipParams).concat(parameters));
}


call(foo, 5, [theFValue, theGValue, theHValue], this);

开始变得“有点”冗长了。它也不能很好地处理第一个参数之后缺少的参数,除非您想传递 undefined:

call(foo, 5, [theFValue, theGValue, theHValue, undefined, theJValue], this);

或者,完全不同的东西:

var _ = undefined;
foo(_,_,_,_,_, theFValue);

一个更严肃的问题是:

处理可选参数的最佳选择是改变处理参数的方式:

function foo(parameters){
// do stuff with `parameters.a`, `parameters.b`, etc.
}


foo({c: 1, g: false});

这种方法没有受到前面示例中 任何缺点的影响。

如果这是你想经常做的事情,那么考虑一个简单的包装:

function bar(f) {
foo(undefined, undefined, undefined, undefined, undefined, f);
}

如果你只做这一次,或者你想要参数的随机排列,那么这种方法并不是最好的。

对部分应用程序使用 bind:

function foo(a, b, c, d, e, f) {
document.write(f);
}


function skip(f, n) {
while (n--) {
f = f.bind(null, undefined);
}
return f;
}


skip(foo, 5)('hallo');

例如:

foo(undefined, undefined, undefined, undefined, undefined, arg1, arg2);

。等于:

foo(...Array(5), arg1, arg2);

。或:

foo(...[,,,,,], arg1, arg2);

例如:

foo(undefined, arg1, arg2);

。等于:

foo(...Array(1), arg1, arg2);

。或:

foo(...[,], arg1, arg2);

例如:

foo(arg1, arg2);

。等于:

foo(...Array(0), arg1, arg2);

。或:

foo(...[], arg1, arg2);

如果您将传递一个属性名为 F的对象,那么您可以使用具有 ES6语法的 破坏性转让,如下所示:

function foo({ f }) {
console.log(f);
}
    

foo({ g: 5, f: 10 });

跳过功能:

const skip = (num) => new Array(num);

跳过初始参数:

foo(...skip(4), f);

跳过末端参数:

foo(f, ...skip(4));

跳过中间参数:

foo(f, ...skip(4), f2);

怎么样

function multiply(a = 2, b = 1) {
return a * b;
}


console.log(multiply(undefined, 3));
// expected output: 6

如果传递未定义的参数,它将使用定义中的默认值。

我提供了一些方法,可以帮助您实现,如下所示,

  1. 解构分配 (推荐)
  2. 可选的 _ chaining

方法1: 破坏任务

例子1

function Person(name, {id="007", age=-1, info={msg:null, mood:undefined}}) {
return [name, id, age, info.msg, info.mood]
}


// 👇 Test Only
for (const [result, expected] of [
[Person("Carson", {}), // If you don't need any options then must set "" or {}
["Carson", "007", -1, null, undefined]
],
[Person("Aoo", {
age: 29,
info: {
msg: "hello world"
}
}),
["Aoo", "007", 29, "hello world", undefined]
],
[Person("Boo", {
id: "003",
info: {
mood: "Happy"
}
}),
["Boo", "003", -1, null, "Happy"]
]
]) {
console.log(JSON.stringify(result))
console.log(JSON.stringify(result) === JSON.stringify(expected))
}

例子2

const user = {
id: 42,
displayName: 'jdoe',
fullName: {
firstName: 'John',
lastName: 'Doe'
}
};


function userId({id}) {
return id;
}


function whois({displayName, fullName: {firstName: name}}) {
return `${displayName} is ${name}`;
}


console.log(userId(user)); // 42
console.log(whois(user));  // "jdoe is John"

来自 对象 _ 解构 搜索 Unpacking fields from objects passed as a function parameter的源代码

方法2

使用 可选的 _ chaining设置默认值

const val = obj ?? "default value" // if obj is undefined then val = default value
const val = obj?.msg // equal to obj.msg if {msg:...} exists in the obj. Otherwise, undefined

比如说

/*
Assume your options is:
{
id:"",
info:{
msg:"",
mood: "",
}
}
*/
function MyFunc(name, options = {}) {
const id = options.id ?? "007"
const msg = options.info?.msg ?? null
const mood = options.info?.mood
// ...
}

例子

function Person(name, options = {}) {
const id = options.id ?? "007"
const msg = options.info?.msg ?? null
const mood = options.info?.mood
return [name, id, msg, mood]
}




for (const [result, expected] of [
[Person("Carson"),
["Carson", "007", null, undefined]
],
[Person("Aoo", {
info: {
msg: "hello world"
}
}),
["Aoo", "007", "hello world", undefined]
],
[Person("Boo", {
id: "003",
info: {
mood: "Happy"
}
}),
["Boo", "003", null, "Happy"]
]
]) {
console.log(JSON.stringify(result) === JSON.stringify(expected))
}

方法二: 延伸

如果您想让 IDE 知道选项是什么,您可以考虑使用下面的方法,

function PersonOptions(options={}) {
this.id = options.id ?? "007"
this.msg = options.info?.msg ?? null
this.mood = options.info?.mood
}


function Person2(name, options = new PersonOptions()) {
return [name, options.id, options.msg, options.mood]
}


for (const [result, expected] of [
[Person2("Carson"),
["Carson", "007", null, undefined]
],
[Person2("Aoo", new PersonOptions({
info: {
msg: "hello world"
}
})),
["Aoo", "007", "hello world", undefined]
],
[Person2("Boo", new PersonOptions({
id: "003",
info: {
mood: "Happy"
}
})),
["Boo", "003", null, "Happy"]
]
]) {
console.log(JSON.stringify(result) === JSON.stringify(expected))
}