variable within a object not updating in javascript - javascript

I have an object which is initialized like
var x = function(){
var result = 5,
clear = function(){
result = 0;
};
return {
result: result,
clear: clear
}
}
I am later creating a new instance of x using var y = new x();
but when i try setting the value y.result = 5; and want to clear the result value to 0 I call y.clear();
However it is not resetting the y.result to 0... Not sure why?
Anything that i am doing wrong?

Within your function:
var x = function(){
var result = 5,
clear = function(){
result = 0;
The identifier result in this function has a closure to the variable result in the outer function (i.e. outer execution context).
};
return {
result: result,
That assigns the value of the variable named result to the object property named result.
clear: clear
}
}
So later when you call y.clear() you are setting the value of the variable held in the closure, which does not update the object property named result.
If you want x to be a constructor, then:
function X() {
this.result = 5;
this.clear = function() {
this.result = 0;
}
}
So now:
var y = new X();
y.clear();
console.log(y.result); // 0
Note that it is convention for constructors to have a name starting with a capital letter. You can learn more about how to use the new operator on MDN.
To leverage ECMAScript inheritance, put the clear function on the constructor's prototype so that all instances inherit the one method, rather than each having its own:
function X() {
this.result = 5;
}
X.prototype.clear = function() {
this.result = 0;
}

The problem is that numbers are referenced by value. Assigning value to result variable from clear function won't change value of result on new x instance.
There are several ways to go about this:
Store data on this, then modify it there inside constructor and method, I find it easier to understand and more readable. This is probably what you wanted to begin with:
function x () {
this.result = 5;
}
x.prototype.clear = function () {
this.result = 0;
}
var z = new x();
// z.result === 5
z.clear()
// z.result === 0;
Define getter and setter on returned object, so instance result would return\set closured variable:
function x () {
var result = 5;
function clear () {
result = 0;
}
var out = {
clear: clear
};
Object.defineProperty(out, "result", {
get: function () {
return result;
},
set: function (value) {
result = value;
}
});
return out;
}
var z = new x();
// z.result === 5
z.clear()
// z.result === 0;
z.result = 10
// z.result === 10;
z.clear()
// z.result === 0;

Related

How do I call a JavaScript method based on a variable value?

I have method a(), method b(), and method c(). I will get a response message from server, which contains a or b or c and so on.
If the response message is a, then I need to call method a().
If the response message is b, then I need to call method b()
And so on...
I don't want to write any if else conditions or switch case to identify the method.
I don't want to do this:
if(res == 'a')
a();
else if(res == 'b')
b();
Instead of that I need something like reflections in Java.
If you have defined the function in Global/window Scope then you can directly use res variable
window[res]();
Otherwise define the function in object and then use it
var obj = {
a : function(){},
b : function(){}
}
obj[res]();
You could use an object and store the function inside, like
var functions = {
a: function () {},
b: function () {},
c: function () {}
default: function () {} // fall back
}
Usage:
functions[res]();
Or with default
(functions[res] || functions.default)();
For this purpose you can define a class that allows you to define and call methods, and determine the calling context:
var MethodsWorker = function () {
this._context = window;
this._methods = {};
}
MethodsWorker.prototype.setContext = function (context) {
this._context = context;
}
MethodsWorker.prototype.defineMethod = function (name, method) {
this._methods[name] = method;
};
MethodsWorker.prototype.invoke = function (methodName, args) {
var method = this._methods[methodName];
if (!method) { throw {}; }
return method.apply(this._context, args);
};
Usage:
var methodsWorker = new MethodsWorker ();
methodsWorker.setContext(Math);
methodsWorker.defineMethod('sqrtOfSum', function() {
var sum = 0;
for (var i = 0, n = arguments.length; i < n; i++) {
sum += arguments[i];
}
return this.sqrt(sum);
});
var result = methodsWorker.invoke('sqrtOfSum', [1, 2, 3]);
alert (result);

clear and undo clear the array

