3

Consider this code:

In the hello function I use this.msg. This works fine. However, it gives a msg unefined error if I don't use this. Why is JavaScript confused, while in many other OO languages this is used only to make code explicit to the reader?

var smallMap = {
    msg: "Hellow ",
    hello: function(name) {
        console.log(this.msg + name);
    }
};
Rooster
  • 9,954
  • 8
  • 44
  • 71
Asad Iqbal
  • 3,241
  • 4
  • 32
  • 52
  • Because `smallMap` is an object? And personally I feel explicit > implicit :) – Ja͢ck Jul 06 '13 at 02:50
  • 2
    Javascript isn't really OO, it's just faking it by setting `this` when necessary. – Barmar Jul 06 '13 at 02:51
  • @Barmar that's a subjective argument, it depends on what you understand OOP to be. – Ja͢ck Jul 06 '13 at 02:54
  • 1
    [Is JavaScript Object Oriented?](http://stackoverflow.com/questions/107464/is-javascript-object-oriented) – kojiro Jul 06 '13 at 02:54
  • Yeah. Every OO language is slightly different in the way they implement accessing instance variables. JS requires you to do it through `this`. – Barmar Jul 06 '13 at 02:57
  • @Mr_Green: Horribly wrong and misleading. Arrays are objects. Only strings, numbers, booleans, null, and undefined are not objects. – user2357112 Jul 06 '13 at 06:09
  • @user2357112 Yes I was wrong. I deleted my comment. – Mr_Green Jul 06 '13 at 12:25

8 Answers8

3

Because this is special in Javascript and doesn't always apply to the same object. For example I could do this:

var smallMap = {
    msg: "Hellow ",
    hello: function(name) {
        console.log(this.msg + name);
    }
};

var smallMap2 = {
    msg: "Hellow2 ",
    hello: function(name) {
        console.log(this.msg + name);
    }
};
//here i set `this` to refer to `smallMap2` within smallMap
smallMap.hello.call( smallMap2, "the name" );
//will print "Hellow2 the name" instead of "Hellow the name"

this refers to the object that the function is being called on and not the necessarily the object that the function is a property of. See this for more details:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

Also take a look at call, apply, and bind for more info related to this.

go-oleg
  • 19,272
  • 3
  • 43
  • 44
  • 1
    +1 for giving actual code examples and demonstrating why the OP's interpreation *cannot* work – Brandon Jul 06 '13 at 03:32
3

"Why is JavaScript confused,"

It's not. It has a specific set of rules governing how access to object properties works. It's just that those rules are not the same as every other OO language.

"in many other OO languages this is used only to make code explicit to the reader"

In some OO languages, e.g., Java, this is sometimes used just to make the code explicit to the reader, but really it isn't completely optional - it is required to distinguish between instance variables (members) and other variables of the same name (e.g., local variables in methods).

JavaScript is object oriented, but it doesn't have classes and doesn't have member methods like some other OO languages such as Java. In JavaScript functions are a type of object and in general terms any variable or object property may be set to reference any function - so even when you define a function inside an object literal like in the question that function isn't owned by the object in question. An example:

function test1() {
    alert('test1');
}
var obj1 = {
    prop1 : 'obj1',
    method1 : test1,
    method2 : function() {
       alert(this.prop1);
    }
}
var test2 = obj1.method2;

obj1.method1();                 // alerts 'test1'
test1();                        // alerts 'test1'
obj1.method2();                 // alerts 'obj1'
test2();                        // alerts undefined (probably; see note below)
test2.call({prop1 : 'test2'});  // alerts 'test2'
delete obj1.method2;            // remove the property
alert(obj1.method2);            // alerts undefined - property no longer exists
test2.call({prop1 : 'test2'});  // alerts 'test2' - the function still exists

Notice that obj1.method1 references a function defined outside the literal, a function that can be called directly with test1(). Similarly, test2 has been set to refer to a function that has been defined in the literal but can be called directly - even if you actually remove the method2 property you can still call test2() directly.

I defined method2 / test2 so that it uses this.prop1. The value of this is set depending on how a function is called. If you call it with "dot" notation, like obj1.method2() then within the function this will be the object before the dot. If you call the function directly like test2() then in non-strict mode this would be window, but in strict mode may be undefined or some other value - see MDN for more details. Or you can call a function with .call() or .apply() and explicitly set this to some other object, like in the example above.

nnnnnn
  • 147,572
  • 30
  • 200
  • 241
1

In Javascript, it's impossible to statically determine what properties this has. The msg property could be deleted, or the hello method could be attached to a new object or called as an ordinary function. Thus, Javascript has to assume that an unqualified identifier refers to a variable instead of an object property, even if the object happens to have a property with the right name. It's possible to force Javascript to look in the object properties with a with statement, but because you can't tell what the properties are, this is generally considered a horrible idea.

user2357112
  • 260,549
  • 28
  • 431
  • 505
1

What you have created is an object (or at least as far as JS is concerned). When you want to access the objects own properties, you will need to use the this keyword.

An object in JS is simply a collection of variables and functions. When you want to use the objects own variables inside it, you will need to use this. You have created this object by using {} or curly-braces in the definition of the object.

Outside the confines of the object, you will need to use, <objectName>.var_or_func.

Games Brainiac
  • 80,178
  • 33
  • 141
  • 199
  • 1
    Note that inside the confines of the object you can only use `this` to access its properties if the function in question was called in a way that sets `this` to the object in question. – nnnnnn Jul 06 '13 at 04:19
1

What you have coded is not a class, but an object.

The word this in javascript is related to the scope and not to the object that this peace of code is in.

You could get something like you want by doing this:

var smallMap = (function(){
    var msg = "Hellow ";

    return {
        hello : function(name) {
            console.log(msg + name);
        }
    }   

})();

That said you also can't use this.msg. Just try it out and you will see.

Rafael Fontes
  • 1,195
  • 11
  • 19
1

Since Javascript is not really object-oriented (it is prototypical, meaning, objects can inherit directly from other objects), things doesn't work quiet the same as OO from scoping perspective:

Let's take your example, and use it to inherit the "hello" function by another object:

var new_obj;
new_obj.hello = smallMap.hello;

There, now another object has the same function. Alas, when this function will be called on new_obj, for example:

new_obj.hello("test");

unless we define new_obj.msg, we'll get undefinedtest.

So here we should be careful: what do we really want ? to use the new_obj.msg or to always use smallMap.msg. If the answer is the latter, we should be using smallMap.msg instead of this.msg inside function hello. TMHO of course...

Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
  • 1
    _"Javascript is not_ really _object-oriented"_ - Yes it is. Classical inheritance isn't the only valid form of OO. – nnnnnn Jul 06 '13 at 04:16
  • @nnnnnn I would reply but someone else already did a better job than I could, explaining why the encapsulation characteristic is problematic in JS: http://stackoverflow.com/a/108773/1057429 – Nir Alfasi Jul 06 '13 at 06:01
  • 1
    Yes, I've read that answer before. Note that it starts out declaring itself "only an opinion", mentions a few issues, and then concludes "my vote still remains that Javascript is object oriented", so doesn't that support _my_ point of view? The main issue discussed there is about the idea that JS isn't really OO because it fails to provide both encapsulation and inheritance, but even if we assume that to be true of JS the idea that you _must_ have inheritance for OO is itself not true (though of course there are many reasons why it is desirable). – nnnnnn Jul 06 '13 at 06:12
  • @nnnnnn now it becomes a philosophical argument :) well, you're right - I guess that it's a matter of opinion. BTW I wouldn't say that Javascript's prototypal-inheritance is not considered as an OO inheritance even though it doesn't work the same as class-inheritance. – Nir Alfasi Jul 06 '13 at 07:32
  • I agree with you that prototypal inheritance is still inheritance and is OO. I was referring to the point made in the answer you linked to that basically said that JS can do encapsulation or inheritance but not both at once (although I'm not sure I agree with that). Anyway, it sounds like you and I are at least in the same chapter if not on the same page, so no need to get too esoteric about it. – nnnnnn Jul 06 '13 at 07:48
0

Using object literals ({ ... }) is not the same as defining a class. The scope for the "hello" function is the same as if you defined it externally, e.g., smallMap.hello = function() { ... }.

Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
0

The reason for this is so that you can write arg1.func(arg2, arg3) and refer to arg1 as this within the definition of func, instead of writing func(arg1, arg2, arg3). this is resolved dynamically unlike other variables which are resolved statically (which is why you can't access msg without it). It's there to facilitate dot notation for calling 'methods', and it's there as a comfort blanket for Java developers. (Although since JavaScript doesn't have function overloading, x.f(y,z) gives you useful namespacing for function f.)

1983
  • 5,882
  • 2
  • 27
  • 39
  • 1
    _"it's there as a comfort blanket for Java developers."_ - It is? In my experience it tends to cause Java developers more problems than not, because they usually assume `this` will work exactly the same as in Java. – nnnnnn Jul 06 '13 at 04:08
  • @nnnnnn Indeed JavaScript often *looks* like it works similarly to Java, but doesn't really. – 1983 Jul 06 '13 at 07:57