如何在不改变上下文的情况下将参数数组传递给函数?

时间:2022-10-12 23:17:01

I am dealing with functions which are each bound to a specific context. Somewhere else in the code, I have to call them with a variable number of arguments. Normally, I would do it with apply, but that would change the context (this).

我正在处理每个绑定到特定上下文的函数。在代码中的其他地方,我必须使用可变数量的参数来调用它们。通常,我会用apply来做,但这会改变上下文(this)。

Can I achieve the effect of apply( null, args ) without changing the existing, bound value of this in the function?

我可以在不改变函数中现有的绑定值的情况下实现apply(null,args)的效果吗?

(I don't have the value of the functions's this at hand in a variable when the call needs to happen.)

(当调用需要发生时,我没有函数的值在变量中。)

Incidentally, the question here is not a duplicate of that one where, despite the promising title, the OP is just trying to add syntactic sugar to a method call.

顺便提一下,这里的问题并不是那个问题的重复,尽管有很好的标题,OP只是试图将语法糖添加到方法调用中。

2 个解决方案

#1


Surprisingly, it turns out this is a non-issue. If a function is bound to a context, it can safely be called with apply without the context changing.

令人惊讶的是,事实证明这不是问题。如果函数绑定到上下文,则可以使用apply安全地调用它,而不会更改上下文。

The first argument of apply can be set to anything - undefined, null, window, another object. It doesn't have any effect if the function is bound.

apply的第一个参数可以设置为任何 - undefined,null,window,另一个对象。如果绑定了函数,它没有任何影响。

Example:

var o = { id: "foo" },
    args = [ "bar", "baz" ],
    f = function () {
      var args = Array.prototype.slice.call( arguments ).join( ", ");
      return "Called in the context of " + this.id + " with args " + args; 
    },

    // Binding f to o with ES5 bind
    boundNative = f.bind( o ),

    // Binding f to o with a closure
    boundWithClosure = ( function ( context ) { 
        return function () { 
            return f.apply( context, arguments ); 
        } 
    } )( o );

// Does boundNative.apply( whatever, args ) change the context?
console.log( boundNative.apply( undefined, args ) );
console.log( boundNative.apply( null, args ) );
console.log( boundNative.apply( window, args ) );
console.log( boundNative.apply( { id: "quux" }, args ) );

// Same test with the closure
console.log( boundWithClosure.apply( undefined, args ) );
console.log( boundWithClosure.apply( null, args ) );
console.log( boundWithClosure.apply( window, args ) );
console.log( boundWithClosure.apply( { id: "quux" }, args ) );

All calls return "Called in the context of foo with args bar, baz", so no issue.

所有调用返回“使用args bar,baz在foo的上下文中调用”,所以没有问题。

I have to admit the result surprised me at first. After all, apply enforces a context - how come that is ignored? But in fact it makes perfect sense.

我不得不承认这个结果一开始让我感到惊讶。毕竟,apply强制执行一个上下文 - 怎么被忽略?但实际上它很有道理。

Yes, the original function (f) refers to this, and calling it with apply would change its value. But we are not calling the original function.

是的,原始函数(f)引用了这个,并用apply调用它会改变它的值。但我们并没有调用原来的功能。

The bound function is an entirely separate entity, and it does not reference this any longer. It is not quite so obvious with ES5 bind, but the closure construct gives it away. The this keyword doesn't appear anywhere in the function which is returned by the IIFE. Calling that, there is nothing which apply can change.

绑定函数是一个完全独立的实体,它不再引用它。使用ES5绑定并不是那么明显,但是闭包构造将它放弃了。 this关键字不会出现在IIFE返回的函数中的任何位置。称之为,没有什么适用可以改变。

#2


Context exists always, it can be global object (window) or context of some particular object. When you call a function, it uses some context. Also you should definitely have access to it. The function exist in visible scope (context and scope are not the same)

上下文总是存在,它可以是全局对象(窗口)或某个特定对象的上下文。当你调用一个函数时,它会使用一些上下文。你也一定要访问它。该函数存在于可见范围内(上下文和范围不同)

var text = "Current context is ";

function A() {
    this.test = "A";
    this.print = function(msg) {
        return msg + this.test;
    }
};

