js动态调用函数
在 闭包 中,如果 onFinished
和 sayHello
是闭包内的局部函数,而不是全局函数或对象方法,那么直接通过函数名(字符串)调用会变得复杂,因为闭包内的函数无法通过 window
或全局对象访问。
以下是几种在闭包中实现动态调用函数的方法:
1. 使用函数映射(推荐)
在闭包中维护一个函数映射表(对象),将函数名与函数本身关联起来。
function createClosure() {
// 闭包内的函数
function sayHello(name) {
console.log(`Hello, ${name}!`);
}
function add(a, b) {
console.log(`Sum: ${a + b}`);
}
// 函数映射表
const functionMap = {
sayHello,
add
};
// onFinished 实现
function onFinished(functionName, ...args) {
if (typeof functionMap[functionName] === 'function') {
functionMap[functionName](...args); // 通过映射表调用函数
} else {
console.error(`函数 ${functionName} 不存在或不是一个函数`);
}
}
return onFinished;
}
// 创建闭包并获取 onFinished
const onFinished = createClosure();
// 调用 onFinished
onFinished('sayHello', 'Alice'); // 输出: Hello, Alice!
onFinished('add', 2, 3); // 输出: Sum: 5
onFinished('nonExistentFunction'); // 输出: 函数 nonExistentFunction 不存在或不是一个函数
2. 使用 eval
(不推荐)
在闭包中,可以通过 eval
动态调用局部函数,但这种方法存在安全性和性能问题,不推荐使用。
function createClosure() {
// 闭包内的函数
function sayHello(name) {
console.log(`Hello, ${name}!`);
}
function add(a, b) {
console.log(`Sum: ${a + b}`);
}
// onFinished 实现
function onFinished(functionName, ...args) {
try {
eval(`${functionName}(${args.map(arg => JSON.stringify(arg)).join(',')})`);
} catch (error) {
console.error(`函数 ${functionName} 不存在或执行出错:`, error);
}
}
return onFinished;
}
// 创建闭包并获取 onFinished
const onFinished = createClosure();
// 调用 onFinished
onFinished('sayHello', 'Bob'); // 输出: Hello, Bob!
onFinished('add', 5, 7); // 输出: Sum: 12
onFinished('nonExistentFunction'); // 输出: 函数 nonExistentFunction 不存在或执行出错: ReferenceError
3. 将函数暴露到闭包外
如果闭包内的函数需要被外部调用,可以将它们暴露到闭包外(例如,返回一个包含函数的对象)。
function createClosure() {
// 闭包内的函数
function sayHello(name) {
console.log(`Hello, ${name}!`);
}
function add(a, b) {
console.log(`Sum: ${a + b}`);
}
// onFinished 实现
function onFinished(functionName, ...args) {
if (typeof functions[functionName] === 'function') {
functions[functionName](...args); // 调用暴露的函数
} else {
console.error(`函数 ${functionName} 不存在或不是一个函数`);
}
}
// 暴露函数
const functions = { sayHello, add };
return { onFinished, functions };
}
// 创建闭包并获取 onFinished 和 functions
const { onFinished, functions } = createClosure();
// 调用 onFinished
onFinished('sayHello', 'Charlie'); // 输出: Hello, Charlie!
onFinished('add', 10, 20); // 输出: Sum: 30
// 也可以直接调用暴露的函数
functions.sayHello('Dave'); // 输出: Hello, Dave!
4. 使用 arguments.callee
(已弃用)
在旧版 JavaScript 中,可以使用 arguments.callee
获取当前函数,然后通过函数名调用闭包内的函数。但这种方法 已被弃用,不推荐使用。
function createClosure() {
// 闭包内的函数
function sayHello(name) {
console.log(`Hello, ${name}!`);
}
function add(a, b) {
console.log(`Sum: ${a + b}`);
}
// onFinished 实现
function onFinished(functionName, ...args) {
const caller = arguments.callee.caller; // 获取调用者
if (typeof caller[functionName] === 'function') {
caller[functionName](...args); // 调用闭包内的函数
} else {
console.error(`函数 ${functionName} 不存在或不是一个函数`);
}
}
return onFinished;
}
// 创建闭包并获取 onFinished
const onFinished = createClosure();
// 调用 onFinished
onFinished('sayHello', 'Eve'); // 输出: Hello, Eve!
onFinished('add', 3, 4); // 输出: Sum: 7
5. 总结
在闭包中动态调用函数时,推荐使用 函数映射表 的方式(方法 1),因为它既安全又灵活。如果闭包内的函数需要被外部调用,可以将它们暴露到闭包外(方法 3)。
避免使用 eval
和 arguments.callee
,因为它们会带来安全性和维护性问题。
