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);
}
};
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);
}
};
Share
Improve this question
edited Jul 6, 2013 at 2:51
Rooster
10.1k8 gold badges49 silver badges72 bronze badges
asked Jul 6, 2013 at 2:45
Asad IqbalAsad Iqbal
3,3414 gold badges35 silver badges54 bronze badges
7
-
Because
smallMap
is an object? And personally I feel explicit > implicit :) – Ja͢ck Commented Jul 6, 2013 at 2:50 -
2
Javascript isn't really OO, it's just faking it by setting
this
when necessary. – Barmar Commented Jul 6, 2013 at 2:51 - @Barmar that's a subjective argument, it depends on what you understand OOP to be. – Ja͢ck Commented Jul 6, 2013 at 2:54
- 1 Is JavaScript Object Oriented? – kojiro Commented Jul 6, 2013 at 2: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 Commented Jul 6, 2013 at 2:57
8 Answers
Reset to default 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 pletely 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.
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/en-US/docs/Web/JavaScript/Reference/Operators/this
Also take a look at call, apply, and bind for more info related to this.
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.
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
.
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.
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...
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() { ... }
.
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 fort blanket for Java developers. (Although since JavaScript doesn't have function overloading, x.f(y,z) gives you useful namespacing for function f
.)
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745122577a4612500.html
评论列表(0条)