If I do have the following code then empty the arry:
var a1 = [1,2,3];
a1 = [];
//returns []
But I'm trying to make a function to clear and undo clear the array, it's not working as expected:
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a;
a = [];
}
function undoClearArray(a){
a = storeArray;
}
clearArray(foo);
foo; //still returns ['f','o','o']
//but expected result is: []
Here's the problem:
You assign an array to a variable foo.
Then you pass this object to your function which stores it in another variable a. Now you have one object that two variable are pointing at. In the function you then reassign a to a different object an empty array []. Now a points at the empty object and foo still points at the original object. You didn't change foo by reassigning a.
Here's a concise way to store you're array:
var storeArray = [];
function clearArray(a){
while (a.length>0){
storeArray.push(a.shift()) //now a is empty and storeArray has a copy
}
}
I tried something different. Maybe it's dirty, but the storage itself is on the object.
the fiddle
//define the object to hold the old data
Object.defineProperty(Array.prototype, "storage", {
enumerable: false,
configureable: true,
get: function () {
return bValue;
},
set: function (newValue) {
bValue = newValue;
}
});
//define the prototype function clear to clear the data
Object.defineProperty(Array.prototype, "clear", {
enumerable: false,
writable: false,
value: function () {
this.storage = this.slice(0); //copy the data to the storage
for (var p in this) {
if (this.hasOwnProperty(p)) {
delete this[p]; //delete the data
}
}
return this; //return the object if you want assign the return value
}
});
//define the prototype function restore to reload the data
Object.defineProperty(Array.prototype, "restore", {
enumerable: false,
writable: false,
value: function () {
var a = this.storage.slice(0); //copy the storage to a local var
for (var p in this.storage) {
if (this.storage.hasOwnProperty(p)) {
this[p] = a[p]; //assign the pointer to the new variable
delete this.storage[p]; //delete the storage
}
}
return this;
}
});
var a = ['f','o','o'];
console.log(a); //--> displays ['f','o','o']
a.clear();
console.log(a); //--> displays []
a.restore();
console.log(a); //--> displays ['f','o','o']
You can use splice() method to delete all elements of an array likes below
function clearArray(a){
storeArray = a;
a.splice(0,a.length);
}
var a = [1,2,3,4];
var tempArr ;
clearArray = function() {
tempArr = a.slice(0);
a.length = 0;
}
undoArray = function() {
a = tempArr.slice(0);
}
Here is a small jsfiddle: http://jsfiddle.net/66s2N/
Here's working way of what you want to achieve:
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a.slice(0);
for (var i=0; i<a.length; i++)
delete a[i];
a.length = 0;
}
function undoClearArray(a){
for (var i=0; i<storeArray.length; i++)
a.push(storeArray[i]);
}
console.log(foo);
clearArray(foo);
console.log(foo); //now foo is []
undoClearArray(foo);
console.log(foo); // now foo is ['f','o','o']
http://jsfiddle.net/44EF5/1/
When you do:
var a1 = [1,2,3];
a1 = [];
it's as if you've written:
var a1 = [1,2,3];
var a1 = [];
You're overwriting variables.
Now, why your approach doesn't work - in JS there's no passing by reference. MarkM response explains what's happening within the function.
Now, why does the above work - while you've got two variables pointing towards the same array, nothing prevents you from modifying that array. As such storeArray = a.slice(0) will create a copy of the array. Then by using delete we're removing all values of the array, and then as length isn't enumerable (so using for (var i in a) wouldn't help) we reassign the length of the array. This has removed the values of original array, while creating a new array assigned to storeArray.
function clearArray(a){
storeArray = a.slice(0);
return a.length = 0;
}
or set foo.length = 0;
Just update your both function with below ones
function clearArray(a){
storeArray = a.slice(0);
a.length = 0;
}
function undoClearArray(a){
a = storeArray;
return a;
}
in undoClearAray() we are returning the variable which have new reference(in your clearArray(), Both the original and new array refer to the same object. If a referenced object changes, the changes are visible to both the new and original arrays). so use it as foo=undoClearArray(foo); for old values.
try
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a;
a = [];
return a;
}
function undoClearArray(a){
a = storeArray;
}
foo = clearArray(foo);
foo; //returns []
You can use wrappers to do this quite nicely. First create a wrapper function with the additional methods defined, then create your array using that function instead of []. Here is an example (see JSFiddle):
var extendedArray = function() {
var arr = [];
arr.push.apply(arr, arguments);
arr.clearArray = function() {
this.oldValue = this.slice(0);
this.length = 0;
}
arr.undoArray = function() {
this.length = 0;
for (var i = 0; i < this.oldValue.length; i++) {
this.push(this.oldValue[i]);
}
}
return arr;
};
var a = extendedArray('f', 'o', 'o');
alert(a);
a.clearArray();
alert(a);
a.undoArray();
alert(a);

Am I understanding JavaScript closures properly?

