最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

function - javascript object this - Stack Overflow

programmeradmin5浏览0评论

I have an object and it has another inner object. How can I call the parent object from the inner object?

var test = {
    init: function () {
        var instance = this;
    },
    call: function() {
        this.stop(); // works
    },
    stop: function() {
        this.parseText(); // works
    },
    parseText: {
        load: function ()
        {
            this.call(); //*** dont work
            instance.call(); // work, but what if i have this instance (same name) on another object, would'nt this conflict it?
        }
    }
};

I'm using an instance, which works fine, but what if I or someone wrote an instance (same name) var in another object, wouldn't it will conflict and overwrite this instance?

I have an object and it has another inner object. How can I call the parent object from the inner object?

var test = {
    init: function () {
        var instance = this;
    },
    call: function() {
        this.stop(); // works
    },
    stop: function() {
        this.parseText(); // works
    },
    parseText: {
        load: function ()
        {
            this.call(); //*** dont work
            instance.call(); // work, but what if i have this instance (same name) on another object, would'nt this conflict it?
        }
    }
};

I'm using an instance, which works fine, but what if I or someone wrote an instance (same name) var in another object, wouldn't it will conflict and overwrite this instance?

Share Improve this question edited Oct 30, 2011 at 10:41 Felix Kling 817k180 gold badges1.1k silver badges1.2k bronze badges asked Oct 30, 2011 at 10:15 BasitBasit 17.2k31 gold badges98 silver badges156 bronze badges 7
  • 2 Your examples doesn't work. instance is only visible in the scope of init, and will not be usable inside parseText.load – Eric Commented Oct 30, 2011 at 10:27
  • like i told @Rob i wanted to use self/this or instance inside the object, rather then direct object name.. dont want to use object name inside functions, so how can i do that? – Basit Commented Oct 30, 2011 at 10:31
  • @Basit: Look again at Eric's answer, he's giving you a reasonable way to do what you say you want (a working version of your updated example, which doesn't work). – T.J. Crowder Commented Oct 30, 2011 at 10:35
  • 1 @Basit: That's exactly the same as our answers! The only difference is we named our variables object and obj instead of self – Eric Commented Oct 30, 2011 at 10:36
  • 1 This is a duplicate of stackoverflow./questions/6873281/… – T.J. Crowder Commented Oct 30, 2011 at 10:55
 |  Show 2 more ments

4 Answers 4

Reset to default 9

Eric's answer gives you a reasonable example of how to do what you want to do, but doesn't really go into why.

In JavaScript, this is set entirely by how a function is called (for now; see below the fold for details), not where the function is defined as it is in some other languages that have the same keyword (Java, C++, C#, ...).

You, the coder, determine what this will be each time you call a function. There are two main ways: By calling the function via an object property (in the same expression), or explicitly using the function's built-in call and apply functions.

Via an object property

Using an object property:

obj.foo();    // or
obj["foo"](); // both work

That does two very distinct things, but which collaborate to set the this value: First, the function reference is found by looking up the foo property of the object obj. Then, the function is called. Because you called it as part of the same overall expression retrieving the property value, the JavaScript engine will set this to obj within the call.

So in your example, test.parseText.load(), within the load call this will be parseText, not test, because that's the object on which load was looked up.

Note that setting-this-via-property-lookup only works when they're done at the same time. This does not work:

var f = obj.foo;
f(); // `this` will not be `obj` within the call

That doesn't work because they weren't done at the same time. The property lookup and function call were separated.

Using call or apply

The second way of setting this is more explicit: All functions have the call and apply properties, which are themselves function references that call the function using information you supply. In both cases, the first argument is the object to use as this during the call. So if we wanted to fix the example above that didn't work, we could do this:

var f = obj.foo;
f.call(obj);  // `this` will be `obj` within the call
f.apply(obj); // same

The only difference between call and apply is how you supply function arguments. With call, you supply them as further discrete arguments to the function; with apply, you pass in an array of arguments.

So these all do the same thing:

// 1 - Directly via property
obj.foo("a", "b", "c");

// 2 - Using `call`
f = obj.foo;
f.call(obj, "a", "b", "c");

// 3 - Using `apply`
f = obj.foo;
f.apply(obj, ["a", "b", "c"]); // Note the `[ ... ]`, one array with three elements

You can see how call and apply could work with your existing structure:

test.parseText.load.call(test.parseText);

That calls test.parseText.load, making this = test.parseText within the call.

What Eric did in his answer was to use a closure to make it simpler for you to call parseText with the this value you expect.

Further reading (disclosure: from my blog):

  • Mythical methods
  • You must remember this
  • Closures are not plicated

Up top I said:

In JavaScript, this is set entirely by how a function is called (for now...

The reason I said "for now" is that in ES6, JavaScript is getting "arrow functions" and unlike other functions, the value of this within an arrow function is set by where they're created, not how they're called: They get this from the context where you create them.

Suppose you were writing code in an object method and wanted to use another method of the object to, I don't know, output information from an array (yes, this is contrived). In ES5, you'd probably do this:

this.output("Entries:");
theArray.forEach(function(entry, index) {
    this.output(index + ": " + entry);
}, this);
// ^------- tells `forEach` what to use as `this` during the callback

If you left off the argument, you'd have a bug:

this.output("Entries:");
theArray.forEach(function(entry, index) {
    this.output(index + ": " + entry); // <== Bug, `this` is either
                                       // `undefined` (strict) or
                                       // the global object (loose)
});

But since arrow functions inherit this from where they're created rather than getting it based on how they're called, the arrow function version of that doesn't need the second argument:

this.output("Entries:");
theArray.forEach((entry, index) => {
  this.output(index + ": " + entry);
});

If all you're worried about is test changing, do it like this:

var test = (function() {
    var object = {}
    object.call = function() {
        this.stop(); // works
    };
    object.stop = function() {
        this.parseText(); // apparently works, even though parseText is not a function
    };
    object.parseText = {
        load: function() {
            object.call(); // works
        }
    };
    return object;
})();

If you don't know the name of test, you can use a self-invoking anonymous function to create a wrapper, and refer to the object as shown below.

Note that test is not a reference to a function, but to the return value of the anonymous function. Because the object name (obj) is wrapped inside a function, it cannot be read or modified from outside

The solution below is neat, does not pollute the scope of test, and works like a charm. As mentioned earlier, test refers to the same object as obj. It's however not possible to manipulate variable obj, from outside, so that the code inside the function breaks.

var test = (function(){ //Self-executing function
    var obj = {
        call: function() {
            this.stop(); // works
        },
        stop: function() {
            this.parseText(); // works
        },
        parseText: {
            load: function ()
            {
                obj.call();  // obj refers to the main object
            }
        }
    };
    return obj; //Return the object, which is assigned to `test`.
})(); //Invoke function

Update

It's not possible to reliably refer to self, this, or any reference to the object inside an object, without wrapping it.

Your current solution does not work, see ments in the code below:

var obj = {
   init: function(){
      var instance = this; //`instance` is declared using `var` inside a function
   },                       // This variable cannot read from "the outside"
   parseText: {
      load: function(){
          instance.call(); //Does NOT work! instance is not defined
      }
   }
}

"call" is actually a built-in function on the function object that can be used to call the function specifying what to use for this. How does your code work? It doesn't seem like it should since parseText isn't a function...

Maybe try this:

parseText: function() {
    var load =  function ()
    {
        this.call(); //*** should work
    };
    load.call(this);
}
发布评论

评论列表(0)

  1. 暂无评论