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.
Related
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]
When I run the following code on Chrome browser, I detect a different behavior between declaring a variable on global namespace and declaring a variable inside a functional namespace for a new object.
1. var ss = 'text';
2. console.log(this.ss);
3. function Person(first){
4. console.log('inside');
5. console.log(this);
6. this.firstName = first;
7. var second = 'Qui';
8. console.log(this.second);
9. }
10. var person1 = new Person('Leo');
On line 1, I declare variable ss and it becomes a property of this (global namespace = Window). I print this.ss on line 2 to confirm.
On line 7, I declare variable second but it doesn't become a property of its this (function namespace for Person object). On line 8, I print this.second which results undefined.
Why declaring a variable on global namespace makes that variable to become a property of this(global namespace = Window) ?
Why the behavior on item 1 does not happen inside a functional scope when creating a new object ?
Why declaring a variable on global namespace makes that variable to become a property of this(global namespace = Window) ?
Because this in the global scope is a reference to the object on which variables reside.
Why the behavior on item 1 does not happen inside a functional scope when creating a new object ?
Because this in the function scope does not behave the same as it does in the global scope.
In a function that has a this binding, its value is determined by the caller of the function, and may be just about any object (or even a primitive in strict mode).
Declaring a variable local to a function does make it in-scope for that function but does not make it a property of the function object. When using the this keyword you are referencing the function as an object and can thus assign a variable to it as a property of that object.
this in the global scope is a reference to the object on which variables reside.
global namespace = Window. You said it yourself
In a function with this binding, its value is set by the caller of the function
further reading
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
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.
What is the difference between
function person(first_name, last_name) {
this.first = first_name
this.last = last_name
}
and this:
function person(first_name, last_name) {
var first = first_name
var last = last_name
}
Why only the first one makes person.first & person.last accessible outside the function?
The this keyword within a function is called the invocation context.
1) If you define your function as a member of an object (a method):
myObject.someMethod = function() { this.x = 2; };
then the invocation context, this, is the object to which the method is being added, myObject. So after calling myObject.someMethod(); above, myObject.x is then 2. The member x is undefined until you call the method, unless you defined it before.
2) If you use your function as a constructor with the new keyword, then this refers to the new object that is being created:
function MyX() { this.x = 3; };
var myX = new MyX();
You'll then have property myX.x set to 3.
Note that I called my constructor MyX(), not myX(). You should call yours Person(), not person(). It's just a convention, but it is useful to indicate that a function is meant to be used as a constructor.
3) Finally, if you use this within a function that you call as neither a method nor a constructor, then this refers to the global object (document or, equivalently, window). Note however that if you are using javascript in strict mode (which you should do), this is undefined in such a situation, which means that you basically cannot use this in a function that is not a method or a constructor.
Your specific question refers to case 2), the constructor. this.x = 3 in the constructor just sets property x of the newly created object. After some object myX is created, you can then access and modify x externally as any other object property using myX.x.
when you write constructor function ( using new) - you add properties using this.XXX
then you do :
var p = new Person('s','d');
and then you have access to p.first etc.
in the second example :
youre not creating any properties..
youre only creating private variables.
so you cant access them...
By using this.something you're saying that THIS is an object and something is his property.
By using var, you're saying that it's just a variable and not a property.
More information about variable vs property:
http://javascriptweblog.wordpress.com/2010/08/09/variables-vs-properties-in-javascript/
Because of function scope.
A variable lifetime is between the curly braces of the function. The this keyword allows to access the function properties outside of it.
Definitely take a look at this link: https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope
'var' keyword make a variable scoped. In the last example var first and var last create variable accessible only in the scope of the function. You can see this as a local variable in a constructor.
when in javascript you declare a variable as
var variable
it only exists inside the method where you declared it. If you want a variable to be accessible for everyone (that is, global) it has to be declared without the 'var' part
You do not necessarily have to use this. It'd also work fine if you've got a structure like this:
Person = function(first_name, last_name) {
var first, last;
create(first_name, last_name);
function create(first_name, last_name) {
first = first_name
last = last_name
}
return {
firstName: first,
lastName: last
}
}
I do not understand this behavior:
var a = 1;
console.log('a is undefined1:', a == undefined);
var a;
//iterate selected jQuery elements:
jQuery.each(this, function(index, htmlElement) {
console.log('a is undefined2:', a == undefined);
var a;
Returns:
a is undefined1: false
a is undefined2: true
If the last line (var a;) is commented out, this is returned:
a is undefined1: false
a is undefined2: false
I would expect always the latter output. What do I not know?
Thanks so much!
Putting var a inside a function creates a different a variable that is scoped to that function.
Since you don't assign a value to it, it is undefined.
When you comment it out, you are testing the outer a which has the value of 1.
Variables are hoisted. It doesn't matter where in a function you use var foo, the foo for that function still applies to the whole function.
Declaring variable within function using var makes local copy (new variable) with scope on the whole function - it does not matter whether it is used before it is declared.
Never declare variables without var.
If you want to access the golobal variable and you have local variable of the same name, you can access the global foo variable using window.foo