Variables created inside a function, cannot be accessed outside the function.
For example in:
function haha()
{
var a = 5;
}
a cannot be accessed outside haha().
And that is where a closure comes in handy:
function haha()
{
var a = 5;
return function hahainside(){ }
}
newfunction = hahainside();
Now, if I call newfunction(), it can access the "a" variable inside the haha().
Am I correct?
I am also wondering why:
<script>
function exclusive()
{
d = "Robert, Ryo, Yuri";
function returnfunction() { alert( d ); }
return returnfunction();
}
ryo = exclusive();
alert(7);
</script>
I am also just wondering why alert(7); does not display on my browser.
Here's what you need to know:
var a = 0;
function haha(){
a = 5; // when calling haha `a` is accessible to everything below where var is declared
return function(){
a = 10; // same as notes above
}
}
var newfunc = haha(); // `a` will become 5 where var is declared
newfunc(); // now `a` is 10 where var is declared
console.log(a); // works
Without having var a declared outside of haha:
function haha(){
var a = 5; // only available in `haha`
return function(){
a = 10; // nearly useless - only scoped to `haha`
}
}
var newfunc = haha(); // `a` will become 5 where var is declared
newfunc(); // now `a` is 10 where var is declared - can't access `a` where `newfunc` is called
console.log(a); // undefined
Maybe you want a Constructor:
function haha(arg){
var whatever = 'something'; // never accessible in a new instance from outside
this.a = arg;
this.hahaInside = function(val){
this.a = val;
}
}
var newfunc = new haha(20); // `newfunc.a` is now `20`
newfunc.a = 12; // `newfunc.a` is now `12`
newfunc.hahaInside(10); // newfunc.a is now 10
As an Object:
var haha = {
a: 5,
hahaInside: function(val){
this.a = val;
}
}
No private variables in an Object, and no Constructor arguments. You don't have to call a new instance as an Object, but you may want an new instance. To avoid writing the keyword this:
if(!Object.create){
Object.create = function(o){
function F(){}
F.prototype = o;
return new F;
}
}
var newfunc = Object.create(haha); // new 'newfunc` is a new instance of `haha`
Real use, no closure:
// assuming 3 radio buttons
var ary = ['a', 'b', 'c'], radioButtons = document.getElementsByName('radButs');
var resultVar = '';
for(var i=0,l=radioButtons.length; i<l; i++){
radioButtons[i].onclick = function(){
resultVar = ary[i];
}
}
// resultVar will always be `'c'` because by the time the click Event is called the loop has run all the through and the scope of `i` is global
A closure prevents a variable from being scoped higher. Global in this case:
// assuming 3 radio buttons
var ary = ['a', 'b', 'c'], radioButtons = document.getElementsByName('radButs');
var resultVar = '';
for(var i=0,l=radioButtons.length; i<l; i++){
(function(i){
radioButtons[i].onclick = function(){
resultVar = ary[i];
}
})(i);
}
// now `resultVar` will be `'a'`, `'b'`, or `'c'` respectively, depending on the radio button that you clicked because `i` becomes separately scoped at each step of the loop even by the time the click Event is called due to user action
You can also use use a closure to create a pseudo-static function like this:
var count = (function(){
var c = 0;
return function(){
return c++;
}
})();
Now every time you call count() it will do just that. The reason this works is because the self-executing function is invoked immediately, scoping var c within it, and returning an unexecuted function that increases c where it was last scoped.

Array values transfer between 2 functions

I try to read an array using a function and use it in another function, however the second function does not seem to read it. What I am doing wrong?
function calcDet () {
var A = []; //generates the array
for (var i = 0; i < k; i++) {
A[i] = [];
for (var j = 0; j < k; j++) {
var id = "A" + (i + 1) + (j + 1);
A[i][j] = parseFloat(document.getElementById(id).value);
}
}
alert (A);
return (A);
}
function calcRec() {
var s;
var det;
alert (A)
}
firstly your array is not declared outside the function. its scope is limited to function body. but as your function returns the array back then try using it for initializing your local variable in other array. also this will work.
or
try declaring it outside the functions
Frist way is
function function1()
{
var valriable1=12;
function2(val);
}
function function2(val)
{
var variableoffunction1 = val;
}
Second way is
var globalvarialbe;
function function1()
{
globalvarialbe=12;
function2();
}
function function2()
{
var local = globalvarialbe;
}
It's because JavaScript has a "functional scope". It means that whatever is declared inside the function cannot be seen by the outside, but what's outside can be seen from the inside.
In your case, you must declare the array outside the function.
var A = []
function calcDet(){...}
function calcRec(){
alert(A);
}
or call the function and return A
function calcDet(){
var A = [];
...
return A;
}
function calcRec(){
var A = calcDet(); //get A from calcDet
alert(A);
}
You can't because you are declaring A locally in calcDet
One way is to declare A outside the function, or simply feed it into calcRec:
var A
function calcDet() {
// code
}
function calcRec() {
// code
}
or (better)
function calcRec() {
var s;
var det;
alert (calcDet())
}
See this link about scope.
The A variable, being declared inside of the function, is only scoped to that function. It will die after the function dies. You need to pass it as a parameter:
function calcRec(data) {
var s;
var det;
alert (data)
}
A = calcDet();
calcRec(A);

