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

时间:2015-05-11 08:40:00

标签: javascript

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

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

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

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

2 个答案:

答案 0 :(得分:1)

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

apply的第一个参数可以设置为任何内容 - undefinednullwindow,另一个对象。如果函数绑定,它没有任何效果。

示例:

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

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

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

是的,原始函数(f)引用this,并使用apply调用它会更改其值。但我们并没有调用原来的功能。

绑定函数是一个完全独立的实体,它不再引用this。 ES5 bind并不是那么明显,但是闭包构造将它放弃了。 this关键字不会出现在IIFE返回的函数中的任何位置。调用它,apply无法改变。

答案 1 :(得分:0)

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

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