简体   繁体   English

如何在不使用eval的情况下调用不存在的(非成员,非全局)方法?

[英]How do I make a nonexistent (non-member, non-global) method invocable without using eval?

Let's start from the code: 让我们从代码开始:

function say(name) {
    var ghost=function () {
        function ghost() {
            alert('!');
        };

        return body;
    };

    eval("var body=''+"+name+';');
    eval(name+('=('+ghost).replace('body', body)+')();');
    eval(name+'();');
}

function Baal() {
    if ('undefined'===typeof ghost) {
        say('Baal');
        return;
    }

    ghost();
}

say('Baal'); // or just Baal();

Looks like that saying the devil's name invoke his presence (well, maybe he needs somebody for spiritual possession) .. 看起来好像说魔鬼的名字唤起了他的存在 (嗯,也许他需要有人来进行精神占有)。

As you can see the ghost doesn't exist along with Baal , but we can invoke it since there're eval s in say(name) . 如您所见,幽灵与Baal并不存在,但是我们可以调用它,因为say(name)eval

say(name) reassigns Baal to its code body as a closure and makes it captured a ghost method, that's how things work. say(name)Baal重新分配给其代码主体作为闭包,并使其捕获了ghost方法,这就是工作方式。 But I'm trying to avoid eval .. 但是我在努力避免eval

So .. let me reword the question: 所以..让我改写这个问题:

How do I make a nonexistent(and not a member or global) method invocable without using eval ? 如何在不使用eval情况下使不存在的(而不是成员或全局的)方法可调用?

Let me rephrase your question, just to make sure I've got it. 让我改一下您的问题,以确保我已明白。 Given a function, you want to put a new variable in its scope, without that scope being the global scope or a scope shared between the caller and the subject, without using eval (or the equivalent new Function and other hacks depending on the environment). 给定一个函数,您想在其作用域中放置一个新变量,而该作用域不是全局作用域或调用方与主题之间共享的作用域,而无需使用eval (或等效的new Function和其他依赖于环境的技巧) 。

You can't. 你不能

In the case you just mentioned, you could define one function, base() , that uses arguments.callee.caller . 在刚才提到的情况下,您可以定义一个使用arguments.callee.caller函数base()

Don't do that. 不要那样做

The short answer: You don't. 简短的答案:您不会。

That scope is not available. 该范围不可用。 If you were to attach the scope then it would be available inside of the scope used. 如果要附加范围,则它将在所使用的范围内可用。 You could then access the method handles. 然后,您可以访问方法句柄。 I assume this is not what you were looking for, but here is what that would look like. 我认为这不是您想要的,但是这里看起来会是这样。 demo 演示

function say(name){
 var methods = {};   
 methods.Baal = function(){
  alert("!");  
 };

 return methods[name];//this could invoke as well: methods[name]()
}

var handle = say('Baal');
handle();

What your evals break down to is something along these lines (although with dynamic content from string building - this is the end result) 您的评估分解为以下内容(尽管具有字符串构建过程中的动态内容,这是最终结果)

function say(name) {
 var Baal = (function () {
    function ghost() {
        alert('!');
    };

    return function(){ 
     if ('undefined'===typeof ghost) {
      say('Baal');
      return;
     }
     ghost();
   }
 })();
 Baal();
}

say('Baal'); // or just Baal();

Note that the meat of what happens here is from the function Baal , namely that it calls a hardcoded ghost() which in turn calls a hardcoded alert. 请注意,这里发生的事情来自函数Baal ,即它调用了一个硬编码的ghost() ,而后者又调用了一个硬编码的警报。 Why go through all of this trouble to access a hardcoded function? 为什么要经历所有这些麻烦才能访问硬编码功能?

A better way would be to inject this function as a callback which expects some parameters to be injected. 更好的方法是将该函数作为回调插入,该回调需要注入一些参数。

jsFiddle Demo

function say(callback){
 var params = "!";
 if( typeof callback == "function" ){
  callback(params);   
 }
}

say(function(params){
 alert(params);  
});

So if I understand, it seems like you want to create an alias of eval: Something like 因此,据我了解,您似乎想创建一个eval的别名:

#Note this code is not intended as a solution, but demonstrates
#an attempt that is guaranteed to fail.
#
function myAlias(ctx) {
eval.call(ctx, 'var ghost = 42');
}

myAlias(this);
alert(ghost);

Javascript allows many funky sleight-of-hand tricks especially with closures, but this is maybe the one impossible thing that javascript cannot do. Javascript允许许多时髦的惯用技巧,尤其是对于闭包,但这可能是JavaScript无法做到的一件事。 I've tried at length to do this exact same thing, and I can tell you that you'll run into nothing but complaints from the browser, saying that eval cannot be re-contexted or aliased in any way. 我已经竭尽全力地做同样的事情,我可以告诉你,除了浏览器的抱怨外,您什么都不会遇到,说不能以任何方式重新评估eval或使用别名。

It's very difficult for me to read through your code and figure out what you are trying to accomplish with it, but it appears that you are trying to introduce a variable into the current scope so that you can call it. 对于我来说,通读您的代码并弄清楚您要用它完成什么非常困难,但是看来您正在尝试将变量引入当前范围,以便您可以调用它。 You cannot do this in javascript with the method that you demonstrated. 您无法使用您演示的方法在javascript中执行此操作。 Scoping only ever "flows down". 作用域仅“流下来”。 By that I mean that a variable or function defined within a function will only be available to that function and any other functions defined therein. 我的意思是,在函数中定义的变量或函数将仅可用于该函数以及其中定义的任何其他函数。 Your function named ghost will only ever be available within the function where it is defined, regardless of when that function is evaluated. 无论何时评估该函数,名为ghost的函数将仅在定义该函数的地方可用。

What you can do, however, is write a function that returns a function. 但是,您可以做的是编写一个返回函数的函数。 You can then call that function and assign the result to a variable in the scope where you want to expose functionality. 然后,您可以调用该函数,并将结果分配给要公开功能的作用域中的变量。 Doing that would look something like this. 这样做看起来像这样。

function defineSpecialAlert() {
    return function(name) {
        alert(name + "!");
    };
}

var newlyDefinedMethod = defineSpecialAlert();

newlyDefinedMethod("Baal");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM