【问题标题】:Call function with parameters from array - apply() without the context parameter?使用数组中的参数调用函数 - apply() 没有上下文参数?
【发布时间】:2012-07-17 04:21:51
【问题描述】:

是否有任何方法调用函数但将上下文 this 设置为当我通过执行 fn() 调用函数时它具有的“默认”值?

这个方法应该接受一个数组并将单个元素作为参数传递给函数,就像 apply() 所做的那样:

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

编辑:为了澄清这一点,我确实关心 this 在被调用函数中的值 - 它必须是它在执行 emitter.emit() 时所具有的“正常”上下文,不是全局对象或其他任何东西。否则,这有时会破坏事情。

【问题讨论】:

  • 那么"normal" 上下文是什么?
  • someObject.emit.apply(someObject, args) 那么呢?
  • @Esailija 是的,这就是他所追求的 - 他只需要一些语法糖来避免重复(根据我的更新答案)
  • @Esailija 啊,不,不止这些 - 他希望第一个 arg 与其他 arg 分开。

标签: javascript


【解决方案1】:

如果你不关心上下文,你可以传递nullundefined。在函数内部,thiswill then refer to the global object 在非严格模式下and to null respectively undefined in strict-mode

函数的“默认”上下文很难定义

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

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

其中哪一个是“正确”的上下文?

在您的情况下,您可能会考虑使用实用功能

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

【讨论】:

  • 整洁 - 我不知道传递 null 会自动将上下文更改为全局对象。
  • 谢谢,但我需要this 来引用“正常”上下文,而不是全局对象。
  • “正常”上下文全局对象。
  • 啊,这似乎是 old 行为,ES5 不支持。
  • 一个函数可以附加到多个对象。如果要将函数附加到特定对象,则必须显式设置。
【解决方案2】:

只需将第一个参数设置为全局对象(即浏览器中的window

在 ES3 浏览器中,您可以改为传递 null,它会自动更改为全局对象,但这种行为 has been removed in the ES5 specifications


EDIT听起来你只需要一个新功能:

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

此时您可以调用:

emitter.emitArgs('event', args);

编辑感谢@Esalija [].concat

【讨论】:

  • 没有被移除,只适用于严格模式es5.github.com/#C
  • 谢谢,但这仍然只是数组的浅拷贝;)
  • @Niko 为什么需要深拷贝?如果emit 函数需要一个深拷贝,它将需要一个 - 此代码只是一个中介。
  • 嗯,你是对的 - 实际上,我不想要一个,因为 emit() 不应该得到副本。没马上明白。
【解决方案3】:

这由本机函数“参数”变量解决。

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

要维护“this”上下文,您可以在构造函数中绑定 emit 方法,尽管这会为每个实例创建“自己的”对象属性,从而增加内存消耗,并且实际上会在对象创建时执行所有原型链查找(对于绑定方法)不管你是否需要。

【讨论】:

    猜你喜欢
    • 2021-05-09
    • 2013-03-31
    • 1970-01-01
    • 1970-01-01
    • 2022-11-28
    • 1970-01-01
    • 2013-03-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多