有没有可能调用function.apply而不改变上下文? [英] Is it possible to call function.apply without changing the context?

查看:112
本文介绍了有没有可能调用function.apply而不改变上下文?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一些Javascript代码(特别是node.js)中,我需要调用具有未知参数集的函数而不更改上下文。例如:

 函数fn(){
var args = Array.prototype.slice.call(arguments);
otherFn.apply(this,args);
}

上面的问题是当我调用应用,我通过传递 this 作为第一个参数来改变上下文。我想将 args 传递给被称为的函数,而不用更改被调用函数的上下文。我基本上想这样做:

$ p $ function fn(){
var args = Array.prototype.slice.call (参数);
otherFn.apply(< otherFn's original context>,args);
}

编辑:添加更多关于我的具体问题的详细信息。我正在创建一个Client类,其中包含有关连接的其他信息的套接字(socket.io)对象。

 类客户端
构造函数:(套接字) - > ;
@socket = socket
@avatar = socket.handshake.avatar
@listeners = {}
$ b addListener:(name,handler) - >
@listeners [name] || = {}
@listeners [name] [handler.clientListenerId] = wrapper = =>
#在传递给处理程序之前追加客户端对象作为第一个参数
args = Array.prototype.slice.call(参数)
args.unshift(this)
handler.apply this,args)#< ---- HANDLER的语境在此变化:(

@ socket.addListener(name,wrapper)

removeListener :((name,handler) - >
try
obj = @listeners [name]
@ socket.removeListener(obj [handler.clientListenerId])
delete obj [handler.clientListenerId]

请注意, clientListenerId 是一个自定义的唯一标识符属性,与在这里找到答案相同。

解决方案



 更改上下文
| n | y |
接受数组n | func()| func.call()|
的参数y | ???????? | func.apply()|

PHP有一个函数, call_user_func_array 。不幸的是,JavaScript在这方面缺乏。看起来你使用 eval()来模拟这种行为。

 函数.prototype.invoke = function(args){
var i,code ='this(';
for(i = 0; i< args.length; i ++){
if(i ){code + =','}
code + ='args ['+ i +']';
}
eval(code +');');
}

是的,我知道。没有人喜欢 eval()。这是缓慢而危险的。但是,在这种情况下,您可能不必担心跨站点脚本,至少所有变量都包含在函数中。真的,JavaScript不具备本地功能,但我认为对于这种情况我们有 eval



证明它有效:

  function showArgs(){
for(x in arguments){console.log(arguments [x]);}
}

showArgs.invoke(['foo',/ bar / g]);
showArgs.invoke([window,[1,2,3]]);

Firefox控制台输出:

   -  
[12:31:05.778]foo
[12:31:05.778] [object RegExp]
[12:31:05.778] [对象窗口]
[12:31:05.778] [object Array]


In some Javascript code (node.js specifically), I need to call a function with an unknown set of arguments without changing the context. For example:

function fn() {
    var args = Array.prototype.slice.call(arguments);
    otherFn.apply(this, args);
}

The problem in the above is that when I call apply, I'm change the context by passing this as the first argument. I'd like to pass args to the function being called without changing the context of the function being called. I essentially want to do this:

function fn() {
    var args = Array.prototype.slice.call(arguments);
    otherFn.apply(<otherFn's original context>, args);
}

Edit: Adding more detail regarding my specific question. I am creating a Client class that contains a socket (socket.io) object among other info pertaining to a connection. I am exposing the socket's event listeners via the client object itself.

class Client
  constructor: (socket) ->
    @socket    = socket
    @avatar    = socket.handshake.avatar
    @listeners = {}

  addListener: (name, handler) ->
    @listeners[name] ||= {}
    @listeners[name][handler.clientListenerId] = wrapper = =>
      # append client object as the first argument before passing to handler
      args = Array.prototype.slice.call(arguments)
      args.unshift(this)
      handler.apply(this, args)  # <---- HANDLER'S CONTEXT IS CHANGING HERE :(

    @socket.addListener(name, wrapper)

  removeListener: (name, handler) ->
    try
      obj = @listeners[name]
      @socket.removeListener(obj[handler.clientListenerId])
      delete obj[handler.clientListenerId]

Note that clientListenerId is a custom unique identifier property that is essentially the same as the answer found here.

解决方案

If I understand you correctly:

                          changes context
                   |    n     |      y       |
accepts array    n |  func()  | func.call()  |
of arguments     y | ???????? | func.apply() |

PHP has a function for this, call_user_func_array. Unfortunately, JavaScript is lacking in this regard. It looks like you simulate this behavior using eval().

Function.prototype.invoke = function(args) {
    var i, code = 'this(';
    for (i=0; i<args.length; i++) {
        if (i) { code += ',' }
        code += 'args[' + i + ']';
    }
    eval(code + ');');
}

Yes, I know. Nobody likes eval(). It's slow and dangerous. However, in this situation you probably don't have to worry about cross-site scripting, at least, as all variables are contained within the function. Really, it's too bad that JavaScript doesn't have a native function for this, but I suppose that it's for situations like this that we have eval.

Proof that it works:

function showArgs() {
    for (x in arguments) {console.log(arguments[x]);}
}

showArgs.invoke(['foo',/bar/g]);
showArgs.invoke([window,[1,2,3]]);

Firefox console output:

--
[12:31:05.778] "foo"
[12:31:05.778] [object RegExp]
[12:31:05.778] [object Window]
[12:31:05.778] [object Array]

这篇关于有没有可能调用function.apply而不改变上下文?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