简体   繁体   中英

Call function with parameters from array - apply() without the context parameter?

Is there any method that invokes a function but sets the context this to the "default" value that it has when I invoke the function by doing fn() ?

This method should accept an array and pass the single elements as arguments to the function, much like apply() does:

emitter = new EventEmitter();
args = ['foo', 'bar'];

// This is the desired result:
emitter.emit('event', args[0], args[1], ...);

// I can do this using apply, but need to set the context right
emitter.emit.apply(emitter, 'event', args);

// How can I trim the context from this?
emitter.emit.???('event', args);

EDIT: To clarify this, I do care about the value that this will have inside the called function - it needs to be the "normal" context it has when doing emitter.emit() , not the global object or anything else. Otherwise, this will break things sometimes.

You can pass null or undefined if you don't care about the context. Inside the function, this will then refer to the global object when in non-strict mode and to null respectively undefined in strict-mode .

A "default" context for a function is hard to define

function f() { return this };
a = { b: f }
c = a.b;

console.log(f());   # window
console.log(a.b()); # a
console.log(c());   # window

Which one of these is the "right" context?

In your case you might consider a utility function

/* you might call it something else */
emitter.emit_all = function (event, args) {
    return this.emit.apply(this, [event].concat(args));
}

Just set the first parameter to the global object (ie window in a browser)

In ES3 browsers you could pass null instead and it would be automatically be changed to the global object, but that behaviour has been removed in the ES5 specifications .


EDIT it sounds like you just need a new function:

EventEmitter.prototype.emitArgs = function(event, args) {
    this.emit.apply(this, [event].concat(args));
}

at which point you can just call:

emitter.emitArgs('event', args);

( EDIT thanks to @Esalija for [].concat )

This is solved by the native Function "arguments" variable.

var EventEmitter = window.EventEmitter = function(){
    //this.emit = this.emit.bind(this);//bind emit to "this"
    return this;
};
EventEmitter.prototype.isMe = function(obj){
    return obj === this;
};
EventEmitter.prototype.emit = function(eventName){
    var input = Array.prototype.slice.call(arguments, 1);
    console.log("this:%O, Emitting event:%s, with arguments:%O", this, eventName,input);
};

emitter = new EventEmitter();
emitter.emit('magicEvent', 'Zelda Con', 'Zork Meetup', 'etc');

To maintain the "this" context you could bind the emit method in the constructor, though this would create per instance "own" object properties increasing memory consumption and practically perform all prototype chain lookups (for bound methods) on object creation regardless if you needed them or not.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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