วิธีการใช้งานฟังก์ชั่น JavaScript เมื่อฉันมีชื่อเป็นสตริง


1050

ฉันมีชื่อฟังก์ชั่นใน JavaScript เป็นสตริง ฉันจะแปลงให้เป็นตัวชี้ฟังก์ชั่นเพื่อให้ฉันสามารถเรียกมันได้ในภายหลัง?

ขึ้นอยู่กับสถานการณ์ฉันอาจต้องผ่านการขัดแย้งต่าง ๆ ลงในวิธีการด้วย

namespace.namespace.function(args[...])บางส่วนของฟังก์ชั่นอาจใช้รูปแบบของ

คำตอบ:


1438

อย่าใช้evalเว้นเสียแต่ว่าคุณจะบวกไม่มีทางเลือกอื่น

ตามที่ได้กล่าวไว้การใช้บางอย่างเช่นนี้จะเป็นวิธีที่ดีที่สุดในการทำสิ่งนี้:

window["functionName"](arguments);

อย่างไรก็ตามจะไม่ทำงานกับฟังก์ชันเนมสเปซ:

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

นี่คือวิธีที่คุณจะทำ:

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

เพื่อให้ง่ายขึ้นและให้ความยืดหยุ่นนี่คือฟังก์ชั่นความสะดวกสบาย:

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);
}

คุณจะเรียกมันว่า:

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

หมายเหตุคุณสามารถผ่านในบริบทใดก็ได้ที่คุณต้องการดังนั้นสิ่งนี้จะทำเช่นเดียวกับข้างบน:

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

4
คุณรู้หรือไม่ว่าคุณไม่จำเป็นต้องสร้าง "func" ทั้งหมด? "context.apply" เพียงอย่างเดียวใช้ได้ดี
annakata

16
แน่นอนฉันรู้ว่า - แต่วิธีที่ฉันเขียนฟังก์ชั่นนั้นมีความชัดเจนสำหรับผู้อ่านที่อาจไม่ได้ยินว่าเกิดอะไรขึ้น ฉันเขียนฟังก์ชั่นนี้โดยตระหนักว่าผู้คนที่อ่านมันอาจต้องการความช่วยเหลือ ฉันจะให้เป็นทางเลือกแม้ว่าคุณจะถามว่า ...
Jason Bunting

108
เกาว่า - รหัสนั้นชัดเจนเพียงพอและผู้รู้ทราบ หากคุณเป็นเหมือนฉันและรู้ว่าคุณกำลังทำอะไรคุณสามารถทำการเปลี่ยนแปลงดังกล่าวได้ด้วยตัวเองหากคุณใช้รหัสนี้ Stack Overflow สำหรับการให้การศึกษาแก่ผู้อื่นและฉันคิดว่ารหัสของฉันง่ายต่อการเข้าใจ ขอบคุณนะ!
เจสันตอม่อ

4
มีสถานการณ์เมื่อหน้าต่าง ["funcName"] จะกลับมาไม่ได้กำหนด? นั่นคือปัญหาที่ฉันมีอยู่ในขณะนี้ รหัสการโทรและฟังก์ชั่นที่กำหนดไว้ในสองไฟล์ js แยกต่างหาก ฉันลองเพิ่มลงในไฟล์เดียวกัน แต่ก็ไม่ได้ทำให้แตกต่าง
codemonkey

5
ฉันคิดว่ามีปัญหาที่นี่ เมื่อคุณโทรMy.Namespace.functionName(), thisจะหมายถึงMy.Namespaceวัตถุ แต่เมื่อคุณโทรexecuteFunctionByName("My.Namespace.functionName", window)ไม่มีทางที่thisจะพูดถึงสิ่งเดียวกัน บางทีควรใช้เนมสเปซสุดท้ายเป็นขอบเขตหรือwindowหากไม่มีเนมสเปซ หรือคุณอาจอนุญาตให้ผู้ใช้ระบุขอบเขตเป็นอาร์กิวเมนต์
เจดับบลิว

