有没有可能调用function.apply而不改变上下文? [英] Is it possible to call function.apply without changing the context?
问题描述
函数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屋!