I'm creating an object with multiple functions.. i.e.:
var test = {
setA: function(){
console.log(a)
}
endB: function(){
console.log(a)
}
}
How do I declare variable a so that it can only be accessed in the test object and every function within that the object? and is there anything unique about accessing it than other variables?
I know I can declare a global variable but would rather avoid doing that.
var test = (function() {
var a = 'test';
return {
setA: function(){ console.log(a) }, // <-- was missing a comma
endB: function(){ console.log(a) }
};
})();
This places a in a function invocation which creates a new variable environment. Only function inside this environment will be able to access it.
Your object that contains the functions is returned from the function, and assigned to test. Those two functions will continue to have access to a.
Example: http://jsfiddle.net/yWdFw/
This pattern:
(function() {
// your code
})();
...is commonly called an immediately invoked function expression or IIFE. You're defining a function, and invoking it immediately. As such, its return value is what's being assigned to test.
An alternative to patrick's answer is adding an attribute to the object and then accessing it via this
var test = {
a: 'blah',
setA: function(){
console.log(this.a)
},
endB: function(){
console.log(this.a)
}
}
Related
I have a function that returns a variable and a function which edit the variable value.
But it's not working and I don't know why.
And what is the correct way to do this?
Here is my code:
function t(){
var test = 1;
var changeTest = function(){
test++;
}
return {
changeTest:changeTest,
test:test
}
}
var b = t();
b.changeTest();
console.log(b.test) // the value is 1 not 2
The value of test is a primitive and so it is indeed not a reference.
A solution: make the exposed test property a getter, so that the value of the private test variable is retrieved at the moment the property is accessed:
return {
changeTest:changeTest,
get test() { return test }
}
function t(){
var test = 1;
var changeTest = function(){
test++;
}
return {
changeTest,
get test() { return test }
}
}
var b = t();
b.changeTest();
console.log(b.test);
With this pattern, the test variable remains private, and you only expose the features you want to. So in this case you allow explicitly to read the test value, but not to write it.
NB: you can shorten the object literal notation to just:
return {
changeTest,
get test() { return test }
}
In changeTest you have to use this.test instead of test.
function t(){
var test = 1;
var changeTest = function(){
this.test++;
}
return {
changeTest:changeTest,
test:test
}
}
var b = t();
b.changeTest();
console.log(b.test) // the value is 1 not 2
If you would like to increase inside of the function, you need to use this keyword inside, just like the following:
function t(){
const changeTest = function() { this.test++; };
return { changeTest, test: 1 };
}
const b = t();
console.log('original value', b.test);
b.changeTest();
console.log('increased value', b.test);
The reason is why it is happening because you are not modifying the value inside, it is called lexical closure what you face with, as the documentations states:
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.
Using the this keyword the code accesses the proper test variable.
For further explanation please read further here:
Closures: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
I hope this helps!
I decided to create a funcB function that I call from funcA. I want all variables from funcA to be available in the funcB so func B can change that variables.
How to modify the code below so it meets my requirements? I doubt passing all variables it the only possible and the best way.
function funcB(){
alert(var1);//how to make it alert 5
alert(var20);//how to make it alert 50
}
function funcA(){
var var1=5;
...
var var20=50;
funcB();
}
var obj = {
one : "A",
two : "B",
fnA : function() {
this.fnB(); // without fnB method result will be displayed as A B, with fnB as C D
console.log(this.one + " " + this.two);
},
fnB : function() {
this.one = "C";
this.two = "D";
}
};
obj.fnA();
this keyword refers to obj object
You can define object with properties and methods inside it. With methods all the variables can be manipulated as you wish, from this example with fnB I'm changing values of properties which are displayed from fnA method
JSFiddle
One way is to drop the var keyword:
function funcB(){
alert(var1);//how to make it alert 5
alert(var20);//how to make it alert 50
}
function funcA(){
var1 = 5;
var20 = 50;
funcB();
}
This will expose them to the global scope so funcB can access them. Notice you can also create the varaibles in the global scope itself, with the var keyword, but both methods will ultimately have the same effect.
Note:
This may not work if there is already a var1 or var20 in the global scope. In such case, it will modify the global value and may result in unwanted errors.
This method is not preferred for official code, and is bad practice Reason
This is not possible as when you declare a variable with the var keyword, they are scoped to the function in which they are declared.
If you avoid the var keyword, they are instead defined as a global variable. This is deemed very bad practice.
I would recommend you read up on javascript coding patterns, particularly the module pattern.
For example:
var myNamespace = (function () {
var foo, bar;
return {
func1: function() {
foo = "baz";
console.log(foo);
},
func2: function (input) {
foo = input;
console.log(foo);
}
};
})();
Usage:
myNamespace.func1();
// "baz"
myNamespace.func2("hello");
// "hello"
I have tried folllowing two ways of referring a function:
First
let a = function() {
somefunction();
}
Second
let a = somefunction;
Where somefunction is the following in both cases:
function somefunction() {
alert("hello");
}
Is there any difference between these two ways?
Yes, there is a difference between your two examples.
In the first case, you are defining a new anonymous (unnamed) function which calls somefunction. You are then assigning your new function definition to the variable a. a holds a reference to your new function.
In the second case, you are simply assigning your original function of somefunction to the variable a. The variable a then holds a reference to somefunction. You are not creating a new function as you are in the first case.
I think this example may make the difference clear. arguments is an array like object that contains each of the arguments passed to a function.
Try running each of these lines on your favorite browser console.
var somefunction = function() { console.log(arguments); };
Your first example demonstrates defining a named function a that closes around the named function somefunction.
var a = function() { somefunction(); };
Your second example makes a reference, b, directly to somefunction. This makes invoking b the same as invoking somefunction.
var b = somefunction;
Now if you call each of these a and b with some arguments you will see the difference.
=> a('a', 1);
[]
=> b('a', 1);
['a', 1]
In the first case the arguments object is empty. That's because the arguments that were passed to a were not forwarded onto somefunction.
In the second case the arguments are available to somefunction, because some function is being called directly.
Here is how you could redefine a so that it were functionally equivalent using apply
var a = function() { somefunction.apply(this, arguments); }
Running this at your console prints the argument array.
=> a('a', 1);
['a', 1]
var a = function(){
somefunction();
}
Is an Anonymous Function attributed to a variable.
somefunction :function() {
alert("hello");
}
Is an declaration of a function throungh the Object Literal notation.
The diference are shown when you are creating an object. The anonymous function are not acessible as a "public" method, instead in the Object Literal notation, that are acessible from outside.
As Douglas Crockford said, in JS the Good Parts, the first declaration are just a function and the second one could be a method.
In the first case, you are creating a function which calls someFunction(), then you assign that function to a, so now calling a() calls an anonymous function which in turn calls someFunction().
In the second case, a and someFunction become the exact same thing, calling a() is the same as calling someFunction().
The way you're setting var a by accessing the function is clearly out of scope.
So I suspect you have a typo : instead of = :
var somefunction = function() {
alert("hello");
};
somefunction(); // hello
...Now that your first and second makes sense with the code above:
Anonymous Function stored in variable:
var a = function(){
alert('Hey');
somefunction();
};
a(); // Hey // hello
Variable as Function Reference
var a = somefunction;
a(); // hello
In the other case than:
var objLiteral = {
somefunction : function() {
alert("hello");
}
};
var a = objLiteral.somefunction;
a(); // hello
I'm fairly new to javascript objects and I could use some clarification on calling variables. I'm trying to call the test variable in the bar function. Is this possible? If so how would I do it correctly?
var foo = {
bar: function()
{
var test = 'Hello World';
},
speak: function()
{
// Log the Variable from above ^^
console.log(foo.bar.test);
}
};
Thanks
No; local variables are not visible outside their declaring functions.
Instead, you need to add a property to the object:
foo.test = ...;
You could also set foo.bar.test; that would add a property to the function object.
When you declare a local variable inside the function, you add it to the VariableEnvironment of the functions (which essentially has no difference from the outer LexicalEnvironment, but the ECMA distinguishes them). The function has a reference to the LexicalEnvironment of the scope in which it was declared (in our case, the global object or window). When you try to reference the variable from inside the function, the engine first searches for it the the native VariableEnvironment of the function, and then, if not found, in the outer LexicalEnvironment. In your case, you try to reference a variable from outside of the function, so the engine searches for it in the scope of global object at the very start.
So, to accomplish your task, you should either declare the variable in the outer scrope, and then assign it inside the function, or you should add a new property to the object and then reference it:
var foo = {
test: 'Hello world',
speak: function()
{
console.log(this.test);
}
};
You can access test by return it on call of bar method.
var foo = {
bar: function()
{
var test = 'Hello World';
return test;
},
speak: function()
{
// Log the Variable from above ^^
console.log(foo.bar());
}
};
In order to access the variable test in that manner, you need to define it as a property of the object like so:
var foo = {
test: 'Hello World, before calling bar()',
bar: function()
{
this.test = 'Hello World';
},
speak: function()
{
// Log the Variable from above ^^
console.log(this.test);
}
};
console.log(foo.test);
I also changed the functions to access the object foo using the keyword this. It will usually work but keeping track of your scope in javascript can be tricky sometimes, so just try to be aware of that.
What I want to do is to sending data between two handlers.
element.onmousedown = function() {
data = precalculate();
}
element.onmouseup = function() {
dosomething(data);
}
if the data is a global variable it works. People says global variable is evil. But I don't know how to do without it.
or I misunderstood "global variable"?
Just scope the variable if you don't want/need it to be global:
(function() {
var data;
element.onmousedown = function() {
data = precalculate();
}
element.onmouseup = function() {
dosomething(data);
}
})();
EDIT: To clarify, the only way to create a new variable scope in javascript is in a function.
Any variable declared with var inside a function is inaccessible to the outer scope.
In the code above, I created an IIFE (immediately invoked function expression), which is simply a function that is invoked as soon as it is created, and I placed your data variable (along with the handler assignments) inside of it.
Because the handlers were created in a scope that has access to the data variable, they retain their access to that variable.
To give another example:
var a = "a"; // global variable
(function() {
var b = "b"; // new variable in this scope
(function() {
var c = "c"; // new variable in this scope
// in this function, you have access to 'a', 'b' and 'c'
})();
// in this function you have access to 'a' and 'b' variables, but not 'c'
})();
// globally, you have access to the 'a' variable, but not 'b' or 'c'
In this case a global variable would make sense. Another possibility is to attach the value to the DOM element:
element.onmousedown = function() {
// 'this' should point to the element being mouse downed
this.data = precalculate();
};
element.onmouseup = function() {
// 'this' should point to the element being mouse upped
var data = this.data;
dosomething(data);
};
You misunderstood "global variable is evil".
In fact, what really happened is that someone wanted to be "part of the crowd", and so told you a sweeping generalisation, when in fact they should have said "only use global variables where appropriate".
Well, they are appropriate here, my friend.
JQuery makes this possible by using the .data() function:
http://api.jquery.com/jQuery.data/
You can get away with using global variables as long as you keep them to a minimum, for example you can place stuff in a single global namespace:
App = {};
element.onmousedown = function() {
App.data = "hello";
}
element.onmouseup = function() {
console.log(App.data);
}
Another more general solution is to create functions that cache their results using a technique that is called memoization. There's plenty of stuff if you search.
The following code does exactly that :
Function.prototype.memoize = function() {
var fn = this;
this.memory = {};
return function() {
var args = Array.prototype.slice.call(arguments);
return fn.memory[args] ? fn.memory[args] : fn.memory[args] = fn.apply(this, arguments);
};
};
e.g. You have an expensive function called exfunc..
newFunc = exfunc.memoize();
The above statement creates a new function called newFunc that caches the result of the original function so that the first time the actual code is being executed and all subsequent calls are retrieved from a local cache.
This mostly works with functions whose return value does not depend on global state.
More info :
http://osteele.com/archives/2006/04/javascript-memoization