100

แค่คิดว่าฉันโพสต์ฟังก์ชั่นที่มีประโยชน์มากของJason Buntingรุ่นที่เปลี่ยนแปลงเล็กน้อยฟังก์ชั่นที่เป็นประโยชน์มากเจสันตอม่อ

ครั้งแรกฉันได้ลดความซับซ้อนของคำสั่งแรกโดยการส่งพารามิเตอร์ที่สองเพื่อชิ้น ()() รุ่นเดิมทำงานได้ดีในเบราว์เซอร์ทั้งหมดยกเว้น IE

ประการที่สองฉันได้แทนที่สิ่งนี้ด้วยบริบทในคำสั่ง return; มิฉะนั้นสิ่งนี้จะชี้ไปที่หน้าต่างเสมอเมื่อมีการเรียกใช้ฟังก์ชันเป้าหมาย

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);
}

ไม่มีการตรวจสอบว่า "functionName" มีอยู่จริงหรือไม่?
Crashalot

ฉันคิดว่าคำตอบของ Mac นั้นต่ำเกินไป ฉันไม่ใช่ผู้เชี่ยวชาญ แต่ดูเหมือนว่าจะดีและมีประสิทธิภาพ
Martin Hansen Lennox

65

คำตอบสำหรับคำถามอื่นแสดงให้คุณเห็นว่าต้องทำอย่างไร: Javascript เทียบเท่ากับ Python locals ()?

โดยทั่วไปคุณสามารถพูดได้

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

หรืออย่างที่คนอื่น ๆ ได้แนะนำคุณสามารถใช้ eval:

eval(fname)(arg1, arg2);

แม้ว่าจะไม่ปลอดภัยอย่างมากเว้นแต่คุณจะแน่ใจอย่างแน่นอนเกี่ยวกับสิ่งที่คุณกำลังประเมิน


6
รูปแบบแรกอยู่ไกลดีกว่า
annakata

19
ใช้ eval เป็นทางเลือกสุดท้ายเมื่อทุกอย่างล้มเหลว
เจสันตอม่อ

1
มันคือ ... แต่มันจะทำงานกับฟังก์ชั่นเช่นนี้: xyz (args) หรือไม่
Kieron

@keiron: ใช่ ดูคำตอบของฉันด้านล่าง
annakata

55

คุณไม่สามารถทำสิ่งนี้ได้:

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

คุณยังสามารถเรียกใช้ JavaScript อื่น ๆ โดยใช้วิธีนี้


3
ทำงานได้แม้มีการส่งผ่านอาร์กิวเมนต์ด้วยฟังก์ชัน
adeel41

ฟังก์ชั่นกลับมาเกี่ยวกับอะไร?
Peter Denev

12
แตกต่างจากeval("My.Namespace.functionName()");อย่างไร
developerbmw

@PeterDenev เพิ่งเปลี่ยนบรรทัดแรกเป็นvar codeToExecute = "return My.Namespace.functionName()";
developerbmw

2
@developerbmw นี่คือคำตอบstackoverflow.com/questions/4599857/…
Tejasvi Hegde

48

ฉันคิดว่าวิธีที่ยอดเยี่ยมในการทำเช่นนี้คือการกำหนดฟังก์ชั่นของคุณในวัตถุแฮช จากนั้นคุณสามารถอ้างอิงถึงฟังก์ชันเหล่านั้นได้จากแฮชโดยใช้สตริง เช่น

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

จากนั้นคุณสามารถโทร:

customObject['customFunction'](param);

โดยที่ customFunction จะเป็นสตริงที่ตรงกับฟังก์ชั่นที่กำหนดไว้ในวัตถุของคุณ


