Cách thực thi hàm JavaScript khi tôi có tên là chuỗi


1051

Tôi có tên của một hàm trong JavaScript dưới dạng một chuỗi. Làm thế nào để tôi chuyển đổi nó thành một con trỏ hàm để tôi có thể gọi nó sau?

Tùy thuộc vào hoàn cảnh, tôi cũng có thể cần chuyển các đối số khác nhau vào phương thức.

Một số chức năng có thể có hình thức namespace.namespace.function(args[...]).

Câu trả lời:


1438

Đừng sử dụng evaltrừ khi bạn hoàn toàn, tích cực không có lựa chọn nào khác.

Như đã đề cập, sử dụng một cái gì đó như thế này sẽ là cách tốt nhất để làm điều đó:

window["functionName"](arguments);

Tuy nhiên, điều đó sẽ không hoạt động với chức năng không gian tên:

window["My.Namespace.functionName"](arguments); // fail

Đây là cách bạn sẽ làm điều đó:

window["My"]["Namespace"]["functionName"](arguments); // succeeds

Để làm cho điều đó dễ dàng hơn và cung cấp một số tính linh hoạt, đây là một chức năng tiện lợi:

function executeFunctionByName(functionName, context /*, args */) {
  var args = Array.prototype.slice.call(arguments, 2);
  var namespaces = functionName.split(".");
  var func = namespaces.pop();
  for(var i = 0; i < namespaces.length; i++) {
    context = context[namespaces[i]];
  }
  return context[func].apply(context, args);
}

Bạn sẽ gọi nó như vậy:

executeFunctionByName("My.Namespace.functionName", window, arguments);

Lưu ý, bạn có thể vượt qua trong bất kỳ bối cảnh nào bạn muốn, vì vậy điều này sẽ làm tương tự như trên:

executeFunctionByName("Namespace.functionName", My, arguments);

4
bạn có biết bạn không cần toàn bộ cấu trúc "func" không? Chỉ riêng "bối cảnh.apply" là ổn
annakata

16
Chắc chắn, tôi biết điều đó - nhưng cách tôi viết hàm cung cấp một số sự rõ ràng cho những người đọc nó có thể không hoàn toàn mò mẫm những gì đang xảy ra. Tôi đã viết chức năng này nhận ra mọi người đọc nó có thể cần một số trợ giúp. Tôi sẽ cung cấp một thay thế mặc dù, vì bạn đã hỏi ...
Jason Bunting

108
Cào đó - mã là đủ rõ ràng và những người biết, biết. Nếu bạn giống như tôi và biết bạn đang làm gì, bạn có thể tự mình thực hiện các thay đổi đó nếu bạn sử dụng mã này. Stack Overflow là để giáo dục người khác và tôi nghĩ rằng mã của tôi dễ hiểu hơn đối với người mới. Cảm ơn mặc dù!
Jason Bunting

4
Có một tình huống khi cửa sổ ["funcName"] sẽ trở lại không xác định? Đó là vấn đề tôi đang gặp phải vào lúc này. Mã gọi và chức năng được xác định trong hai tệp js riêng biệt. Tôi đã thử thêm chúng vào cùng một tệp nhưng điều đó không có gì khác biệt.
codemonkey

5
Tôi nghĩ rằng có một vấn đề ở đây. Khi bạn gọi My.Namespace.functionName(), thissẽ đề cập đến My.Namespaceđối tượng. Nhưng khi bạn gọi executeFunctionByName("My.Namespace.functionName", window), không có cách nào thisđể nói đến điều tương tự. Có lẽ nó nên sử dụng không gian tên cuối cùng làm phạm vi hoặc windownếu không có không gian tên. Hoặc bạn có thể cho phép người dùng chỉ định phạm vi làm đối số.
JW.

100

Chỉ cần nghĩ rằng tôi sẽ đăng một phiên bản thay đổi một chút chức năng rất hữu ích của Jason Bunting .

Đầu tiên, tôi đã đơn giản hóa câu lệnh đầu tiên bằng cách cung cấp một tham số thứ hai cho lát () . Phiên bản gốc đã hoạt động tốt trong tất cả các trình duyệt trừ IE.