function B() {
    this.test = "B";
}

var testObj = {
    test: "testObj"
};

test = "window";

var msgFn = function (msg) {
    return msg + "msgFn";
}

var a = new A();
var b = new B();

a.print.apply(a, [text]); // Current context is A
a.print.apply(b, [text]); // Current context is B
a.print.apply(null, [text]); // Current context is window
a.print.apply(testObj, [text]); // Current context is testObj
msgFn.apply(msgFn, [text]); // // Current context is msgFn

#1


Surprisingly, it turns out this is a non-issue. If a function is bound to a context, it can safely be called with apply without the context changing.

令人惊讶的是,事实证明这不是问题。如果函数绑定到上下文,则可以使用apply安全地调用它,而不会更改上下文。

The first argument of apply can be set to anything - undefined, null, window, another object. It doesn't have any effect if the function is bound.

apply的第一个参数可以设置为任何 - undefined,null,window,另一个对象。如果绑定了函数,它没有任何影响。

Example:

var o = { id: "foo" },
    args = [ "bar", "baz" ],
    f = function () {
      var args = Array.prototype.slice.call( arguments ).join( ", ");
      return "Called in the context of " + this.id + " with args " + args; 
    },

    // Binding f to o with ES5 bind
    boundNative = f.bind( o ),

    // Binding f to o with a closure
    boundWithClosure = ( function ( context ) { 
        return function () { 
            return f.apply( context, arguments ); 
        } 
    } )( o );

// Does boundNative.apply( whatever, args ) change the context?
console.log( boundNative.apply( undefined, args ) );
console.log( boundNative.apply( null, args ) );
console.log( boundNative.apply( window, args ) );
console.log( boundNative.apply( { id: "quux" }, args ) );

// Same test with the closure
console.log( boundWithClosure.apply( undefined, args ) );
console.log( boundWithClosure.apply( null, args ) );
console.log( boundWithClosure.apply( window, args ) );
console.log( boundWithClosure.apply( { id: "quux" }, args ) );

All calls return "Called in the context of foo with args bar, baz", so no issue.

所有调用返回“使用args bar,baz在foo的上下文中调用”,所以没有问题。

I have to admit the result surprised me at first. After all, apply enforces a context - how come that is ignored? But in fact it makes perfect sense.

我不得不承认这个结果一开始让我感到惊讶。毕竟,apply强制执行一个上下文 - 怎么被忽略?但实际上它很有道理。

Yes, the original function (f) refers to this, and calling it with apply would change its value. But we are not calling the original function.

是的,原始函数(f)引用了这个,并用apply调用它会改变它的值。但我们并没有调用原来的功能。

The bound function is an entirely separate entity, and it does not reference this any longer. It is not quite so obvious with ES5 bind, but the closure construct gives it away. The this keyword doesn't appear anywhere in the function which is returned by the IIFE. Calling that, there is nothing which apply can change.

绑定函数是一个完全独立的实体,它不再引用它。使用ES5绑定并不是那么明显,但是闭包构造将它放弃了。 this关键字不会出现在IIFE返回的函数中的任何位置。称之为,没有什么适用可以改变。

#2


Context exists always, it can be global object (window) or context of some particular object. When you call a function, it uses some context. Also you should definitely have access to it. The function exist in visible scope (context and scope are not the same)

上下文总是存在,它可以是全局对象(窗口)或某个特定对象的上下文。当你调用一个函数时,它会使用一些上下文。你也一定要访问它。该函数存在于可见范围内(上下文和范围不同)

var text = "Current context is ";

function A() {
    this.test = "A";
    this.print = function(msg) {
        return msg + this.test;
    }
};

function B() {
    this.test = "B";
}

var testObj = {
    test: "testObj"
};

test = "window";

var msgFn = function (msg) {
    return msg + "msgFn";
}

var a = new A();
var b = new B();

a.print.apply(a, [text]); // Current context is A
a.print.apply(b, [text]); // Current context is B
a.print.apply(null, [text]); // Current context is window
a.print.apply(testObj, [text]); // Current context is testObj
msgFn.apply(msgFn, [text]); // // Current context is msgFn