@ibsenv ขอขอบคุณสำหรับความคิดเห็นของคุณเพื่อช่วยฉันระบุการตอบกลับนี้ว่าดีที่สุด ฉันสร้างอาร์เรย์ของฟังก์ชั่นวัตถุและในทางกลับกันก็ใช้มันเพื่อสร้างอาร์เรย์ของ deferred.promises ฉันใส่รหัสตัวอย่างด้านล่าง (ฉันไม่ต้องการสร้างคำตอบใหม่และขอยืมคำตอบของ Ruben)
user216661

ฟังก์ชัน getMyData (arrayOfObjectsWithIds) {var functionArray = arrayOfObjectsWithIds.map (ฟังก์ชัน (ค่า) {ส่งกลับ {myGetDataFunction: MyService.getMyData (value.id)};} q.defer (); getDataFunction.myGetDataFunction.success (ฟังก์ชั่น (ข้อมูล) {deferred.resolve (data)}) ข้อผิดพลาด (ฟังก์ชั่น (ข้อผิดพลาด) {deferred.reject ();}); return deferred.promise;}); $ q.all (สัญญา) .then (ฟังก์ชั่น (dataArray) {// do stuff})};
user216661

มันใช้งานได้ดีฉันเพิ่มขีดล่าง / lodash เพื่อตรวจสอบว่าเป็นฟังก์ชันหรือไม่ และเรียกใช้
elporfirio

35

ด้วย ES6 คุณสามารถเข้าถึงวิธีการเรียนโดยใช้ชื่อ:

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

ผลลัพธ์จะเป็น:

1
2

1
จาวาสคริปต์ที่ดีที่สุดบริสุทธิ์ ... พระเจ้า .. ลบคลาสไม่ทำงานและมันก็โอเค ขอบคุณ!
KingRider

1
นี่คือสิ่งที่ฉันกำลังมองหามาเป็นเวลานาน ขอบคุณ!
PaladiN

ES2015 ไม่มีอะไรให้ทำที่นี่ Object.create()คุณสามารถบรรลุเป้าหมายเดียวกันการใช้วัตถุบริสุทธิ์หรือต้นแบบคณะผู้แทนทาง const myObj = {method1 () {console.log ('1')}, method2 () {console.log ('2')}} myObj ['method1'] (); // 1 myObj ['method2'] (); // 2
sminutoli

1
นี่คือทอง !!! ฉันประหลาดใจที่ฉันไม่เคยคิดถึงเรื่องนี้มาก่อน นีซ !!!
thxmike

ฉันคิดว่านี่เป็นวิธีที่เรียบร้อยที่สุดในการบรรลุเป้าหมายของเรา
Chris Jung

24

สองสิ่ง:

  • หลีกเลี่ยงการ eval มันอันตรายมากและช้า

  • ประการที่สองมันไม่สำคัญว่าจะมีฟังก์ชั่นของคุณอยู่ที่ใด x.y.foo()สามารถเปิดใช้งานผ่านx.y['foo']()หรือหรือแม้กระทั่งx['y']['foo']() window['x']['y']['foo']()คุณสามารถโยงเรื่องนี้ไปเรื่อย ๆ


1
แต่คุณไม่สามารถทำหน้าต่าง ['xyz'] () เพื่อโทร xyz ()
nickf

17

คำตอบทั้งหมดสมมติว่าฟังก์ชั่นสามารถเข้าถึงได้ผ่านขอบเขตทั่วโลก (หน้าต่าง) อย่างไรก็ตาม OP ไม่ได้ทำสมมติฐานนี้

หากฟังก์ชั่นอาศัยอยู่ในขอบเขตท้องถิ่น (การปิด aka) และไม่ได้อ้างอิงโดยวัตถุในท้องถิ่นอื่น ๆ โชคไม่ดี: คุณต้องใช้eval()AFAIK ดูการ เรียกใช้ฟังก์ชั่นท้องถิ่นในจาวาสคริปต์


2
เพื่อน (หรือ dudette) ขอบคุณมากสำหรับการชี้ให้เห็น! ฉันคิดว่าฉันบ้าไปแล้ว
Funktr0n

13

window[<method name>]คุณเพียงแค่ต้องแปลงสตริงของคุณเพื่อชี้โดย ตัวอย่าง:

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

และตอนนี้คุณสามารถใช้มันเหมือนเป็นตัวชี้


นี่เป็นวิธีที่ปลอดภัยกว่ามาก
James Poulose

12

นี่คือผลงานของฉันต่อคำตอบที่ยอดเยี่ยมของ Jason Bunting / Alex Nazarov ซึ่งฉันรวมการตรวจสอบข้อผิดพลาดที่ร้องขอโดย Crashalot

รับบทนำนี้ (ประดิษฐ์):

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(){};

จากนั้นฟังก์ชั่นต่อไปนี้:

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 );
}

