嵌套.bind无法按预期工作

时间:2014-11-13 07:19:01

标签: javascript closures call bind nested-function

不幸的是.bind在创建更复杂的闭包时给了我一个悲伤。

我很感兴趣。为什么.bind在嵌套函数后似乎有不同的工作方式。

例如:

function t(){
    t = t.bind({}); //correctly assigns *this* to t  
    function nested_t(){
        nested_t = nested_t.bind({}); // fails to assign *this* to nested_t
        return nested_t; 
    }
    return nested_t(); 
}
//CASE ONE
alert(t()); 
          // alerts the whole function t instead of nested_t

//CASE TWO
aleft(t.call(t)); 
         // alerts the global object (window) 

在这两种情况下,我都期待这样的行为:

function t(){
    var nested_t = function nested_t(){
        return this;
    };
    return nested_t.call(nested_t);
}

alert(t.call(t));

如果有人能够在第一个(和/或)第二个案例中解释.bind的行为,那将非常感谢!

3 个答案:

答案 0 :(得分:3)

所以,我不是完全重现你的问题(这两种情况都返回全局对象),但我会尝试解释我看到的代码。

function t(){
    t = t.bind({}); //correctly assigns *this* to t  
    function nested_t(){
        nested_t = nested_t.bind({}); // fails to assign *this* to nested_t
        return this; 
    }
    return nested_t(); 
}
//CASE ONE
alert(t()); 

让我们一步一步来。

首先,定义函数t()。然后,在通话时,它会被干净的上下文覆盖。但是,我没有看到任何使用这种情况。

现在,定义了嵌套函数(nested_t)。 通话后,会被干净的上下文覆盖。然后它会在调用时返回的上下文。

返回t()。然后,您返回nested_t()结果 nested_t本身。在原始函数调用中,仍然使用全局上下文调用nested_t

因此,当您运行t()时,它将返回全局对象。

答案 1 :(得分:2)

您的代码如何工作

目前还不清楚,您的代码正在尝试做什么。您可以找到.bind() here的文档。看起来你可能在某种程度上误解了this是什么以及如何使用它。无论如何,运行代码时会发生什么:

  1. 在全局范围内创建t函数。
  2. [案例一] 调用t函数。
    1. 全局范围t将替换为新值(绑定到特定上下文的原始t - 匿名空对象),不会以任何方式影响当前调用。此外,在覆盖全局t时,本地t表现为只读。您可以尝试使用以下代码进行检查:(function foo () { return (function bar () { bar = window.bar = 'baz'; return bar; })(); })()并将返回值与window.bar进行比较。
    2. 在嵌套上下文(而不是全局上下文)中nested_t也会发生同样的事情。
    3. 返回nested_t来电的结果。 nested_t返回调用它的上下文,即window,因为没有指定上下文。具体来说,它没有使用空对象上下文调用,因为.bind()内部不会影响调用本身。
  3. [案例二] 完全相同的事情再次发生。现在,您只需将t作为上下文调用。由于t在其代码中的任何位置都没有使用其上下文(this),因此没有任何改变。

  4. 你的误解可能是什么

    基本上,你混淆了两件事 - 函数实例和函数调用上下文。函数是JavaScript中的“一等公民” - 它是一个对象,您可以为其属性赋值。

    function foo () {
        foo.property = 'value';
    }
    foo();    // foo.property is assigned a value
    

    这与函数调用上下文无关。当您调用函数时,上下文被分配给该调用,可以使用this(函数体内)访问

    function foo () {
        this.property = 'value';
    }
    var object = {};
    foo.call(object);    // object.property is assigned a value
    

    当您使用.bind()时,您只需使用相同的代码创建一个新函数,该函数将锁定到特定的上下文。

    function foo () {
        this.property = 'value';
    }
    var fixedContext = {},
        object = {};
    bar = foo.bind(fixedContext);
    foo.call(object);    // fixedContext.property is set instead of object.property
    

    但在这种情况下,还有函数实例foobar,它们也可以被赋予属性,并且与这些函数的调用的上下文无关。

答案 2 :(得分:1)

让我们看一下bind的工作原理。首先,一级嵌套:

var foo = function() { return this.x; };
alert(foo());  // undefined
alert(foo.bind({x: 42})()); // 42

现在我们可以添加下一级嵌套:

var bar = function() { return foo.bind(this)(); };
alert(bar());  // undefined
alert(bar.bind({x: 42})());

我们将this上下文传递给foo - 猜猜是什么? - bindbind在范围之间的工作方式没有什么不同。唯一的区别是我们已将this绑定在bar内,因此bar的正文可以在this内重新绑定foo

正如一些评论者所指出的那样,覆盖自身的功能是一种巨大的代码味道。没有理由这样做;当你打电话给你时,你可以bind上下文。

我非常强烈建议您阅读the documentation on bind,然后尝试理解,以便从头开始编写基本版Function.prototype.bind