Thứ hai, tôi đã thay thế điều này bằng bối cảnh trong tuyên bố trở lại; mặt khác, điều này luôn luôn trỏ đến cửa sổ khi chức năng đích đang được thực thi.

function executeFunctionByName(functionName, context /*, args */) {
    var args = Array.prototype.slice.call(arguments, 2);
    var namespaces = functionName.split(".");
    var func = namespaces.pop();
    for (var i = 0; i < namespaces.length; i++) {
        context = context[namespaces[i]];
    }
    return context[func].apply(context, args);
}

Không có kiểm tra để xem "functionName" có thực sự tồn tại không?
Crashalot

Tôi nghĩ rằng câu trả lời của Mac bị đánh giá thấp. Tôi không phải là một chuyên gia nhưng có vẻ như đã suy nghĩ kỹ và mạnh mẽ.
Martin Hansen Lennox

65

Câu trả lời cho câu hỏi khác này cho bạn biết cách thực hiện: Javascript tương đương với người địa phương của Python ()?

Về cơ bản, bạn có thể nói

window["foo"](arg1, arg2);

hoặc như nhiều người khác đã đề xuất, bạn chỉ có thể sử dụng eval:

eval(fname)(arg1, arg2);

mặc dù điều này cực kỳ không an toàn trừ khi bạn hoàn toàn chắc chắn về những gì bạn đang đánh giá.


6
hình thức đầu tiên là tốt hơn nhiều
annakata

19
Chỉ sử dụng eval như là phương sách cuối cùng, khi tất cả những thứ khác đều thất bại.
Jason Bunting

1
Đó là ... nhưng nó sẽ hoạt động với các chức năng như thế này: xyz (args)?
Kieron

@keiron: vâng. xem câu trả lời của tôi dưới đây
annakata

55

Bạn có thể không chỉ làm điều này:

var codeToExecute = "My.Namespace.functionName()";
var tmpFunc = new Function(codeToExecute);
tmpFunc();

Bạn cũng có thể thực thi bất kỳ JavaScript nào khác bằng phương pháp này.


3
hoạt động khi các đối số chẵn được truyền với hàm
adeel41

Điều gì về trả về chức năng?
Peter Denev

12
Nó khác với eval("My.Namespace.functionName()");như thế nào?
nhà phát triển xe máy

@PeterDenev chỉ cần thay đổi dòng đầu tiên thànhvar codeToExecute = "return My.Namespace.functionName()";
developerbmw

2
@developerbmw, đây là câu trả lời stackoverflow.com/questions/4599857/
Tejasvi Hegde

48

Tôi nghĩ rằng một cách thanh lịch để làm điều này là bằng cách xác định các chức năng của bạn trong một đối tượng băm. Sau đó, bạn có thể có một tham chiếu đến các hàm đó từ hàm băm bằng chuỗi. ví dụ

var customObject = {
  customFunction: function(param){...}
};

Sau đó, bạn có thể gọi:

customObject['customFunction'](param);

Trong đó customFunction sẽ là một chuỗi khớp với một hàm được xác định trong đối tượng của bạn.


@ibsenv, cảm ơn bạn đã bình luận để giúp tôi xác định phản hồi này là tốt nhất. Tôi đã tạo ra một mảng các đối tượng hàm và lần lượt sử dụng nó để tạo ra một mảng deferred.promises. Tôi đặt một số mã mẫu dưới đây. (Tôi không muốn tạo phản hồi mới và mượn phản hồi của Ruben.)
user216661 8/1/2016