Set length property of JavaScript object

Let's say I have a JavaScript object:
function a(){
var A = [];
this.length = function(){
return A.length;
};
this.add = function(x){
A.push(x);
};
this.remove = function(){
return A.pop();
};
};
I can use it like so:
var x = new a();
x.add(3);
x.add(4);
alert(x.length()); // 2
alert(x.remove()); // 4
alert(x.length()); // 1
I was trying to make .length not a function, so I could access it like this: x.length, but I've had no luck in getting this to work.
I tried this, but it outputs 0, because that's the length of A at the time:
function a(){
var A = [];
this.length = A.length;
//rest of the function...
};
I also tried this, and it also outputs 0:
function a(){
var A = [];
this.length = function(){
return A.length;
}();
//rest of the function...
};
How do I get x.length to output the correct length of the array inside in the object?
You could use the valueOf hack:
this.length = {
'valueOf': function (){
return A.length;
},
'toString': function (){
return A.length;
}
};
Now you can access the length as x.length. (Although, maybe it's just me, but to me, something about this method feels very roundabout, and it's easy enough to go with a sturdier solution and, for example, update the length property after every modification.)
If you want A to stay 'private', you need to update the public length property on every operation which modifies A's length so that you don't need a method which checks when asked. I would do so via 'private' method.
Code:
var a = function(){
var instance, A, updateLength;
instance = this;
A = [];
this.length = 0;
updateLength = function()
{
instance.length = A.length;
}
this.add = function(x){
A.push(x);
updateLength();
};
this.remove = function(){
var popped = A.pop();
updateLength();
return popped;
};
};
Demo:
http://jsfiddle.net/JAAulde/VT4bb/
Because when you call a.length, you're returning a function. In order to return the output you have to actually invoke the function, i.e.: a.length().
As an aside, if you don't want to have the length property be a function but the actual value, you will need to modify your object to return the property.
function a() {
var A = [];
this.length = 0;
this.add = function(x) {
A.push(x);
this.length = A.length;
};
this.remove = function() {
var removed = A.pop();
this.length = A.length;
return removed;
};
};
While what everyone has said is true about ES3, that length must be a function (otherwise it's value will remain static, unless you hack it to be otherwise), you can have what you want in ES5 (try this in chrome for example):
function a(){
var A = [],
newA = {
get length(){ return A.length;}
};
newA.add = function(x){
A.push(x);
};
newA.remove = function(){
return A.pop();
};
return newA;
}
var x = a();
x.add(3);
x.add(4);
alert(x.length); // 2
alert(x.remove()); // 4
alert(x.length); // 1
You should probably use Object.create instead of the function a, although I've left it as a function to look like your original.
I don't think you can access it as a variable as a variable to my knoledge cannot return the value of a method, unless you will hijack the array object and start hacking in an update of your variable when the push/pop methods are called (ugly!). In order to make your method version work I think you should do the following:
function a(){
this.A = [];
this.length = function(){
return this.A.length;
};
this.add = function(x){
this.A.push(x);
};
this.remove = function(){
return this.A.pop();
};
};
These days you can use defineProperty:
let x = {}
Object.defineProperty(x, 'length', {
get() {
return Object.keys(this).length
},
})
x.length // 0
x.foo = 'bar'
x.length // 1
Or in your specific case:
Object.defineProperty(x, 'length', {
get() {
return A.length
}
})
function a(){
this.A = [];
this.length = function(){
return this.A.length;
};
this.add = function(x){
this.A.push(x);
};
this.remove = function(){
return this.A.pop();
};
};

Categories

Resources