จะช่วยให้คุณสามารถเรียกใช้ฟังก์ชันจาวาสคริปต์โดยใช้ชื่อที่เก็บไว้ในสตริงไม่ว่าจะเป็นเนมสเปซหรือโกลบอลโดยมีหรือไม่มีอาร์กิวเมนต์ (รวมถึงออบเจ็กต์ Array) ซึ่งให้ข้อเสนอแนะเกี่ยวกับข้อผิดพลาดที่พบ

ผลลัพธ์ตัวอย่างแสดงวิธีการทำงาน:

// 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 ... มันเป็นความพยายามที่ดีมากชัดเจน แต่ฟังดูเหมือน "กว้างเกินไป" สำหรับฉัน ...
TechNyquist

2
ฮะ? ดังนั้นเป็นคำถาม / คำตอบ / แพลตฟอร์มการสอน ฉันยินดีที่จะให้ตัวอย่างทั้งหมดที่ฉันสามารถนึกหวังว่าจะสื่อความส่องสว่าง ให้ฉันที่จุด
Mac

หากคุณกำลังใช้ฟังก์ชันชื่ออยู่อยู่ทำไมไม่ลองใช้ชื่อนั้นดูล่ะ
ข้อมูล

มันไม่ได้ผลสำหรับฉัน ฉันมีฟังก์ชั่น namespaced abcd โดยที่ d คือชื่อฟังก์ชั่น การเรียก executeFunctionByName ("abcd", หน้าต่าง) ล้มเหลวในบรรทัดที่ตรวจสอบif( typeof context[ functionName ] !== 'function' )เนื่องจากบริบท - หน้าต่าง - ถูกกำหนดเป็นวัตถุและอาร์เรย์ แต่ไม่มีหน้าต่าง ['abcd'] ตามที่ระบุว่าเป็นปัญหาในการยอมรับ คำตอบ: window["My.Namespace.functionName"](arguments); // fail
akousmata

12

ขึ้นอยู่กับว่าคุณอยู่ที่ไหนคุณยังสามารถใช้:

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

หรือใน nodejs

global["funcname"]()

9

window["functionName"]หากคุณต้องการที่จะเรียกฟังก์ชั่นของวัตถุแทนการใช้ฟังก์ชั่นระดับโลกที่มี คุณสามารถทำได้เช่น;

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

ตัวอย่าง:

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

8

ระวัง!!!

หนึ่งควรพยายามหลีกเลี่ยงการเรียกใช้ฟังก์ชันโดยสายอักขระใน JavaScript ด้วยเหตุผลสองประการ:

เหตุผลที่ 1: รหัส obfuscators จะทำลายรหัสของคุณเนื่องจากพวกเขาจะเปลี่ยนชื่อฟังก์ชั่นทำให้สตริงไม่ถูกต้อง

เหตุผลที่ 2: การบำรุงรักษาโค้ดที่ใช้วิธีการนี้ยากกว่ามากเนื่องจากเป็นการยากที่จะค้นหาวิธีการที่เรียกใช้โดยสตริง


7