function getMyData (ArrayOfObjectsWithIds) {var functionArray = ArrayOfObjectsWithIds.map (function (value) {return {myGetDataFunction: MyService.getMyData (value.id)};}) var hứa hẹn q.defer (); getDataFunction.myGetDataFunction.success (function (data) {deferred.resolve (data)}). error (function (error) {deferred.reject ();}); return deferred.promise;}); $ q.all (lời hứa) .then (hàm (dataArray) {// do Stuff})};
dùng216661

Điều này hoạt động tuyệt vời Tôi chỉ thêm dấu gạch dưới / lodash để xác minh nếu nó là một chức năng. Và sau đó chạy
elporfirio

35

Với ES6, bạn có thể truy cập các phương thức lớp theo tên:

class X {
  method1(){
    console.log("1");
  }
  method2(){
    this['method1']();
    console.log("2");
  }
}
let x  = new X();
x['method2']();

đầu ra sẽ là:

1
2

1
PURE javascript tốt nhất ... Chúa ơi .. xóa lớp không hoạt động và nó vẫn ổn. Cảm ơn!
KingRider

1
Đây là điều tôi đã tìm kiếm từ lâu. Cảm ơn!
PaladiN

ES2015 không có gì để làm ở đây. Bạn có thể đạt được cùng một mục tiêu bằng cách sử dụng các đối tượng thuần túy hoặc ủy quyền nguyên mẫu thông qua Object.create(). const myObj = {method1 () {console.log ('1')}, method2 () {console.log ('2')}} myObj ['method1'] (); // 1 myObj ['method2'] (); // 2
sminutoli

1
Đây là vàng !!! Tôi ngạc nhiên tôi chưa bao giờ nghĩ về điều này trước đây. Đẹp!!!
thxmike

Tôi cũng nghĩ rằng đây là cách gọn gàng nhất để đạt được mục tiêu của chúng tôi.
Chris Jung

24

Hai điều:

  • tránh eval, nó cực kỳ nguy hiểm và chậm

  • thứ hai, không quan trọng chức năng của bạn tồn tại ở đâu, tính "toàn cầu" là không liên quan. x.y.foo()có thể được kích hoạt thông qua x.y['foo']()hoặc x['y']['foo']()hoặc thậm chí window['x']['y']['foo'](). Bạn có thể chuỗi vô tận như thế này.


1
nhưng bạn không thể thực hiện window ['xyz'] () để gọi xyz ()
nickf

17

Tất cả các câu trả lời cho rằng các chức năng có thể được truy cập thông qua phạm vi toàn cầu (cửa sổ). Tuy nhiên, OP đã không đưa ra giả định này.

Nếu các hàm sống trong phạm vi cục bộ (còn gọi là đóng) và không được tham chiếu bởi một số đối tượng cục bộ khác, thật không may: Bạn phải sử dụng eval()AFAIK, hãy xem động gọi hàm cục bộ trong javascript


2
Dude (hoặc dudette), cảm ơn bạn rất nhiều vì đã chỉ ra điều đó! Tôi nghĩ rằng tôi sẽ phát điên trong một giây.
Funktr0n

13

Bạn chỉ cần chuyển đổi chuỗi của bạn thành một con trỏ bằng cách window[<method name>]. thí dụ:

var function_name = "string";
function_name = window[function_name];

và bây giờ bạn có thể sử dụng nó như một con trỏ.


Đây dường như là một cách an toàn hơn nhiều.
James Poulose

12

Đây là đóng góp của tôi cho câu trả lời xuất sắc của Jason Bunting / Alex Nazarov, trong đó tôi bao gồm kiểm tra lỗi do Crashalot yêu cầu.

Đưa ra lời mở đầu (giả định) này:

a = function( args ) {
    console.log( 'global func passed:' );
    for( var i = 0; i < arguments.length; i++ ) {
        console.log( '-> ' + arguments[ i ] );
    }
};
ns = {};
ns.a = function( args ) {
    console.log( 'namespace func passed:' );
    for( var i = 0; i < arguments.length; i++ ) {
        console.log( '-> ' + arguments[ i ] ); 
    }
};
name = 'nsa';
n_s_a = [ 'Snowden' ];
noSuchAgency = function(){};

Sau đó, chức năng sau đây:

function executeFunctionByName( functionName, context /*, args */ ) {
    var args, namespaces, func;

    if( typeof functionName === 'undefined' ) { throw 'function name not specified'; }

    if( typeof eval( functionName ) !== 'function' ) { throw functionName + ' is not a function'; }

    if( typeof context !== 'undefined' ) { 
        if( typeof context === 'object' && context instanceof Array === false ) { 
            if( typeof context[ functionName ] !== 'function' ) {
                throw context + '.' + functionName + ' is not a function';
            }
            args = Array.prototype.slice.call( arguments, 2 );

        } else {
            args = Array.prototype.slice.call( arguments, 1 );
            context = window;
        }

    } else {
        context = window;
    }

    namespaces = functionName.split( "." );
    func = namespaces.pop();

    for( var i = 0; i < namespaces.length; i++ ) {
        context = context[ namespaces[ i ] ];
    }

    return context[ func ].apply( context, args );
}

sẽ cho phép bạn gọi một hàm javascript theo tên được lưu trữ trong một chuỗi, được đặt tên hoặc toàn cục, có hoặc không có đối số (bao gồm các đối tượng Array), cung cấp phản hồi về bất kỳ lỗi nào gặp phải (hy vọng bắt được chúng).

Đầu ra mẫu cho thấy cách thức hoạt động:

// calling a global function without parms
executeFunctionByName( 'a' );
  /* OUTPUT:
  global func passed:
  */

// calling a global function passing a number (with implicit window context)
executeFunctionByName( 'a', 123 );
  /* OUTPUT:
  global func passed:
  -> 123
  */

// calling a namespaced function without parms
executeFunctionByName( 'ns.a' );
  /* OUTPUT:
  namespace func passed:
  */

// calling a namespaced function passing a string literal
executeFunctionByName( 'ns.a', 'No Such Agency!' );
  /* OUTPUT:
  namespace func passed:
  -> No Such Agency!
  */

// calling a namespaced function, with explicit context as separate arg, passing a string literal and array 
executeFunctionByName( 'a', ns, 'No Such Agency!', [ 007, 'is the man' ] );
  /* OUTPUT:
  namespace func passed:
  -> No Such Agency!
  -> 7,is the man
  */

// calling a global function passing a string variable (with implicit window context)
executeFunctionByName( 'a', name );
  /* OUTPUT:
  global func passed:
  -> nsa
  */

// calling a non-existing function via string literal
executeFunctionByName( 'n_s_a' );
  /* OUTPUT:
  Uncaught n_s_a is not a function
  */

// calling a non-existing function by string variable
executeFunctionByName( n_s_a );
  /* OUTPUT:
  Uncaught Snowden is not a function
  */

// calling an existing function with the wrong namespace reference
executeFunctionByName( 'a', {} );
  /* OUTPUT:
  Uncaught [object Object].a is not a function
  */

// calling no function
executeFunctionByName();
  /* OUTPUT:
  Uncaught function name not specified
  */

// calling by empty string
executeFunctionByName( '' );
  /* OUTPUT:
  Uncaught  is not a function
  */

// calling an existing global function with a namespace reference
executeFunctionByName( 'noSuchAgency', ns );
  /* OUTPUT:
  Uncaught [object Object].noSuchAgency is not a function
  */

Dunno ... đó là một nỗ lực rất tốt, rõ ràng. Nhưng âm thanh như "quá rộng" đối với tôi ...
TechNyquist

2
Huh? SO là một câu hỏi / câu trả lời / nền tảng giảng dạy. Tôi sẵn sàng cung cấp tất cả các ví dụ mà tôi có thể nghĩ ra để hy vọng truyền đạt sự chiếu sáng. Đối với tôi, đó là điểm chính .
Mac

Nếu bạn vẫn đang sử dụng functionName, tại sao không sử dụng nó?
dữ liệu

Điều này không làm việc cho tôi. Tôi có một hàm tên abcd abcd trong đó d là tên hàm. lệnh gọi execFunctionByName ("abcd", window) không thành công trên dòng kiểm tra if( typeof context[ functionName ] !== 'function' )vì bối cảnh - cửa sổ - được xác định, là một đối tượng và một mảng, nhưng cửa sổ ['abcd'] không tồn tại như được xác định là một vấn đề trong chấp nhận Trả lời: window["My.Namespace.functionName"](arguments); // fail
akousmata

12

Tùy thuộc vào nơi bạn ở, bạn cũng có thể sử dụng:

this["funcname"]();
self["funcname"]();
window["funcname"]();
top["funcname"]();
globalThis["funcname"]();

hoặc, trong nodejs

global["funcname"]()

9

Nếu bạn muốn gọi một hàm của một đối tượng thay vì một hàm toàn cục với window["functionName"]. Bạn có thể làm nó như thế nào;

var myObject=new Object();
myObject["functionName"](arguments);

Thí dụ:

var now=new Date();
now["getFullYear"]()

8

HÃY CẨN THẬN!!!

Mọi người nên cố gắng tránh gọi một hàm theo chuỗi trong JavaScript vì hai lý do:

Lý do 1: Một số obfuscators mã sẽ phá hỏng mã của bạn vì chúng sẽ thay đổi tên hàm, làm cho chuỗi không hợp lệ.

Lý do 2: Việc duy trì mã sử dụng phương pháp này khó hơn nhiều vì việc định vị các cách sử dụng các phương thức được gọi bởi một chuỗi khó hơn nhiều.


7

Đây là cách tiếp cận Es6 của tôi cho phép bạn gọi hàm của mình bằng tên của nó dưới dạng chuỗi hoặc tên hàm và cũng cho phép bạn chuyển các số lượng đối số khác nhau cho các loại hàm khác nhau:

function fnCall(fn, ...args)
{
  let func = (typeof fn =="string")?window[fn]:fn;
  if (typeof func == "function") func(...args);
  else throw new Error(`${fn} is Not a function!`);
}


function example1(arg1){console.log(arg1)}
function example2(arg1, arg2){console.log(arg1 + "  and   " + arg2)}
function example3(){console.log("No arguments!")}

fnCall("example1", "test_1");
fnCall("example2", "test_2", "test3");
fnCall(example3);
fnCall("example4"); // should raise an error in console


6

Ngạc nhiên khi thấy không đề cập đến setTimeout.

Để chạy một hàm không có đối số:

var functionWithoutArguments = function(){
    console.log("Executing functionWithoutArguments");
}
setTimeout("functionWithoutArguments()", 0);

Để chạy chức năng với các đối số:

var functionWithArguments = function(arg1, arg2) {
    console.log("Executing functionWithArguments", arg1, arg2);
}
setTimeout("functionWithArguments(10, 20)");

Để chạy chức năng đặt tên sâu:

var _very = {
    _deeply: {
        _defined: {
            _function: function(num1, num2) {
                console.log("Execution _very _deeply _defined _function : ", num1, num2);
            }
        }
    }
}
setTimeout("_very._deeply._defined._function(40,50)", 0);

Điều này không cung cấp một câu trả lời cho câu hỏi. Để phê bình hoặc yêu cầu làm rõ từ một tác giả, hãy để lại nhận xét bên dưới bài đăng của họ - bạn luôn có thể nhận xét về bài đăng của riêng bạn và khi bạn có đủ danh tiếng, bạn sẽ có thể nhận xét về bất kỳ bài đăng nào .
AstroCB

Vui lòng thêm một ví dụ về cách bạn sẽ gọi runMevới một vài đối số.
lexicore

1
@lexicore Tôi đã bỏ phiếu để xóa trong hàng đánh giá, vì nó không cung cấp rõ ràng câu trả lời cho câu hỏi và nó không có giá trị gì.
AstroCB

1
Phương thức này có khả năng rất lớn, vì nó đặt thực thi đến hết hàng đợi kết xuất , do đó làm cho cuộc gọi này không đồng bộ
PeterM

1
Tôi thích câu trả lời này, nó dường như làm việc cho các yêu cầu của tôi.
Quintonn

3

Vì vậy, như những người khác đã nói, chắc chắn lựa chọn tốt nhất là:

window['myfunction'](arguments)

Và như Jason Bunting đã nói , nó sẽ không hoạt động nếu tên hàm của bạn bao gồm một đối tượng:

window['myobject.myfunction'](arguments); // won't work
window['myobject']['myfunction'](arguments); // will work

Vì vậy, đây là phiên bản chức năng của tôi sẽ thực thi tất cả các chức năng theo tên (bao gồm cả một đối tượng hay không):

my = {
    code : {
        is : {
            nice : function(a, b){ alert(a + "," + b); }
        }
    }
};

guy = function(){ alert('awesome'); }

function executeFunctionByName(str, args)
{
    var arr = str.split('.');
    var fn = window[ arr[0] ];
    
    for (var i = 1; i < arr.length; i++)
    { fn = fn[ arr[i] ]; }
    fn.apply(window, args);
}

executeFunctionByName('my.code.is.nice', ['arg1', 'arg2']);
executeFunctionByName('guy');


3
  let t0 = () => { alert('red0') }
  var t1 = () =>{ alert('red1') }
  var t2 = () =>{ alert('red2') }
  var t3 = () =>{ alert('red3') }
  var t4 = () =>{ alert('red4') }
  var t5 = () =>{ alert('red5') }
  var t6 = () =>{ alert('red6') }

  function getSelection(type) {
    var evalSelection = {
      'title0': t0,
      'title1': t1,
      'title2': t2,
      'title3': t3,
      'title4': t4,
      'title5': t5,
      'title6': t6,
      'default': function() {
        return 'Default';
      }
    };
    return (evalSelection[type] || evalSelection['default'])();
  }
  getSelection('title1');

Một giải pháp OOP hơn ...


2

Thêm một chi tiết về bài viết của Jason và Alex. Tôi thấy hữu ích khi thêm một giá trị mặc định vào ngữ cảnh. Chỉ cần đặt context = context == undefined? window:context;ở đầu chức năng. Bạn có thể thay đổi windowthành bất kỳ bối cảnh ưa thích nào của bạn, và sau đó bạn sẽ không cần phải chuyển cùng một biến mỗi lần bạn gọi nó trong ngữ cảnh mặc định của bạn.


2

Để thêm vào câu trả lời của Jason Bunting, nếu bạn đang sử dụng nodejs hoặc thứ gì đó (và điều này cũng hoạt động trong dom js), bạn có thể sử dụng thisthay vì window(và hãy nhớ: eval là ác :

this['fun'+'ctionName']();

2

Có một điều rất giống trong mã của tôi. Tôi có một chuỗi do máy chủ tạo ra chứa tên hàm mà tôi cần chuyển qua làm cuộc gọi lại cho thư viện bên thứ 3. Vì vậy, tôi có một mã lấy chuỗi và trả về một "con trỏ" cho hàm hoặc null nếu nó không được tìm thấy.

Giải pháp của tôi rất giống với " Chức năng rất hữu ích của Jason Bunting " * , mặc dù nó không tự động thực hiện và bối cảnh luôn ở trên cửa sổ. Nhưng điều này có thể dễ dàng sửa đổi.

Hy vọng điều này sẽ hữu ích cho ai đó.

/**
 * Converts a string containing a function or object method name to a function pointer.
 * @param  string   func
 * @return function
 */
function getFuncFromString(func) {
    // if already a function, return
    if (typeof func === 'function') return func;

    // if string, try to find function or method of object (of "obj.func" format)
    if (typeof func === 'string') {
        if (!func.length) return null;
        var target = window;
        var func = func.split('.');
        while (func.length) {
            var ns = func.shift();
            if (typeof target[ns] === 'undefined') return null;
            target = target[ns];
        }
        if (typeof target === 'function') return target;
    }

    // return null if could not parse
    return null;
}


1

Tôi không thể cưỡng lại việc đề cập đến một thủ thuật khác, nó giúp nếu bạn có một số lượng đối số không xác định cũng được truyền vào như một phần của chuỗi chứa tên hàm. Ví dụ:

var annoyingstring = 'call_my_func(123, true, "blah")';

Nếu Javascript của bạn đang chạy trên trang HTML, tất cả những gì bạn cần là một liên kết vô hình; bạn có thể truyền một chuỗi vào onclickthuộc tính và gọi clickphương thức.

<a href="#" id="link_secret"><!-- invisible --></a>

$('#link_secret').attr('onclick', annoyingstring);
$('#link_secret').click();

Hoặc tạo <a>phần tử khi chạy.


Giải pháp sáng tạo, nhưng điều này sẽ không hoạt động cho các đối số kiểu đối tượng hoặc mảng.
Dennis Heiden

1
Đây là sử dụng eval dưới mui xe ... Và thực sự đập xung quanh bụi rậm để làm điều đó
Juan Mendes

1

Cách dễ nhất là truy cập nó như có yếu tố

window.ClientSideValidations.forms.location_form

giống như

window.ClientSideValidations.forms['location_form']

1

Bạn có thể gọi chức năng javascript trong một eval("functionname as string")trong hai. Giống như dưới đây: (eval là chức năng javascript thuần túy)

function testfunc(){
    return "hello world";
}

$( document ).ready(function() {

     $("div").html(eval("testfunc"));
});

Ví dụ hoạt động: https://jsfiddle.net/suatatan/24ms0fna/4/


Điều này hoạt động tốt và nó rất đơn giản
Carlos E

1
Và cũng thực sự chậm.
Marco

1

Điều này làm việc cho tôi:

var command = "Add";
var tempFunction = new Function("Arg1","Arg2", "window." + command + "(Arg1,Arg2)");
tempFunction(x,y);

Tôi mong cái này sẽ thành công.


1

Tôi không nghĩ rằng bạn cần các chức năng trung gian phức tạp hoặc eval hoặc phụ thuộc vào các biến toàn cục như cửa sổ:

function fun1(arg) {
  console.log(arg);
}

function fun2(arg) {
  console.log(arg);
}

const operations = {
  fun1,
  fun2
};

let temp = "fun1";

try {
  // You have to use square brackets property access
  operations["fun1"]("Hello World");
  operations["fun2"]("Hello World");
  // You can use variables
  operations[temp]("Hello World");
} catch (error) {
  console.error(error);
}

Nó cũng sẽ hoạt động với các chức năng được nhập:

// mode.js
export function fun1(arg) {
  console.log(arg);
}

export function fun2(arg) {
  console.log(arg);
}
// index.js
import { fun1, fun2 } from "./mod";

const operations = {
  fun1,
  fun2
};

try {
  operations["fun1"]("Hello World");
  operations["fun2"]("Hello World");
} catch (error) {
  console.error(error);
}

0

Không sử dụng eval('function()')bạn có thể tạo một chức năng mới bằng cách sử dụng new Function(strName). Mã dưới đây đã được kiểm tra bằng FF, Chrome, IE.

<html>
<body>
<button onclick="test()">Try it</button>
</body>
</html>
<script type="text/javascript">

  function test() {
    try {    
        var fnName = "myFunction()";
        var fn = new Function(fnName);
        fn();
      } catch (err) {
        console.log("error:"+err.message);
      }
  }

  function myFunction() {
    console.log('Executing myFunction()');
  }

</script>

0
use this

function executeFunctionByName(functionName, context /*, args */) {
      var args = [].slice.call(arguments).splice(2);
      var namespaces = functionName.split(".");
      var func = namespaces.pop();
      for(var i = 0; i < namespaces.length; i++) {
        context = context[namespaces[i]];
      }
      return context[func].apply(context, args);
    }

1
Tại sao? Câu trả lời mà không có lời giải thích rất có thể là vô dụng.
Daniel W.

0

Nhìn cơ bản:

var namefunction = 'jspure'; // String

function jspure(msg1 = '', msg2 = '') { 
  console.log(msg1+(msg2!=''?'/'+msg2:''));
} // multiple argument

// Results ur test
window[namefunction]('hello','hello again'); // something...
eval[namefunction] = 'hello'; // use string or something, but its eval just one argument and not exist multiple

Hàm loại khác tồn tại là lớp và xem ví dụ nils petersohn


0

Cảm ơn câu trả lời rất hữu ích. Tôi đang sử dụng chức năng của Jason Bunting trong các dự án của mình.

Tôi đã mở rộng nó để sử dụng nó với thời gian chờ tùy chọn, vì cách thông thường để đặt thời gian chờ sẽ không hoạt động. Xem câu hỏi của abhishekisnot

function executeFunctionByName(functionName, context, timeout /*, args */ ) {
	var args = Array.prototype.slice.call(arguments, 3);
	var namespaces = functionName.split(".");
	var func = namespaces.pop();
	for (var i = 0; i < namespaces.length; i++) {
		context = context[namespaces[i]];
	}
	var timeoutID = setTimeout(
		function(){ context[func].apply(context, args)},
		timeout
	);
    return timeoutID;
}

var _very = {
    _deeply: {
        _defined: {
            _function: function(num1, num2) {
                console.log("Execution _very _deeply _defined _function : ", num1, num2);
            }
        }
    }
}

console.log('now wait')
executeFunctionByName("_very._deeply._defined._function", window, 2000, 40, 50 );

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.