Creating a javascript object Using object initializers - javascript

I'm kind a new in Javascript and I have this situation:
I have a separated javascript file and I created a javascript object in this way:
$(document).ready(function () {
var formasPagamento = {
Cartao: 0,
Crediario: 1,
Vale: 2
};
});
In this same file, I have a function and I want to use this object formasPagamento, but when I try to use it, I get the error that formasPagamento is undefined.
Ex:
function CarregarDetalhesPlanoPagamento(idPosDocPagamento) {
if(idPosDocPagamento == formasPagamento.Cartao){ //undefined here
//do something
}
}
What's the proper way to initializa a "global" variable that can be used in another function?

Don't wrap var formasPagamento inside of $(document).ready. That is placing it inside of a child scope of global, making it inaccessible from your function. $(document).ready is to detect when the DOM is ready to be manipulated and there's no reason to postpone declaring that value.

What's the proper way to initializa a "global" variable that can be
used in another function?
window.formasPagamento = {
Cartao: 0,
Crediario: 1,
Vale: 2
};

In your example, you're declaring formasPagamento inside the document.ready jQuery wrapper, so formasPagamento can only be accessed from within that function.
This is known as scope.
To be able to access formasPagamento globally, you can declare it before your $(document).ready.. like so:
var formasPagamento = {
Cartao: 0,
Crediario: 1,
Vale: 2
};
$(document).ready(function () {
..page ready logic..
});
Now when you use your function, it'll be able to see formasPagamento

This article explains it quite well w3School
But basically the variable formasPagamento is only accessible inside the function scope of the document ready function.
$(document).ready(function () {
var formasPagamento {};
// CAN access here!
}
// CANNOT access here!

Related

MVC - Construct javascript object in my index that will be available in my script file

I want to initialize in my index javascript object with urls as properties, I need to initialize it on my view because of the #Url.Action that available in my view. so it will look like this:
Index.cshtml:
window.onload = function () {
myUrls=new Object();
myUrls.url1='#Url.Action("MyAction1","MyControllerName")';
myUrls.url2='#Url.Action("MyAction2","MyControllerName")';
myUrls.url3='#Url.Action("MyAction3","MyControllerName")';
myUrls.url4='#Url.Action("MyAction4","MyControllerName")';
}
Now I have script in my Script folder and I want to access these urls in my script.
How can I achieve this? Can I initialize this object somehow in my script instead of my view?
Because you've done this inside a function, the myUrls variable is scoped to that function. Once the function ends, myUrls goes out of scope and is no longer available. To make it stay around, you have to make it global by either taking it out of the window.onload (which doesn't make any sense anyways for a static variable declaration), or simply declare the variable first in the global namespace.
<script>
var myUrls;
window.onload = function () { ... }
</script>
But again, like I said, you don't need the window.onload because you don't have to wait for the DOM to be ready to declare a variable. So just do:
<script>
var myUrls = {
url1: ...,
url2: ...,
...
}
</script>
You don't need to create a new object explicitly, just use the object notation { ... }.
Finally, since you're adding this to the global namespace, I seriously recommend that you create your own namespace:
<script>
var MyAwesomeAndUniqueNamespace = MyAwesomeAndUniqueNamespace || {};
MyAwesomeAndUniqueNamespace.myUrls = {
...
}
</script>

Why does JS report 'this.function' as not being a function?

I wonder if somebody could please help me understand something that seems odd with JS?
The below code works. The function inlineEditEvent.init() is called, and then t.copy() is called correctly (where var t = this;).
However, if I was to replace that with this.copy(), I get the error this.copy is not a function.
What's the difference here? Why does the below work, but not the way as described in the last paragraph? Thanks.
jQuery(function($){
$(document).ready(function(){inlineEditEvent.init();});
inlineEditEvent = {
init : function(){
var t = this;
/** Copy the row on click */
$('#the-list').on('click', '.row-actions a.single-copy', function(){
return t.copy();
});
}, // init
copy : function(){
// Do stuff here
}
} // inlineEditEvent
});
You're setting t as a context variable of this (of your init function). Once inside your click handler, this is now referring to the click handler, no longer the init function. Therefore, this.copy() is not a function.
this refers to this within the functions scope. That's why you need to set a self variable, so it's accessible within the scope of the function. Considering you're using jQuery, you could use $.proxy:
$.proxy(function(){
return this.copy();
},this)
t.copy(); appears in a different function to var t = this;. The value of this changes inside each function.
When you say var t= this; it refers to what this meant in that context. Later on when you are trying to refer to this, it is referring to a.single-copy instead since that is the new context it is in.

Accessing a variable within a JavaScript object constructed via a function

