argumental reference inconsistency in javascript - javascript

I have recently encountered a nasty issue in JS.
Let say we pass a map, an array of objects to a function f.
var o=[{a:0}];
function f(a){
for(var i in a){
if (a.hasOwnProperty(i)){
a[i]=null;
}
}
return a;
};
var outp=f(o);
alert(outp[0]+" === "+o[0]+" : "+(outp[0]===o[0]));
// here we expect loose equality, and equality in type,
//furthermore it should identically equal as well, and we got right!
But, we can not pass total responsibility of an object to a function as argument, same like in functional paradigm o=(function(o){return o})(), because any kind of modification to o is not referenced!
var o=[];
function ff(a){
return (a=undefined);
};
var outp=ff(o);
alert(outp+" === "+o.constructor+" : "+(outp===o));
// here we expect true, but we got false!
Why is the above described reference loss and
presumably different referencce handling in the second use case,
though in both case, functions got the array argument in the 0. position?

Javascript always passes arguments by value, so this won't work:
function foo(x) {
x = 100;
}
y = 5
foo(y)
y == 100 // nope
However this does work:
function foo(x) {
x.bar = 100;
}
y = {}
foo(y)
y.bar == 100 // yes
In the second snippet x is still passed by value, but this very value is a reference (pointer) to an object. So it's possible in a function to dereference it and access what's "inside" the object.

Related

How to extend Number in TypeScript by adding a function similar to ++

I would like to extend Number with a plusPlus2 function that will increment the number by 2.
The problem is that I don't know how to assign the result back to the number in the extension function. Something like:
Number.prototype.plusPlus2 = function() {
this = this + 2;
}
And the usage would be:
x = 1;
x.plusPlus2(); // expect x to be 3
Primitives (numbers, strings, booleans) are immutable in javascript.
So anytime you change a primitive, you need to assign it to another variable (or even reassign it to itself).
That being said, you cannot do what you propose, you need to return a new value, containing the value you want, let's say:
Number.prototype.plusplus2 = function() {
return this + 2;
}
And then reassign it:
let x = 5;
x = x.plusplus2();
Then, you may be wondering: how x++ works?
And the answer is, x++ is a syntax sugar for x = x + 1, meaning that, in fact, you are not changing x, but instead, adding 1 to x and reassigning it to itself.
You cannot. That has various reasons:
1) this is read only, as you don't expect it to change during the execution of a method.
2) What you access with this is a Number object that wraps the primitive number. It gets thrown away after the call. So even if you could change the internal value property containing the number, the value of x won't change.
Number.prototype.example = function() { this.stuff = "you see" };
let x = 1; // primitive
x.example(); // wrapped object
// wrapped object gets thrown away
console.log(x.stuff); // undefined, another wrapped object
3) Numbers are immutable and primitive. You can write a new number into x, but you can't turn all 1s into 3s.
You could create a new number, but then you have the problem that you have to write that number into x.
Number.prototype.plus2 = function() { return this + 2 };
let x = 1;
x = x.plus2();
Number.prototype.plus2 = function() {
return this + 2
}
let a = 2
console.log(a.plus2())

Modifying variables that are passed by reference in Javascript

I was watching a JavaScript talk, and the tutor said that if we pass a property of an object in a function it will actually change the real value, because we will be passing the variable by reference. Here is the slide:
but when I tried to practice the concept, that wasn't the case. Here is my code:
var obj = {val: 5};
function changeVal(x) {
x = x+5;
return x;
}
console.log(obj.val) // 5
console.log(changeVal(obj.val)) // 10
console.log(obj.val) // 5
I was expecting obj.val to change to 10.
Please tell me what's wrong here, and correct me if I am wrong. Thanks
You are passing not the object, but the primitive type. So when you pass the val of the obj, it is a number and is a primitive type.It copies the val and passes the copy to the object.
If you pass like this, it will work
var obj = {val: 5};
function changeVal( param ) {
param.val = param.val + 5;
return param.val ;
}
console.log(obj.val) // 5
console.log(changeVal(obj)) // 10
console.log(obj.val) // 10
You are not actually passing an object, just passing the value of property(val).
If you will pass obj in changeVal(), then it will actually change the value of the property of passed object.
For that you need to do like:
var obj = {val: 5};
function changeVal(x)
{
x = x+5;
return x;
}
console.log(obj.val); // 5
changeVal(obj); // Need to pass object instead of value of the property's value
console.log(obj.val); // 10
Primitive types (string, integer, boolean, etc...) are immutable, which means if you change one of the values inside a function, the callee (scope which calls your function) will not see the change.
function doSomething(a) {
a = a + 1;
}
var value = 2;
console.log(value); // result: 2
doSomething(value);
console.log(value); // result: 2
Pass-by-reference only works for objects. Like this:
function doSomething(obj) {
obj.attribute = obj.attribute + 1;
}
var myObject = {attribute: 2};
console.log(myObject.attribute); // result: 2
doSomething(myObject);
console.log(myObject.attribute); // result: 3
More reading about Javascript types:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures
Say for instance you have an Iphone . Now lets say a manufacturing company calls you and asks to borrow your Iphone for a reference just so they can design an Iphone that is similar and sell it to customers . Your original Iphone still exists and is never gone , but every now and then the factory needs to use it for a reference , think of your function as the factory that just make a copy of obj.
//Original data
var obj = {val: 5};
Once your function returns something , it technically becomes a value
Example :
return 3; is a value of 3
so
function changeVal(x) {
x = x+5;
return x;
}
is a new value of x which in this case would be x + 5;
x is a copy of whatever you pass into the function .
Hope this helps.