นี่คือวิธี Es6 ของฉันซึ่งช่วยให้คุณสามารถเรียกใช้ฟังก์ชันของคุณโดยใช้ชื่อเป็นสตริงหรือชื่อฟังก์ชันและยังช่วยให้คุณสามารถส่งอาร์กิวเมนต์จำนวนต่างๆไปยังฟังก์ชันประเภทต่างๆ:

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

ประหลาดใจที่เห็นว่าไม่ได้กล่าวถึง setTimeout

วิธีเรียกใช้ฟังก์ชันที่ไม่มีอาร์กิวเมนต์:

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

วิธีเรียกใช้ฟังก์ชันด้วยอาร์กิวเมนต์:

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

ในการเรียกใช้ฟังก์ชันเนมสเปซแบบลึก:

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);

สิ่งนี้ไม่ได้ให้คำตอบสำหรับคำถาม จะวิจารณ์หรือการร้องขอคำชี้แจงจากผู้เขียนแสดงความคิดเห็นด้านล่างโพสต์ของพวกเขา - คุณสามารถแสดงความคิดเห็นในโพสต์ของคุณเองและเมื่อคุณมีเพียงพอชื่อเสียงคุณจะสามารถที่จะแสดงความคิดเห็นในโพสต์ใด
AstroCB

โปรดเพิ่มตัวอย่างว่าคุณจะโทรหาrunMeด้วยอาร์กิวเมนต์บางอย่างได้อย่างไร
lexicore

1
@lexicore ฉันโหวตให้ลบในคิวการตรวจสอบเพราะมันไม่ได้อย่างชัดเจนให้คำตอบกับคำถามที่สำคัญและมีค่าเล็ก ๆ น้อย ๆ ในตัวเอง
AstroCB

1
วิธีการนี้มีข้อบกพร่องที่อาจเกิดขึ้นอย่างมากเนื่องจากทำให้การดำเนินการสิ้นสุดคิวการแสดงผลจึงทำให้การโทรนี้ไม่ตรงกัน
PeterM

1
ฉันชอบคำตอบนี้ดูเหมือนจะทำงานได้ตามความต้องการของฉัน
Quintonn

3

ตัวเลือกที่ดีที่สุดคือ:

window['myfunction'](arguments)

และเช่นเดียวกับJason Bunting กล่าวว่าจะไม่ทำงานหากชื่อฟังก์ชันของคุณมีวัตถุ:

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

ดังนั้นนี่คือรุ่นของฟังก์ชันที่จะเรียกใช้ฟังก์ชันทั้งหมดตามชื่อ (รวมถึงวัตถุหรือไม่):

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');

โซลูชัน OOP เพิ่มเติม ...


2

รายละเอียดเพิ่มเติมเกี่ยวกับการโพสต์ของ Jason และ Alex ฉันพบว่ามีประโยชน์ในการเพิ่มค่าเริ่มต้นให้กับบริบท เพียงใส่context = context == undefined? window:context;ที่จุดเริ่มต้นของฟังก์ชั่น คุณสามารถเปลี่ยนwindowเป็นบริบทที่คุณต้องการจากนั้นคุณไม่จำเป็นต้องผ่านตัวแปรเดียวกันทุกครั้งที่คุณเรียกสิ่งนี้ในบริบทเริ่มต้นของคุณ


2