My application is accessing a third party external JavaScript file that I cannot alter.
Within the file is an object defined similarly to as follows:
object_1 = (function(){
var object_1_var = 'object_1_var_value';
return {
obj_1_func: function() {
console.log(object_1_var);
}
}
})(window);
I need to be able access the object_1_var within the object, but I'm struggling to access it.
object_1.v // returns undefined
object_1.obj_1_func() // returns the value via console, but I need to assign it to a var.
I have tried extending the object using as follows: (Using jQuerys $.extend())
object_2 = (function(){
return {
obj_2_func: function() {
return object_1_var;
}
}
})(window);
$.extend(object_1, object_2);
var my_var = object_1.obj_2_func(); // returns 'Uncaught ReferenceError: object_1_var is not defined'
What can I do to be able to access object_1_var?
You will not be able to access the variable. It happens to be a private member. Private members of an object can be accessed only by its member functions.
Read this.
object_1_var is a lexically scoped local variable.
That means that it can't be accessed by extending object_1 outside of its original definition.
The only way it can be accessed is by adding functions within the original lexical scope in which it was declared:
object_1 = (function(){
var object_1_var = 'object_1_var_value';
return {
obj_1_func: function() {
console.log(object_1_var);
}
var_1: function(x) {
if (typeof x !== 'undefined') {
object_1_var = x;
} else {
return object_1_var;
}
}
}
})(window);
but since you can't modify object_1, you're out of luck, I'm afraid!
Make it public, like this:
object_1 = (function(){
var object_1_var = 'object_1_var_value';
return {
obj_1_func: function() {
console.log(object_1_var);
},
object_1_var: object_1_var
}
})(window);
EDIT
If unable to edit the javascript (such as in a third party library - sorry for omission) then you will not be able to have access to object_1_var as it's scope is local to the closure object_1.
What you are trying to accomplish is impossible in JS.
With the construction of object_1 the variable goes out of scope of that method. The reason why the logging function can access the variable is what we call 'a closure'.
Sadly, object_1_var isn't accessible in this example. The variable is defined as local to within that particular function - the only reason that the other functions can see it is because they are also defined within that function. This "closure scoping" is an interesting feature in JavaScript that you don't see very often elsewhere, but is the only real way of defining "private" variables in JavaScript Objects.
Hope that helps!
In a worst case scenario, in the past I've worked around this sort of issue by effectively overwriting the definition of an object that was previously defined elsewhere - mainly in Greasemonkey scripts - but I wouldn't condone this for production uses!
The trick here is to just copy the entire piece of script into your own. It's ugly as hell, but it might just work! (YMMV)

How to get access to this class member from within a callback?

This question is best explained with some code, so here it is:
// a class
function a_class {
this.a_var = null;
this.a_function = a_class_a_function;
}
// a_class::a_function
function a_class_a_function() {
AFunctionThatTakesACallback(function() {
// How to access this.a_var?
});
}
// An instance
var instance = new a_class();
instance.a_function();
From within the callback in AFunctionThatTakesACallback(), how does one access this.a_var?
You'll need to expand the scope of this by creating a local variable that references it, like this:
function a_class_a_function() {
var self = this;
AFunctionThatTakesACallback(function() {
console.log(self.a_var);
});
}
The reason why you need to do this is because the this reference within the AFunctionThatTakesACallback function is not the same this as the current object, it will likely reference the global windowobject instead. (usually not what you want).
Oh, did I mention that this is called a closure?
You could try using the call method of function objects, which lets you specify a value for this:
myFunction.call(this, args...)
But I think that in this case it would probably be more straightforward to pass 'this' in as one of the parameters to the callback.
When you call instance.a_function(), you're really calling a_class_a_function with instance as this, so you can modify a_class_a_function like so:
function a_class_a_function() {
var self = this;
AFunctionThatTakesACallback(function() {
// do something with self.a_var
});
}
The problem here is that if you attempt to call a_class_a_function without calling it from an instance, then this will likely refer to the global object, window.

Javascript: Access the right scope "under" apply(...)

This is a very old problem, but I cannot seem to get my head around the other solutions presented here.
I have an object
function ObjA() {
var a = 1;
this.methodA = function() {
alert(a);
}
}
which is instantiated like
var myObjA = new ObjA();
Later on, I assign my methodA as a handler function in an external Javascript Framework, which invokes it using the apply(...) method.
When the external framework executes my methodA, this belongs to the framework function invoking my method.
Since I cannot change how my method is called, how do I regain access to the private variable a?
My research tells me, that closures might be what I'm looking for.
You already have a closure. When methodA is called the access to a will work fine.
Object properties are a different thing to scopes. You're using scopes to implement something that behaves a bit like ‘private members’ in other languages, but a is a local variable in the parent scope, and not a member of myObjA (private or otherwise). Having a function like methodA retain access to the variables in its parent scope is what a ‘closure’ means.
Which scopes you can access is fixed: you can always access variables in your parent scopes however you're called back, and you can't call a function with different scopes to those it had when it was defined.
Since a is not a property of this, it doesn't matter that this is not preserved when calling you back. If you do need to get the correct this then yes, you will need some more work, either using another closure over myObjA itself:
onclick= function() { myObjA.methodA(); };
or using Function#bind:
onclick= myObjA.methodA.bind(myObjA);
yes, you're right. Instead of a method reference
var myObjA = new ObjA();
libraryCallback = myObjA.methodA
pass a closure
libraryCallback = function() { myObjA.methodA() }
If you are using jQuery javascript framework, easiest way is to use proxy:
$('a').click($.proxy(myObjA, 'methodA'));
I'd do this:
function ObjA() {
this.a = 1;
this.methodA = function() {
alert(this.a);
}
}
function bindMethod(f, o) {
return function(){
return f.apply(o, arguments);
}
}
var myObjA = new ObjA();
myObjA.methodA = bindMethod(myObjA.methodA, myObjA);
...
Where bindMethod binds the methodA method to always be a method of myObjA while still passing on any arguments which function() {myObjA.methodA()} doesn't do.

Categories