How explain behavior this function clear() ?
Why object a don't assigned the null ?
var a = {};
function clear(a) {
a.b = 2;
a = null;
}
clear(a);
console.log(a); // {b: 2}
console.log(a.b); // 2
When you create a variable in JavaScript, you are not working with the object itself. You are instead working with a reference to the object. Think of variables as signs that point to objects (in other languages like C, these references are appropriately called pointers).
Also, any arguments referenced inside of functions are their own, distinct references. Therefore, assigning these variables to something else while inside the function does not change (mutate) the object that they reference.
For example:
var someObject = {a: 1, b:2, c:3};
function doSomething(a) {
a = null;
}
doSomething(someObject);
console.log(someObject) // {a: 1, b:2, c:3}
The only thing that happened inside of the doSomething function was that a was set to point to null rather than someObject.
In your example, you have a global variable (variable defined outside of a function) called a, and a local function variable also called a. If you want the function to change the global a, you would have to either remove the argument from clear, or change the argument name and still reference a inside the clear function, like so:
var a = {};
function clear() {
a.b = 2;
a = null;
}
clear();
console.log(a); // null
console.log(a.b); // Uncaught TypeError: Cannot read property 'b' of null
or
var a = {};
function clear(b) {
a.b = 2;
a = null;
}
clear(a); // Note that it does not matter whether you pass a in or not
console.log(a); // null
console.log(a.b); // Uncaught TypeError: Cannot read property 'b' of null
When you are passing a to function clear, you pass the copy of the reference to object a. So executing a.b = 2; sets value b in object a.
But as I have mentioned a inside of clear function is just a copy of the reference, so setting it to null simply says that inside of the clear function parameter a points to null. it does not modify the original a object.
Related
Hey I was wondering why the following returns undefined:
let variable;
module.exports.initialize = () => {
variable = "123";
};
module.exports.variable = variable;
I simply require the module in file A and then call the initialize function. In file B I require it and console.log the variable but it returns undefined. What am I missing here?
module.exports.variable is a property on the module.exports object. When you initialize your module, you assign the value of variable to that module.exports.variable property and that value is undefined at the time you assign it (because the initialize() function has not yet been called).
So, when your module is done initializing itself, module.exports.variable is undefined.
Then, sometime later someone else calls module.exports.initialize() and that changes the local variable within your module to "123". That does not affect the value of the module.exports.variable property at all. It remains undefined.
In the future, please don't give either a property or a variable the name variable as it makes it very difficult to document or discuss. A different name that doesn't conflict with the English definition of the word variable would simplify discussing this code.
What you can do instead is export an object instead of a plain value.
let myObj = { name: "John"};
module.exports.setName = (name) => {
myObj.name = name;
};
module.exports.sharedObj = myObj;
Then, why you import it somewhere else
const aModule = require('./otherModule');
console.log(aModule.sharedObj); // {name: "John"}
aModule.setName("Bob");
console.log(aModule.sharedObj); // {name: "Bob"}
Because objects in Javascript are assigned by pointer, when you did module.exports.sharedObj = myObj; in the module initialization, it put a pointer to myObj into module.exports.sharedObj so when myObj changes, anyone viewing module.exports.sharedObj will see that change too. This only works this way for objects in Javascript, not for other types of values (strings, numbers, etc...).
In JavaScript there are two types of values: 1) primitive type and 2) reference type. primitive values are always copied by their value and reference types are always copied by their references (not by their values).
Examples of primitive values: undefined, null, boolean, string, number.
Examples of reference types: every types other than primitive types. e.g., Object, array etc. See the snippet below.
Example of Primitive type
let a = 10;
let b = a;
console.log(a);
console.log(b);
b = 20;
console.log(a);
console.log(b);
Example of Reference type
let obj_a = {value: 1}
let obj_b = obj_a;
console.log(obj_a);
console.log(obj_b);
obj_b.value = 20;
console.log(obj_a);
console.log(obj_b);
So when you declare the variable as let variable its value is undefined and when you assign module.exports.variable = variable then you're just setting it's value to undefined.
See the example below.
const myExports = {};
let variable;
function initialize() {
variable = 10;
}
myExports.variable = variable;
console.log(variable);
console.log(myExports.variable);
initialize();
console.log(variable);
console.log(myExports.variable);
But if you were to initialize the the variable with a reference type e.g., an object then module.exports.variable would reflect any change to the properties of your variable variable.
Example:
const myExports = {};
let object = {};
function initialize() {
object.value = 10;
}
myExports.variable = object;
console.log(object);
console.log(myExports.variable);
initialize();
console.log(object);
console.log(myExports.variable);
Hope it make sense.
try initializing the variable in the module.exports.initailize function
module.exports.initialize = () => {
let variable;
variable = "123";
};
module.exports.variable = variable;
function myConstructor (arg) {
this.myName = arg;
this.totalNumber = 0;
this.foo = {
bar: {
someBoolean: false,
someNumber: 5
},
baz: {
someBoolean: false,
someNumber: 10
}
};
}
myConstructor.prototype.getNumber = function () {
console.log(this); //successfully returns the child object
for (var i in this.foo) {
//console log tests
console.log(this); //still returns the child object with all properties, including the myName 'whatever'
console.log(this.foo); //returns the 'foo' object with all nested properties
console.log(i); //returns 'bar' and 'baz', respectively
console.log(this.foo.hasOwnProperty(i)); //returns true
//where it all goes wrong
console.log(typeof(i)); //returns 'string'
console.log(this.foo.i); //returns undefined, even though 'this.foo' definitely has 'bar' and 'baz' properties
//what I'm trying to accomplish
/*
if (this.foo.i.hasOwnProperty('someBoolean') && this.foo.i.someBoolean === true) {
this.totalNumber += this.foo.i.someNumber;
} //returns 'TypeError: Cannot read property 'hasOwnProperty' of undefined
*/
}
return this.totalNumber;
};
var myChild = new myConstructor('whatever');
myChild.getNumber();
What I'm trying to accomplish is using a constructor to create a child. The having nested objects inside that child, with various properties that I will change later in my code. Then using a method of the constructor to access data within the nested objects of that child. Everything works until I get two-deep in nested objects.
I've tried passing every variable, object and property around with various "var this == that"s and "var prop == i"s and etc. Nothing I do seems to work.
foo has no property named i.
You want foo[i], to get the property with that name.
it should be console.log(this.foo[i])
As foo doen not contain "i" property.
Your confusion lies in the way that for-each/for-in loops are normally used in other programming languages such as Java, C#. Here's the difference:
// java
for(int x in list)
x = x+1;
// javascript
var x;
for(x in list)
list[x] = list[x] + 1;
I have a problem of understanding how javascript works, and I can't find a correct explanation, perhaps you could help me.
Assuming the following code :
// aFunction references console.error
var aFunction = console.error;
// Assign a new property to aFunction
// As aFunction references console.error it will have the property too
aFunction.callCount = 0;
aFunction.hasOwnProperty("callCount"); //true
console.error.hasOwnProperty("callCount"); //true
// Overload console.error (why is not the purpose)
console.error = function() {}
console.dir(aFunction); //VM807:2 function log() { [native code] }
console.dir(console.error); //VM808:2 function () {}
Why aFunction still references the original console.error ?
Thanks in advance for your help.
When you set a variable to a reference to an object (a function, in this case), it gets a copy of that reference value. Subsequent changes to other variables or object properties that share that reference value won't have any effect on the copy you made.
It should be clear what's going on here, right?
var a = 2;
var b = a;
console.log(b); // 2
a = 3;
console.log(b); // still 2
Object references work the same way:
var a = { hello: "world" };
var b = a;
console.log(b.hello); // world
a = { hello: "goodbye" };
console.log(b.hello); // still world
Variable a got a new value, but that didn't affect b at all. The assignment operator = makes copies of values. There's no way to make one JavaScript variable (object property) be an alias for another.
This question already has answers here:
dynamically call local function in javascript
(5 answers)
Closed 8 years ago.
I'm having a difficulty calling a function inside of another function when its name is in a variable:
var obj = {}
obj.f = function() {
var inner = {
a: function() {
function b() {
alert('got it!');
}
b(); // WORKS AS EXPECTED
x = 'b';
[x](); // DOESN'T WORK, NEITHER this[x]() window[x](), etc.
}
}
inner.a();
}
obj.f();
I tried prefixing [x]() with different scope paths but so far w/o success. Searching existing answers did not turn up anything. It works with this[x]() if b() is placed directly inside object inner. I would like to keep b() as a function inside function a() because of variable scope in function a(), otherwise I would need to pass many parameters to b().
////
Re duplicate question: Quentin provided a more elegant answer in this thread imo.
There is no sensible way of accessing an arbitrary variable using a string matching the name of the variable. (For a very poor way to do so, see eval).
[x](); // DOESN'T WORK
You're trying to call an array as a function
NEITHER this[x]()
The function isn't a property of the inner object.
window[x](), etc.
Since it isn't a global, it isn't a property of the window object either.
If you need to call a function based on the value of a string variable, then organise your functions in an object and access them from that.
function b() {
alert('got it!');
}
var myFunctions = {
b: b
};
x = 'b';
myFunctions[x]();
Try this. Currently you are assigning string to variable x, instead of a function variable.
x = b;
x();
The problem is with your assignment
use x = b instead of x = 'b' to assign the function object as the latter just assigns the string into x.
Once you fix your assignment you can invoke the function as
x();
a.x();
a[x]();
etc.
You should make array for the function and then access using name in your variable as follow:
var obj = {}
obj.f = function() {
var inner = {
a: function() {
// set up the possible functions:
var myFuncs = {
b: function b() {alert('got it!');}
};
//b(); // WORKS AS EXPECTED --> commented this code
x = 'b';
myFuncs[x]();
}
}
inner.a();
}
The function declaration b will be captured in the closure of the anonymous function expression assigned as a.
When var is used in a closure, there is no (available in JavaScript) Object which gets assigned a property similar to what happens with window in the Global Scope.
Writing a function declaration effectively vars the name of the function.
If you really want to access a variable (i.e. b) by String, you will either need to create an Object which holds b similar to what you've done for a, or (and possibly dangerously) rely on an eval to convert "b" to b.
If you can't create the whole Object ahead-of-time, you can use this format
/* in (higher?) scope */
var fnRef = {};
// now when you
function b() {/* define as desired */}
// also keep a ref.
fnRef['b'] = b;
// fnRef['b']() will work **after this line**
let's say your code is like this:
//instead of x = 'b'
x = function(){}
then your solution could be like this:
var obj = {}
obj.f = function() {
var inner = {
a: function() {
function b() {
alert('got it!');
}
b(); // WORKS AS EXPECTED
//you can define it as a variable
var x = function(){};
//and call it like this
x();
//or define it like this
this[x] = function(){};
//and call it like this
this[x]();
//but you are creating an array [x] which is not a function
//and you are trying to call an array????
[x](); // DOESN'T WORK, NEITHER this[x]() window[x](), etc.
}
}
inner.a();
}
obj.f();
What is the difference between declaring a variable with this or var ?
var foo = 'bar'
or
this.foo = 'bar'
When do you use this and when var?
edit: is there a simple question i can ask my self when deciding if i want to use var or this
If it is global code (the code is not part of any function), then you are creating a property on the global object with the two snippets, since this in global code points to the global object.
The difference in this case is that when the var statement is used, that property cannot be deleted, for example:
var foo = 'bar';
delete foo; // false
typeof foo; // "string"
this.bar = 'baz';
delete bar; // true
typeof bar; "undefined"
(Note: The above snippet will behave differently in the Firebug console, since it runs code with eval, and the code executed in the Eval Code execution context permits the deletion of identifiers created with var, try it here)
If the code is part of a function you should know that the this keyword has nothing to do with the function scope, is a reserved word that is set implicitly, depending how a function is called, for example:
1 - When a function is called as a method (the function is invoked as member of an object):
obj.method(); // 'this' inside method will refer to obj
2 - A normal function call:
myFunction(); // 'this' inside the function will refer to the Global object
// or
(function () {})();
3 - When the new operator is used:
var obj = new Constructor(); // 'this' will refer to a newly created object.
And you can even set the this value explicitly, using the call and apply methods, for example:
function test () {
alert(this);
}
test.call("hello!"); //alerts hello!
You should know also that JavaScript has function scope only, and variables declared with the var statement will be reachable only within the same function or any inner functions defined below.
Edit: Looking the code you posted to the #David's answer, let me comment:
var test1 = 'test'; // two globals, with the difference I talk
this.test2 = 'test'; // about in the beginning of this answer
//...
function test4(){
var test5 = 'test in function with var'; // <-- test5 is locally scoped!!!
this.test6 = 'test in function with this'; // global property, see below
}
test4(); // <--- test4 will be called with `this` pointing to the global object
// see #2 above, a call to an identifier that is not an property of an
// object causes it
alert(typeof test5); // "undefined" since it's a local variable of `test4`
alert(test6); // "test in function with this"
You can't access the test5 variable outside the function because is locally scoped, and it exists only withing the scope of that function.
Edit: In response to your comment
For declaring variables I encourage you to always use var, it's what is made for.
The concept of the this value, will get useful when you start working with constructor functions, objects and methods.
If you use var, the variable is scoped to the current function.
If you use this, then you are assigning a value to a property on whatever this is (which is either the object the method is being called on or (if the new keyword has been used) the object being created.
You use var when you want to define a simple local variable as you would in a typical function:-
function doAdd(a, b)
{
var c = a + b;
return c;
}
var result = doAdd(a, b);
alert(result);
However this has special meaning when call is used on a function.
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
doAdd.call(o, a, b);
alert(o.c);
You note the first parameter when using call on doAdd is the object created before. Inside that execution of doAdd this will refer to that object. Hence it creates a c property on the object.
Typically though a function is assigned to a property of an object like this:-
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
o.doAdd = doAdd;
Now the function can be execute using the . notation:-
o.doAdd(a, b);
alert(o.c);
Effectively o.doAdd(a, b) is o.doAdd.call(o, a, b)
var foo = 'bar'
This will scope the foo variable to the function wrapping it, or the global scope.
this.foo = 'bar'
This will scope the foo variable to the this object, it exactly like doing this:
window.foo = 'bar';
or
someObj.foo = 'bar';
The second part of your question seems to be what is the this object, and that is something that is determined by what context the function is running in. You can change what this is by using the apply method that all functions have. You can also make the default of the this variable an object other than the global object, by:
someObj.foo = function(){
// 'this' is 'someObj'
};
or
function someObj(x){
this.x=x;
}
someObj.prototype.getX = function(){
return this.x;
}
var myX = (new someObj(1)).getX(); // myX == 1
In a constructor, you can use var to simulate private members and this to simulate public members:
function Obj() {
this.pub = 'public';
var priv = 'private';
}
var o = new Obj();
o.pub; // 'public'
o.priv; // error
Example for this and var explained below:
function Car() {
this.speed = 0;
var speedUp = function() {
var speed = 10; // default
this.speed = this.speed + speed; // see how this and var are used
};
speedUp();
}
var foo = 'bar'; // 'var can be only used inside a function
and
this.foo = 'bar' // 'this' can be used globally inside an object