What is the difference in these two examples about JavaScript scope chain?

var a = 1;
function x() {
a = 2
console.log(a) // 2
}
x();
console.log(a); // 2
and :
var a = 1;
function x(p) {
p = 2
console.log(p) // 2
}
x(a);
console.log(a); // 1
Why is the output of the second example 1 instead of 2?
It's because your p variable exists only inside function x(p). So, you have a new space in memory, a copy variable a. In the first example, it's a pointer to memory address of variable a.
In other hand, objects have a "pass by reference", so if you do this:
var obj = { foo: 1 };
function x(paramObj) {
paramObj.foo = "2";
}
x(obj);
alert(obj.foo);
You will see "2" instead of "1".
Because function arguments are 'created' when the function gets executed.
var a = 1;
function x(p) {
p = 2
console.log(p) // 2
};
In this piece of code you create global variable a = 1; Then you pass it to the x function. Inside the function you set the given parameter to 2 and console.log it; But what really happens is this:
var a = 1;
function x(given_argument) {
var p = given_argument;
p = 2; // global a variable still equals 1;
console.log(p) // 2
};
This is because there are 2 types of variables in Javascript. Values like number, string, boolean etc that are just values and referential types like arrays, objects.
If you know C++ then this should lighten things up a bit. Here is equivalent of what happens in Javascript, written in C++:
// javascript
var a = 1; // plain value
// c++
int a = 1; // plain value
// javascript
var a = {}; // referential type, this is a pointer behind the scenes
// or
var a = new Object(); // if you prefer it this way
// c++
Object* a = new Object(); // this is a pointer to the object, but in C++ you make it a pointer explicitly, in Javascript this happens 'automagically'.
Referential types in Javascript are pointers, it means they can be changed from inside function, if passed as arguments. But if you pass normal value like number or boolean, it is declared inside the function, and it happens implicitly.
I hope it clarified the problem.

Understanding d3.js source: stuck at function.call() and "=+"

In the source code of d3.layout.force, line 158, there is this code
force.charge = function(x) {
if (!arguments.length) return charge;
charge = typeof x === "function" ? x : +x;
return force;
};
Now, if you go to line 225, you will see
charges = [];
if (typeof charge === "function") {
for (i = 0; i < n; ++i) {
charges[i] = +charge.call(this, nodes[i], i);
}
} else {
for (i = 0; i < n; ++i) {
charges[i] = charge;
}
}
What I did not understand here is the line
charges[i] = +charge.call(this, nodes[i], i);
I am new to JavaScript and can not understand what's going on here.
As far as I understood charge takes only 1 argument (x). Here "this" is passed to give the context of current object but what about the other two? Which one of "nodes[i]" and "i" is taken as "x" ?
Again what is "= +" doing here?
Check out the MDN listings for call, apply and bind.
It's a tough concept to wrap your head around but what's happening in call and apply is that you're choosing to execute a function in a different "context."
I say "context" with quotes as "execution context" has an exact meaning in JS and this isn't it. I don't have a great word for it but what's happening here is that you're making swapping out the this object when executing the function.
This might help:
var obj = { foo: "bar" };
method.call( obj, "arg" );
function method( arg ) {
console.log( this.foo ); #bar
console.log( arg ); #"arg"
}
I think you'll find your answer here.
Basically, it's converting this:
function(){ return +new Date; }
into this:
function(){ return Number(new Date); }
Essentially, it is converting the argument into a number, and adding it to the previous value.
More reading about this here
You have to follow charge more carefully. It is variable defined in line 11:
charge = -30,
The function force.charge which you quoted is for setting the charge, it is not the function referred to in +charge.call(this, nodes[i], i);. Have a look at the second line of force.charge:
charge = typeof x === "function" ? x : +x;
x can be a function (callback) you pass, to dynamically calculate the charge. The current node (nodes[i]) and the index of the node (i) will be passed to this callback, so that you can calculate the charge dynamically based on these values:
force.charge(function(node, index) {
return index * 2;
});
x (and therefore charge) can also be a number or numerical string. That's why it is tested beforehand whether charge is a function or not:
if (typeof charge === "function") {
// function so we call it and pass the current node and index
} else {
// static value, the same for each node
}
Apert from that, you can always pass any number of arguments to a function, no matter how many parameters it has defined. For example:
function foo() {
alert([].join.call(null, arguments));
}
foo('a', 'b');
will alert a,b.
To answer your questions: The arguments passed to .call() [MDN] or .apply() [MDN] are passed in the same order to the function. So if I have a function function foo(a, b, c) then foo.call(null, x, y) would pass x as a and y as b (c would be undefined).
The + operator is the unary plus operator [MDN], which simply converts the operand into a number.

javascript arguments for beginner

Why the following code does not increase the variable a for 1 ?
var a =5;
function abc(y){
y++;
}
abc(a);
//a is 5 not 6 why?
but this does
var a = 5;
function abc(){
a++;
}
abc();
//a is 6
Because primitive values are passed by value in JavaScript.
To get the value to be updated, you could put a on an object and take advantage of the fact that objects are passed by reference (well, mostly, really a copy of the reference is passed, but we won't worry about that):
var obj = { a: 5 };
function abc(o){
o.a++;
}
abc(obj);
it takes the argument, but doesn't return any values.
y is just an argument for this I suggest two ways to do this
var a = 10
function increase(){
a++
}
increase();
var a = 10;
function increase(a){
return a++;
}
a = increase(a);
For a beginner's sake,
In simple words, when you call function by abc(a), 'a' is not passed to function abc but its value is copied to 'y'. (Its called pass by value). Since only 'y' in increased, you dont see an updated value of 'a'.

Categories

Resources