JavaScript scopes and object-orientation - javascript

What's wrong with this—how come the variable foo isn't defined from within onModified() of a Document object?
function Document() {
var foo = "dfsadf";
this.onModified = function() {
alert(foo);
};
}
// Does not alert; "foo" doesn't resolve
new Document().onModified();
I'd like to have public methods on Document that reference variables that are somehow private to Document.

Your Document function is clashing with the Document constructor from the DOM.
document instanceof Document; // true
As with any host-object its behavior completely depends on the host environment, and they often can give you unexpected results.
As far I've tested, on Firefox you are not able to replace its value, therefore I would recommend you to either, rename your function, or, declare it on other scope.

Related

Why global "this.function" is not accessible without "this."?

this.func0 = function() {
console.log('hi')
}
this.func0() // this works
func0() // but not this?
Why func0() is not working?
Aren't this.f() and just f() both supposed to access global object?
The important thing to understand here is, in Node.js, each and every JavaScript file will be treated as a separate module.
So, within the JavaScript file, this will refer to the current module object, not the global object. We have something called global object in Node.js, which is somewhat similar to browsers' window object.
This is what you are doing with your program
this.func0 = function() {
console.log('hi')
}
you are creating a function object and assigning it to the current module's func0 attribute.
this.func0();
you are calling current module's func0.
func0();
JavaScript, searches for func0 in the current scope, then in the global scope but it doesn't find it anywhere. That is why it fails with the ReferenceError
ReferenceError: func0 is not defined
If you really wanted to set that in the global scope, then you should do it like this
global.func0 = function() {
console.log('hi')
}
func0();
// hi

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)

accessing my public methods from within my namespace

I am in the process of making my own namespace in JavaScript...
(function(window){
(function(){
var myNamespace = {
somePublicMethod: function(){
},
anotherPublicMethod: function(){
}
}
return (window.myNamespace = window.my = myNamespace)
}());
})(window);
I'm new to these kinds of advanced JavaScript techniques and i'm trying to figure out the best way to call public methods from within my namespace. It appears that within my public methods this is being set to myNamespace.
Should I call public methods like...
AnotherPublicMethod: function(){
this.somePublicMethod()
}
or...
AnotherPublicMethod: function(){
my.somePublicMethod();
}
is there any difference?
The way I see it, if you use this you're using a direct reference to the object, whereas if you use my, the interpreter would need to traverse the scope chain until it finds my as a property of window.
But there may be arguments the other way as well.
EDIT:
I should note that since this is determined by how the function is called, it would require that the Activation object be that object.
So this would work:
my.anotherPublicMethod();
But this would not:
var test = my.anotherPublicMethod;
test();
If that's a possibility, then you should use my, or some other direct reference to the object. You could reduce the scope chain traversal by maintaining a reference to the object. Your myNamespace variable should work.
A little off topic, but I'd also note that your code won't work the way it is.
This line:
return (window.myNamespace = window.my = myNamespace)
...doesn't have access to the myNamespace variable.
Perhaps you meant something more like this?
(function(window){
window.myNamespace = window.my = (function(){
var myNamespace = {
somePublicMethod: function(){
},
anotherPublicMethod: function(){
}
}
return myNamespace;
}());
})(window);

Using window object

I've seen lots of people using window. when calling some variable. But aren't all the variables of a same window actually in window?
Example:
window.onorientationchange = function() {
var orientation = window.orientation; // <-- WHY?
switch(orientation) {
/* ... */
}
}
But the same people use alert(), document, etc. So why?
At certain times you want to expose only certain functions/variables to be explicit properties of the window.
(function() {
var jQuery = function(selector) { alert( selector ) }
})();
jQuery // not defined
If we alter it to be:
(function() {
var jQuery = function(selector) { alert( selector ) }
window.jQuery = jQuery;
})();
then we "expose" it from a private namespace explicitly.
And yes, you do not have to explicitly declare window. to invoke methods such as alert, but everyone has their own style of coding and everyone has their own degree of how explicit their statements should be.
Some people explicitly prefix window. to global methods such as alert in order to avoid any confusion. Let's say you defined a function in a private namespace that was named alert, for example...
(function() {
function alert() {}
alert('lol'); // does nothing
window.alert('lol') // does something
})();
We cannot use alert inside of that private namespace to do our alerting, since we defined a function with exactly the same name. We have to explicitly reference the window.alert method to get around that.
But for general purposes, I would say it's perfectly fine to not prefix things with window. unless you are exposing things in a private namespace to the global namespace. So please use document and alert and such as is, in your code.
In many javascript tutorials alert(), document() and so on are used without fully qualified window object and I think they just repeat that code.

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