I have some JS code where I want to return my global object's instance in its child method (think fluent interface):
myGlobalVar = function() {
this.self = this;
this.Whatever = function() {
//return self; // why does that FAIL??
return this.self; // why does that WORK??
}
}
I would have assumed that I'd return self but that fails. return this.self succeeds but I figured this in the child function would refer to said function. Why does this work?
In javascript the value of this in a function is determined by the caller of the function.
When you call obj.method(), the value of this is set to obj inside of method(). So, in your example above, when you call myGlobalVar.Whatever(), the value of this inside of Whatever() will be myGlobalVar so to reference sefl, you use this.self as you have discovered.
self all by itself does not work because it is not a variable in the current scope all by itself. It's a property of myGlobalVar and thus can ONLY be referenced as either myGlobalVar.self or this.self when this === myGlobalVar. Javascript does not automatically check properties on the current object in order to resolve a symbol. You can only reach a property of an object by specifically referencing the object that hosts the property as in this.self.
There are other ways that the value of this can be altered. If Whatever() is called without the obj context such as:
var fn = myGlobalVar.Whatever;
fn();
Then, the value of this will be either the global object in regular JS or undefined in JS strict mode.
There are also .call() and .apply() methods on every function that allow you to directly specify what you want the this value to be set to inside the method as in myGlobalVar.Whatever.call(myOtherGlobalVar).
When you try and access a variable, JavaScript, first look for that variable in the current function scope, next, in the enclosed functions scope and then finally in the global scope. In your case, self is a member of this, global object. When you say this.self, and if this refers to the global scope, this.self is same as the self. Unless you change the current context, this will refer to the global object and it should work. Check the following example to understand better.
myGlobalVar = function() {
this.self = "thefourtheye";
this.Whatever = function() {
console.log(self);
console.log(this.self);
console.log(this.self === self);
}
}
var b = {
self: "thethirdeye"
}
myGlobalVar();
Whatever();
console.log("-------------------");
Whatever.apply(b);
Output
thefourtheye
thefourtheye
true
-------------------
thefourtheye
thethirdeye
false
When I am calling Whatever, the second time, I am setting the current context to object b, with apply. So, now this points to b. Now, self is different from this.self. When I refer self, it looks up the hierarchy and finds self in the global scope, it prints thefourtheye, when I say this.self, it looks up self in b and it prints thethirdeye. Hope its clear now.
Related
Below I am creating an object in JavaScript. Within the constructor I am setting up an event listener. The problem is that when the event gets fired, this.prop cannot be found, and undefined prints out. How do I solve this?
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
When the event handler gets called, "this" no longer references the "someObj" object. You need to capture "this" into a local variable that the mouseMoving function will capture.
var someObj = function someObj(){
this.prop = 33;
var self = this;
this.mouseMoving = function() { console.log(self.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
I'm assuming "someObj is a constructor, i.e. intended to be called with as new someObj(), otherwise "this" will be the global scope.
The "this" keyword can be confusing in JavaScript, because it doesn't work the same way as in other languages. The key thing to remember is that it is bound to the calling object when the function is called, not when the function is created.
The javascript built-in Function.prototype.bind() is intended for this purpose.
For example:
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving.bind(this),true);
}
More on the bind method here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Other wise you have to pass a reference of the object someObj to the element and use that reference in the line:
console.log(this.referenceToObject.prop); //this references the DOM element in an event.
From Section 4.3 of JavaScript: The Good Parts by Douglas Crockford:
Invoking a function suspends the
execution of the current function,
passing control and parameters to the
new function. In addition to the
declared parameters, every function
receives two additional parameters:
this and arguments. The this parameter
is very important in object oriented
programming, and its value is
determined by the invocation pattern.
There are four patterns of invocation
in JavaScript: the method invocation
pattern, the function invocation
pattern, the constructor invocation
pattern, and the apply invocation
pattern. The patterns differ in how
the bonus parameter this is
initialized.
Crockford continues to explains the binding of 'this' in each of these patterns, as follows:
The Method Invocation Pattern:
When a function is stored as a property of an object, we call it a method. When a method is invoked, this is bound to that object.
The Function Invocation Pattern:
When a function is invoked with this pattern, this is bound to the global object. This was a mistake in the design of the language.
The Constructor Invocation Pattern:
If a function is invoked with the new prefix, then a new object will be created with a hidden link to the value of the function's prototype member, and this will be bound to that new object.
The Apply Invocation Pattern:
The apply method lets us construct an array of arguments to use to invoke a function. It also lets us choose the value of this. The apply method takes two parameters. The first is the value that should be bound to this. The second is an array of parameters.
You could use a variable named 'me', to avoid conflict with the global JavaScript variable 'self':
function someObj() {
var me = this;
this.prop = 33;
this.mouseMoving = function() {
alert(me.prop);
}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
First, you need to understand how 'this' works in JavaScript. 'this' keyword doesn't behave how it behaves in other languages like C# or Java. Read following post to understand more,
What is the rationale for the behavior of the 'this' keyword in JavaScript?
Once you understand that, as Matthew outlined in his code, you can save reference to 'this' and use that reference inside the mouseMoving function.
Though overall, I will advise that you use a JavaScript framework (e.g. jQuery, YUI, MooTools) which will take care of these issues for you. E.g. In Internet Explorer, you use addEvent to attach event and not addEventListenr.
You have some typos on your function declaration.
Your prop variable is also defined as a "public" or "visible" member (by using this.prop), doing so forces you to store the reference of this from the outer function (that is actually a reference to the object instance), as a "private" member of the function (using var) to get access the instance of the created object and read the "public" prop member.
You have some alternatives to rewrite this code:
function someObj (){
var self = this;
this.prop = 33;
this.mouseMoving = function() { alert(self.prop);} // You access the current
// instance, stored in *self*
// since *this*, inside the
// function, is in another
// context.
//...
}
var mySomeObj = new someObj(); // Object instantiation
Or you could:
function someObj (){
var prop = 33;
this.mouseMoving = function() { alert(prop);}
//...
}
var mySomeObj = new someObj(); // Object instantiation
The variables declared with var, are accesible to the functions declared inside of the major constructor function, this feature is known as Closures.
I have a question about what the "this" points to in an arrow function:
// run this file in nodejs by: node test_this.js
const obj = {
scope:this,
func1:()=>{return this},
func2:function(){
const fn = ()=>this;
return fn();
}
}
console.log("0",obj.scope); // module.exports
console.log("1",obj.func1()); // module.exports
console.log("2",obj.func2()); //obj
const newFunc2 = obj.func2;
console.log("newFunc2",newFunc2()); //global
As I konw, arrow function has no own "this". The scope determines the "this" once the arrow function is declared, and it will never be changed. But why the console.log("2",obj.func2()); outputs the obj? and why console.log("newFunc2",newFunc2()); print a different result global?
The lexical value of this for your obj declaration is module.exports. That's the value of this when your obj variable is declared.
So, that explains why obj.scope is module.exports because that is the value of this at the time your object is declared and initialized with your code scope:this,
As you seem to already know, the arrow function declaration when called with an object as in obj.func1() does not carry through obj as this. Instead, it uses the lexical version of this (what it was at declaration time). As obj.scope shows, that lexical value of this is module.exports. So, the result of console.log("1",obj.func1()) is module.exports as expected (because func1 is defined as an arrow function.
Then, with obj.func2(), that is declared as a normal function so the value of this inside of func2, when called as obj.func2() will be obj. This is how method function calls like obj.func2() work in Javascript (as long as the function is a normal function definition or method definition, not an arrow function).
Lastly, when you do this:
const newFunc2 = obj.func2;
You are getting a reference to JUST the func2 method, all by itself. You've isolated just the method and it has no association at all with the object any more. So, when you call it like this:
console.log("newFunc2",newFunc2());
The object referenced for obj is completely gone and the this value will be set the same as any plain function call will be. The value of this will be set to undefined if you're running strict mode or to the global value if not running strict mode.
For a bit of a review of how all this works or a reference for the future, see:
The 6 ways the value of this is determined inside a function at execution time.
When you're assigning obj.func2 to newFunc2, the function is copied to the new variable, having no connection with the obj anymore. So when you are calling newFunc2(), it's referring to the window object by this in that scope. Below example demonstrate that obj.func2 when defined, doesn't have any information of className. When we copy the function func2 in the class MyObj, this now refers to the new class, hence you get the log this.className = 'MyObj'
const obj = {
scope:this,
func1:()=>{return this},
func2:function(){
const fn = ()=>this;
console.log(this.className)
return fn();
}
}
class MyObj {
constructor() {
this.className = 'MyObj'
this.obj()
}
obj() {
this.func2 = obj.func2
}
print() {
this.func2()
}
}
var myObj = new MyObj()
myObj.print()
.
The JavaScript this keyword refers to the object it belongs to.
It has different values depending on where it is used:
In a method, this refers to the owner object.
Alone, this refers to the global object.
In a function, this refers to the global object.
In a function, in strict mode, this is undefined.
In an event, this refers to the element that received the event.
Methods like call(), and apply() can refer this to any object.
In strict mode, when used alone, this also refers to the Global object [object Window]
"use strict";
var x = this; // x equals [object Window]
I have this code:
/// global context
function Outer(){
/// Outer context
this.print = function(){
console.log("1: "+this)
inside(); /// "this" is bound to the global object. Why not bound to the Outer object?
function inside(){
console.log("2: "+this)
}
};
}
function print(){
console.log("3: "+this);
}
var obj = new Outer;
obj.print(); /// "this" is bound to the Outer object.
print(); /// "this" is bound to the global object.
Why inside the method call, this has a global object? Can anyone explain this?
That's because, its obeying following 2 JS rules
Rule 1. In Javascript, new function = new scope - that’s the rule.
Rule 2. When a function is called as a method of an object, this is set to the object the method is called on.
Explanation of the code:
For rule 2, this.print() is a feature of Outer object. So this will refer to the Outer object.
So the console.log 1 will print 1: [object Object]
For rule 1, the function inside() in Outer is not a feature of Outer object. So new scope will created and this assigned to window. And that's also same for the last function 'print()'
So console.log 2 will print 2: [object Window]
And console.log 3 will print 3: [object Window] as well
Hope Helps,
Run the code: https://es6console.com/j9bxeati/
Reference: https://toddmotto.com/everything-you-wanted-to-know-about-javascript-scope/#function-scope
As the reference states,
In most cases, the value of this is determined by how a function is called. It can't be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind method to set the value of a function's this regardless of how it's called, and ES2015 introduced arrow functions which do provide their own this binding (it remains the this value of the enclosing lexical context).
<...>
Inside a function, the value of this depends on how the function is called.
<...>
Since the following code is not in strict mode, and because the value of this is not set by the call, this will default to the global object
<...>
So, in strict mode, if this was not defined by the execution context, it remains undefined.
The posted code is not executed in strict mode, so this equals to global variable (window) inside the function when it's called like print().
If this is not the desirable behaviour, and print is expected to be called separately from the object it originally was defined on (e.g. when being passed as a callback), the function can be bound to its lexical this with arrow in ES6:
function Outer(){
this.print = () => { ... };
}
In ES5 bind or self = this recipe can be used:
function Outer(){
this.print = (function(){ ... }).bind(this);
}
function Outer(){
var self = this;
this.print = function(){
self;
...
};
}
If the function isn't expected to be called with another context, it can be called with another context in-place:
print.call(this);
Or:
print.bind(this)();
If it is not obvious for you, that probably means you confuse scope and context of the function.
Scope is what vars function has access to during invocation. Context (this) is determined by how function is invoked.
Now look on how you invoke your function 'inside' and answer the question. Does it vividly owned by any object? That is why you have global
The value of this is determined by how a function is called.
Your "inside" function was called inside "print" function, which has an object reference, but that object did not have "inside" function as a property or that object did not invoke "inside" function.
"this" refers to the object which called it, not the scope in which it is called.
Hence, the global object
the value of this is depends on how you are making a call to the intended function and generally leading parent object plays important role in it.
what does it mean by leading parent object?:
sampleObj.getDetails(); // here 'sampleObj' is the leading parent object for 'getDetails()' function
lets try to clear the things using some examples of making call to the function using below sample code snippet.
function globalFunction(){
console.log('global this: ', this);
}
var simpleObj = {
name : 'john'
};
var complexObj = {
outer: function(){
console.log('outer this: ', this);
}
}
globalFunction(); // will log global object as no leading parent object is available
complexObj.outer(); // will log 'complexObj' object as leading parent object is 'complexObj'
complexObj.outer = complexObj.outer.bind(simpleObj);
complexObj.outer(); // will log 'simpleObj' object as we have set preference as 'simpleObj' for this **
complexObj.outer.call(); // will log global object as we arent setting any preference for 'this' ***
complexObj.outer.call(simpleObj); // will log simpleObj object as we have set preference as simpleObj for 'this' ***
complexObj.outer.apply(); // will log global object as we arent setting any preference for 'this' ****
complexObj.outer.apply(simpleObj); // will log simpleObj object as we have set preference as simpleObj for 'this' ****
hopefully it will help you!
** what is bind: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
*** what is call: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
**** what is apply: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
You can understand it if you read about arrow functions new in ES6.
Until arrow functions, every new function defined its own this value
(a new object in the case of a constructor, undefined in strict mode
function calls, the base object if the function is called as an
"object method", etc.).
Which means that every function defines it's own this and in case of a simple function it will always be a global object and not the context of a function it is defined in. Just for comparison a function which doesn't define it's own this(an arrow function):
/// global context
function Outer(){
/// Outer context
this.print = function(){
console.log("1: "+this)
let inside = () => {
/// "this" is Outer object here
console.log("2: "+this)
}
inside();
};
}
Does someone has a plausible explanation why javascript does not the pass the object literal as a value to the global variable that is passed via function parameter?
Do I overlook some fundamental rules?
(function(global) {
var id = "3543a1354";
global = {
name: 'global',
getId: function() {
return id;
}
};
})(this.global = this.global || {})
So essentially the value of the parameter 'global' after executing the code is an empty object. Very strange: if setting a breakpoint for example on the last line and execute the object literal assignment in the console, then the value is correctly passed to 'global'.
BTW this would work as expected:
(function(global) {
var id = "3543a1354";
global.name = "global";
global.getId = function() {
return id;
}
}(this.global = this.global || {}))
In both functions, global is a local variable, because it's a function parameter.
In the first case, you're creating a new object with the literal notation, and assigning this to the local variable. This has no effect on the variable that was used in the function call.
In the second case, you're modifying the properties of the object that the local variable refers to. This is the same object that the variable used in the function call refers to, so it's visible to the caller.
You are passing this.global to the function and inside the function global is the parameter which refers to the global global.
When you say,
global = {...}
you are now changing what global refers to. Since you have changed the reference, the global global is left unchanged and the local global refers to the newly assigned object.
In the second case,
global.name = "global";
global.getId = function () {..}
you are altering the local global object, which actually refers to the global global. So, you are indirectly changing global global. That is why, this mutates the global global and the first one didn't.
Consider the following code:
function A() {}
A.prototype.go = function() {
console.log(this); //A { go=function()}
var f = function() {
console.log(this); //Window
};
f();
}
var a = new A();
a.go();
Why does 'this' inside function 'f' refers to the global scope? Why it is not the scope of function 'A' ?
JavaScript has a different concept of what the special name this refers to
than most other programming languages do. There are exactly five different
ways in which the value of this can be bound in the language.
The Global Scope
this;
When using this in global scope, it will simply refer to the global object.
Calling a Function
foo();
Here, this will again refer to the global object.
ES5 Note: In strict mode, the global case no longer exists.
this will instead have the value of undefined in that case.
Calling a Method
test.foo();
In this example, this will refer to test.
Calling a Constructor
new foo();
A function call that is preceded by the new keyword acts as
a constructor. Inside the function, this will refer
to a newly created Object.
Explicit Setting of this
function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // array will expand to the below
foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3
When using the call or apply methods of Function.prototype, the value of
this inside the called function gets explicitly set to the first argument
of the corresponding function call.
As a result, in the above example the method case does not apply, and this
inside of foo will be set to bar.
Note: this cannot be used to refer to the object inside of an Object
literal. So var obj = {me: this} will not result in me referring to
obj, since this only gets bound by one of the five listed cases.
Common Pitfalls
While most of these cases make sense, the first one is to be considered another
mis-design of the language because it never has any practical use.
Foo.method = function() {
function test() {
// this is set to the global object
}
test();
}
A common misconception is that this inside of test refers to Foo; while in
fact, it does not.
In order to gain access to Foo from within test, it is necessary to create a
local variable inside of method which refers to Foo.
Foo.method = function() {
var that = this;
function test() {
// Use that instead of this here
}
test();
}
that is just a normal variable name, but it is commonly used for the reference to an
outer this. In combination with closures, it can also
be used to pass this values around.
Assigning Methods
Another thing that does not work in JavaScript is function aliasing, which is
assigning a method to a variable.
var test = someObject.methodTest;
test();
Due to the first case, test now acts like a plain function call; therefore,
this inside it will no longer refer to someObject.
While the late binding of this might seem like a bad idea at first, in
fact, it is what makes prototypal inheritance work.
function Foo() {}
Foo.prototype.method = function() {};
function Bar() {}
Bar.prototype = Foo.prototype;
new Bar().method();
When method gets called on a instance of Bar, this will now refer to that
very instance.
Disclaimer: Shamelessy stolen from my own resources at http://bonsaiden.github.com/JavaScript-Garden/#function.this
The reason why is you are invoking f as a function and not a method. When invoked as a function this is set to window during the execution of the target
// Method invocation. Invoking a member (go) of an object (a). Hence
// inside "go" this === a
a.go();
// Function invocation. Invoking a function directly and not as a member
// of an object. Hence inside "f" this === window
f();
// Function invocation.
var example = a.go;
example();
The scope of all functions is window.
To circumvent that, you can do this:
function A() {}
A.prototype.go = function() {
var self = this;
console.log(self); //A { go=function()}
var f = function() {
console.log(self); //A { go=function()}
};
f();
}
Because function f() is not called without any object reference. Try,
f.apply(this);