เพื่อเพิ่มคำตอบของ Jason Bunting หากคุณใช้ nodejs หรืออะไรบางอย่าง (และสิ่งนี้ทำงานใน dom js ด้วย) คุณสามารถใช้thisแทนwindow(และจำไว้ว่า: eval เป็นสิ่งชั่วร้าย :

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

2

ในรหัสของฉันมีสิ่งที่คล้ายกันมาก ฉันมีสตริงที่เซิร์ฟเวอร์สร้างขึ้นซึ่งมีชื่อฟังก์ชั่นที่ฉันต้องผ่านเป็น callback สำหรับห้องสมุดบุคคลที่สาม ดังนั้นฉันมีรหัสที่ใช้สตริงและส่งกลับ "ตัวชี้" เพื่อฟังก์ชั่นหรือ null ถ้าไม่พบ

โซลูชันของฉันคล้ายกับ " ฟังก์ชั่นที่มีประโยชน์มากของ Jason Bunting " *ถึงแม้ว่ามันจะไม่ทำงานอัตโนมัติ แต่สิ่งนี้สามารถแก้ไขได้ง่าย

หวังว่านี่จะเป็นประโยชน์กับใครบางคน

/**
 * 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

ฉันไม่สามารถต้านทานพูดถึงเคล็ดลับอื่นซึ่งช่วยถ้าคุณมีจำนวนอาร์กิวเมนต์ที่ไม่รู้จักที่ยังถูกส่งผ่านเป็นส่วนหนึ่งของสตริงที่มีชื่อฟังก์ชั่น ตัวอย่างเช่น:

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

หาก Javascript ของคุณทำงานบนหน้า HTML สิ่งที่คุณต้องมีก็คือลิงค์ที่มองไม่เห็น คุณสามารถส่งผ่านสตริงไปยังonclickแอ็ตทริบิวต์และเรียกใช้clickเมธอด

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

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

หรือสร้าง<a>องค์ประกอบที่รันไทม์


วิธีแก้ปัญหาความคิดสร้างสรรค์ แต่จะไม่สามารถใช้งานได้กับอาร์กิวเมนต์ประเภทวัตถุหรืออาเรย์
Dennis Heiden

1
นี่คือการใช้ eval ภายใต้ประทุน ... และเต้นรอบ ๆ พุ่มไม้เพื่อทำมันจริงๆ
Juan Mendes

1

วิธีที่ง่ายที่สุดคือเข้าถึงได้เหมือนมีองค์ประกอบ

window.ClientSideValidations.forms.location_form

เป็นเช่นเดียวกับ

window.ClientSideValidations.forms['location_form']

1

คุณสามารถเรียกฟังก์ชั่นจาวาสคริปต์ภายในeval("functionname as string")อย่างใดอย่างหนึ่ง ชอบด้านล่าง: (eval เป็นฟังก์ชั่นจาวาสคริปต์ที่บริสุทธิ์)

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

$( document ).ready(function() {

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

ตัวอย่างการทำงาน: https://jsfiddle.net/suatatan/24ms0fna/4/


วิธีนี้ใช้งานได้ดีและเรียบง่าย
Carlos E

1
และก็ช้าจริงๆ
Marco

1

นี่ใช้งานได้สำหรับฉัน:

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

ฉันหวังว่างานนี้


1

ฉันไม่คิดว่าคุณต้องการฟังก์ชั่นกลางที่ซับซ้อนหรือประเมินหรือขึ้นอยู่กับตัวแปรทั่วโลกเช่นหน้าต่าง:

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);
}

มันจะทำงานกับฟังก์ชั่นที่นำเข้า:

// 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

โดยไม่ต้องใช้ที่คุณสามารถทำได้เพื่อสร้างฟังก์ชั่นใหม่โดยใช้eval('function()') new Function(strName)รหัสด้านล่างได้รับการทดสอบโดยใช้ 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
ทำไม? คำตอบที่ไม่มีคำอธิบายมักไร้ประโยชน์
Daniel W.

0

ดูพื้นฐาน:

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

มีฟังก์ชั่นประเภทอื่น ๆ อยู่ระดับและดูตัวอย่างnils petersohn


0

ขอบคุณสำหรับคำตอบที่เป็นประโยชน์มาก ฉันใช้ฟังก์ชันของ Jason Buntingในโครงการของฉัน

ฉันขยายมันเพื่อใช้กับการหมดเวลาเสริมเพราะวิธีปกติในการตั้งค่าการหมดเวลาจะไม่ทำงาน ดูคำถามของ 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 );

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.