简体   繁体   中英

Bind this in nested literal object

Let's say I have this code

(function() {

    function Foo(arg) {
        this.name = arg;
    }

    Foo.prototype = {
        bar: {
            baz: function() {
                alert(this.name); // Undefined...
            }
        }
    }

    var foo = function(arg) {
        return new Foo(arg);
    };


    window.foo = foo;

    return foo;
}());

foo("Anything").bar.baz();

How can I make "this" in my function "baz" refers to the object Foo without using bind or apply when I call it from outside ?

FWIW, I would strongly recommend not building nested structures like that, or at least not on the prototype, because the bar object is shared amongst all of the instances, which opens the door to a lot of cross-talk-style bugs. Instead, I'd create bar within the constructor.

How can I make "this" in my function "baz" refers to the object Foo without using bind or apply when I call it from outside ?

You may have bind and apply / call slightly confused. You wouldn't use bind when calling the function, but when creating it. Unless you use bind (or something equivalent to it), you can't do what you've said you want, because absent bind (or similar), this is set by how the function is called, and so this.bar.baz() will make this be this.bar within the call.

Here's how you'd build bar within the constructor, and use bind to make baz use the correct this :

function Foo(arg) {
    this.name = arg;
    this.bar = {
        baz: function() {
            alert(this.name);
        }.bind(this)            // <== Note
    };
}

Example:

 function Foo(arg) { this.name = arg; this.bar = { baz: function() { snippet.log(this.name); }.bind(this) // <== Note }; } var f1 = new Foo("f1"); var f2 = new Foo("f2"); f1.bar.baz(); // "f1" f2.bar.baz(); // "f2" 
 <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 


More about cross-talk: The naive thing to do is to just add one line to your Foo constructor, and keep bar on the prototype:

this.bar.baz = this.bar.baz.bind(this);

That would be a very bad idea , because you'd get cross-talk between instances:

 function Foo(arg) { this.name = arg; this.bar.baz = this.bar.baz.bind(this); // DON'T DO THIS } Foo.prototype = { bar: { baz: function() { snippet.log(this.name); } } }; var f1 = new Foo("f1"); var f2 = new Foo("f2"); f2.bar.baz(); // "f1" -- cross talk! Should be f2 
 <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 

在声明时使用bind来适当地限制它的范围,例如

function foo() {}.bind(this);

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