admin管理员组文章数量:1287611
I don't understand the following:
var x = function() {
this.foo="foo";
return function() {
this.bar = "bar";
return foo+bar;
};
}(); // returns inner
alert(x()); // 'foobar', so both 'this' variables are set
alert(x.bar); // undefined - but wasn't it used correctly?
alert(new x().bar); // ok, works
My assumption was that a default 'this' scope/variable-map is generated and used the first time, and then when 'new' is called, a new object (function?) with a new 'this' is sent through and returned. Or, perhaps x isn't a proper object? But then, how does 'this' end up being set and used to make 'foobar'?
What do I need to know to understand this?
I don't understand the following:
var x = function() {
this.foo="foo";
return function() {
this.bar = "bar";
return foo+bar;
};
}(); // returns inner
alert(x()); // 'foobar', so both 'this' variables are set
alert(x.bar); // undefined - but wasn't it used correctly?
alert(new x().bar); // ok, works
My assumption was that a default 'this' scope/variable-map is generated and used the first time, and then when 'new' is called, a new object (function?) with a new 'this' is sent through and returned. Or, perhaps x isn't a proper object? But then, how does 'this' end up being set and used to make 'foobar'?
What do I need to know to understand this?
Share Improve this question asked Aug 16, 2009 at 6:55 mk.mk. 11.7k6 gold badges42 silver badges56 bronze badges 1- 1 Read all the answers and follow the links to past discussions. – mk. Commented Aug 16, 2009 at 18:29
4 Answers
Reset to default 9First let's go over some fine points of JavaScript, then we can deal with your example.
Function's context
One point of misunderstanding is a context. Every function is called in a context, which is available using a keyword this
. Let's write a function we can use to inspect contexts:
var probe = function(){
// if the context doesn't have a name, let's name it
if(!this.name){
this.name = "lumberjack";
}
// print the name of my context
console.log(this.name);
};
Here we go:
name = "global!";
// when we call a function normally it still have a context:
// the global context
probe(); // prints: global!
var ctx = {name: "ctx"};
// we can set a context explicitly using call()
probe.call(ctx); // prints: ctx
// we can set a context explicitly using apply()
probe.apply(ctx); // prints: ctx
// it is set implicitly, if we call a function as a member
ctx.fun = probe;
ctx.fun(); // prints: ctx
// or we can create a brand new object and set it as a context:
// that's what "new" does
var t = new probe(); // prints: lumberjack
// let's sum it up:
console.log(name); // prints: global!
console.log(ctx.name); // prints: ctx
console.log(t.name); // prints: lumberjack
That's why it is so easy to mess up and fall down inadvertently to the global context.
Returning value in constructor
Many people are confused when they see a constructor returning a value. It is legal. Constructor can return an object, a function, or an array. This value is going to be used as an instance. The old instance is going to be discarded.
var myClass = function(){
// if it is called as a constructor, "this" will be a new instance
// let's fill it up:
this.a = 42;
this.b = "Ford";
this.c = function(){ return "Perfect"; };
// done? let's discard it pletely!
// and now for something pletely different...
return {
owner: "Monty Python",
establishment: "Flying Circus"
};
};
var t = new myClass();
alert(t.owner + "'s " + t.establishment);
As expected it shows "Monty Python's Flying Circus".
If a constructor returns something else (e.g., a number, a string, the null, the undefined) the returned result is going to be discarded and the old instance will be used.
The example
Your example is hard to understand mostly because of the way it was written. Let's simplify it by rewriting.
First let's deal with the x
:
var x = function() {
this.foo = "foo";
return function() {
this.bar = "bar";
return foo + bar;
};
}(); // returns inner
As we can see the anonymous function (the 1st function
) is executed immediately, so we can inline it:
// next assignment can be simplified because
// top "this" is window or the global scope
//this.foo = "foo"; =>
foo = "foo";
x = function() {
this.bar = "bar"; // this line depends on its context, or "this"
return foo + bar; // this line uses global "foo" and "bar"
};
So at the end we have two global variables: foo
(a string) and x
(a function).
Now let's go over the 1st alert:
alert(x()); // 'foobar', so both 'this' variables are set
Again, let's inline x()
:
// next assignment can be simplified because
// top "this" is window or the global scope
//this.bar = "bar"; =>
bar = "bar";
// at this moment both global "foo" and "bar" are set
alert(foo + bar); // => "foo" + "bar" => "foobar"
The 2nd alert is equally simple:
alert(x.bar); // undefined - but wasn't it used correctly?
It doesn't need much rewriting. x
is a function, we didn't add any properties to it, so x.bar
is undefined. If you add it, you can see results:
x.bar = "bar2";
alert(x.bar); // bar2
The 3rd alert demonstrates JavaScript's OOP in action:
alert(new x().bar); // ok, works
(A side note: it works only because you ran x()
first, otherwise it blows up because bar
is undefined).
Let's rewrite it like that:
var t = new x();
alert(t.bar); // bar
Now let's analyze the constructor. It has two statements: an assignment, and a return. The latter is ignored because it returns a string. So we can rewrite it like that:
x = function(){
this.bar = "bar";
};
var t = new x();
alert(t.bar); // bar
I hope it all looks easy now.
That's the major plain of the new operator...
That operator creates a new object that inherits from the prototype of the operand constructor function, and then it calls the function, assigning the new object to this
.
If you forget to use the new operator when calling a constructor function, you get instead normal function call, and this
is bound to the global object (window
) instead of to a new object.
Your function will be appending global variables whenever it uses this
attempting to initialize its own instance.
In your example the global object ends up with two new variables:
window.foo
window.bar
Because of that some people prefer prototypal inheritance instead of the pseudo-classical approach.
To answer the question you ask in your title: this
will reference the global object.
Keep in mind, this
does not behave in JavaScript as it does in languages like Java or C++; it's used purely for context, and will not necessarily reference the same sort of object every time a given function is called. From the MDC documentation:
There are four ways
this
can be passed
[...]
If none of the above ways are used, the global object is passed as the context object, e.g., when this occurs at top-level outside of any constructor, or when a function is called without being called as a method of an object, as infunc(arg1, arg2)
.
For answers to the rest of your question, please see: Just when I think I finally understand Javascript scope…
As Shog9 said, this is not the same as normal scoping like you see in Java, etc.
AFAIK Javascript uses dynamic scoping, like Common LISP/eLisp does, and not lexical scoping like Scheme/Lisp-1 does.
本文标签: javascriptWhat is 39this39 before an object is instantiated in jsStack Overflow
版权声明:本文标题:javascript - What is 'this' before an object is instantiated in js? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741310918a2371644.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论