var foo = (function(){
var _blah;
function doStuff(){
//how to make _blah instance specific
//and access it here?
}
function bar(blah){
_blah = blah;
doStuff();
//this.blah = blah?
}
bar.prototype.getBlah = function(){ return _blah; };
return bar;
})();
var foos = [];
$.each([1,2,3], function(i, v){
var f = new foo(v);
foos.push(f);
});
//all instances of foo
//gets _blah set to 3
console.log(foos[1].getBlah());
I have two questions regarding the module above:
How do I set a property that is specific for each instance? Right now you can see that _blah gets overwritten, which is pretty obvious. But I need some help with the syntax. My guess is that I need to set it in the constructor like the comment. Is that the right way to do it?
How do I access the property in another method? As far as I know, this refers to window in doStuff().
http://jsfiddle.net/ncg2M/1/
How do I set a property that is specific for each instance? Right now you can see that _blah gets overwritten, which is pretty obvious. But I need some help with the syntax. My guess is that I need to set it in the constructor like the comment. Is that the right way to do it?
Yes. That's the right way to do it, using this.blah = // value, but of course this makes the variable blah accessible publicly without any restriction.
How do I access the property in another method? As far as I know, this refers to window in doStuff().
doStuff() method doesn't make a lot of sense, because when you define a function like that inside a modular, then it is usually a utility function that is used by other instance methods.
Related
Below is simplification of some code I am trying to understand.
What are we trying to do in this javascript fragment? It seems we are creating object(?) called myCompany if not already created, then adding child object myProject to myCompany.
Then creating a local variable withinmyCompany.myProject and another local to function myCompany.myProject.myfunction. The () at the end make it execute immediately. And we are doing this to keep localVariable_1 out of global space?
var myCompany= myCompany || {};
if (!myCompany.myProject) {
myCompany.myProject = {};
}
myCompany.myProject = function () {
var localVariable_1;
function myFunction(){
var anotherlocalVariable;
// .. do some stuff
}
}();
The first line checks if the object exists, if not use shorthand definition {} to create an Object. || compares. If argument one is null set argument two.
The if on the next line checks if the property myProject isn't set on the object. ! is the operator. If myCompany.myProject returns undefined this if clause returns true. When true create object as property myProject.
Third part: myProject gets replaced by a function object. This function is defined between { and }, but is immediately called upon by the () behind the function declaration.
localvariable_1 will never be in the global scope since it has the var statement. Binding it to the scope of myCompany.myProject function. Maybe this function is directly called to set up some initial values, but wrap them in a function that could be reused to change the values at another moment.
One piece at a time...
var myCompany= myCompany || {};
if myCompany exists you set it to it, otherwise you create an empty object and set myCompany to an empty object.
NOTE: if myCompany already exists you have no indicator of what it is
if (!myCompany.myProject) {
myCompany.myProject = {};
}
Now that you know myCompany is an object you verify it has a project property on it. if not you set myProject to an empty object.
NOTE: you have tested nothing about myProject so again there is no indicator of what it is
myCompany.myProject = function () {
var localVariable_1;
function myFunction(){
var anotherlocalVariable;
// .. do some stuff
}
}();
Here you are assigning myCompany.myProject. Notice at the bottom the () before the ; That makes this function get executed immediately. Inside of the function you are creating another function that currently isn't doing anything. Where you aren't returning from the function I think it will set myProject to undefined.
You may already know what an immediate function is but if not it is basically a function that is called right away. It is also standard to wrap it in a () so that it is easier to read for example
var someFunction = (function () {
/*whatever*/
} ());
You said this was simplified from the original so I am guessing you removed an important part of the code that actually does things but the confusion is probably due to the JavaScript's way of scoping. It uses what is called Lexical scoping. You can think of it as scoping by functions.
Another thing that may be tripping you up is how JavaScript uses truthy evaluation for logical comparisons.
The last thing to mention that might be confusing the way you read the code is javascript's hoisting.
Hopefully that helps or at least points you to a few things you can look into to figure out the parts you don't exactly understand.
Sorry I just hate writing in comments lol.
If you are trying to help prevent your global scope from getting polluted then you might want to use objects and a something similar to what you are doing. Depending on how crazy you want to get you could look into Prototypical Inheritance.
A common pattern is to do something like this
var company = (function() {
var name;
var getName = function() {
return name;
};
var setName = function(n) {
name = n;
};
return {
getName : getName,
setName : setName
}
}())
Now you can do company.setName("yoda") or whatever.
This will give you a basic getter and setter where no one can change the companies name without going through your getter and setter and it also doesn't pollute the global scope. You can have whatever you want on company this way and you also encapsulate the data within the object.
Notice how var company = a function that is called immediately which returns an object that has whatever you want to encapsulate on it.
Is that what you are talking about?
I am trying to create a variable that refers to the current object/function.
I mistakenly thought this would do it:
var fn1=function(){
var _this=this;
_this.prop='hey!';
console.log(_this);
};
The console log output the browser window object, which I found confusing until I read this:
this keyword Function context
Can anyone explain to me why, in javascript, this refers to the parent?
As a result of all of this Ive been thinking about using something like this:
var fn2=function(){
var _this=(function(){
return this;
})();
_this.prop='hey!';
console.log(_this);
};
But is there a better way or simply a correct way I am missing, to get at the current object from inside itself?
Can anyone explain to me why, in javascript, this refers to the parent?
The value of this depends on how you call the function.
If you call the function in the context of an object (foo.method()) then this is foo because it is useful to have access to the object to which the method belongs when performing OOP.
But is there a better way or simply a correct way I am missing, to get at the current object from inside itself?
What current object?
If you want to use a constructor function, then use the new keyword.
function Dog(name, breed) {
this._name = name;
this._breed = breed;
}
var myDog = new Dog("Fifi", "Poodle");
alert(myDog._name);
I am attempting to build my first custom object and it looks something like this:
function URLObject()
{
this.syllables = new Array();
etc...
this.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
}
var myobj = new URLObject();
myobj.AdtoSyllables("text");
The execution of the above code results in the JS engine printing out the following:
This is Sylcount: NAN
-or-
This is SylCount: undefined.
I have looked at information in Head First Javascript, in the Javascript bible, and on various JS websites. All of them cover in exhaustive detail the use of arrays of objects, but none of them discuss arrays within objects.
And yet I am doing something wrong here and I do not know what. Can anyone help?
Here you go:
function URLObject()
{
this.syllables = [];
etc...
}
URLObject.prototype.addToSyllables = function(aWord) {
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
var myobj = new URLObject();
myobj.adtoSyllables("text");
.prototype adds the function declared after it to every object constructed by the constructor function. (in your case every object that was instantiated by new URLObject())
Firstly, the code as posted actually works for me on Chrome and Firefox; so this must depend on the JavaScript engine, or else there's something funky going on.
Update: I suspect what may be confusing you is some separate call to AddtoSyllables (in code you haven't shown us) where suddenly this.syllables is no longer defined. This is where the behavior of this can get confusing. I've created a jsFiddle to hopefully explain how it works a bit better for you.
http://jsfiddle.net/J3tUb/
That said, it is often very possible to write code like this without having to use this (or the prototype) at all. For instance:
function createURLObject() {
// Use closed-over locals instead of attaching properties.
var syllables = new Array();
function AddToSyllables(AWord) {
// Since syllables is closed over, it is accessible here
// (but WON'T be accessible outside this scope).
syllables.push(AWord);
return syllables.length;
}
// Expose whatever functionality you want to be "public"
// in the returned object.
return {
AddToSyllables: AddToSyllables
};
}
var myObj = createURLObject();
myObj.AddToSyllables("text");
It is, of course, valuable to understand JavaScript's quirky (and surprising, to most developers coming from other languages) behavior with respect to this. That said, once you do understand it, I suspect you will find that it can often be avoided altogether.
you need to do this :
function URLObject()
{
var that = this;
that.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
etc...
Like this you can add method and attributes to one object.
The issue you are having is that the function AddtoSyllables is not a member function or method of the URLObject. It is just a nested function with no object attachments, so all usages of this will result in returning the dom window object. The correct way of declaring the AddtoSyllables function is this:
function URLObject()
{
//...
}
URLObject.prototype.AddtoSyllables = function (AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
To explain the reasons of the behavior in the question, I'd like to clarify that objects in javascript are treated like a map, dictionary or a key-value pair (use the term what suits you best). Using the syntax x.y = value; is equivalent putting the value value into the map x with key y. Having the code:
this.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
adds the AddtoSyllables function as an entry to the object this points to.
The code
myobj.AdtoSyllables(...)
is equivalent to
myobj["AdtoSyllables"](...) // now a retreiaval operation
or even
var fn = myobj["AdtoSyllables"];
fn (...);
Inside the AdtoSyllables function, this is used. Against common expectations, it is not a pointer to the myobj.
The cause of this is that AddtoSyllables is treated as a static method of the URLObject class (as OOP guys would understand it), or even a loose static function (like in C). To make JS treat it like a member of the URLObject object (an instance method to OOP guys), JS must be told to do so. This is achieved through the URLObject.prototype.AddtoSyllables = .... which equivalents to declaration of an instance method.
From an alternative point of view:
function foo() { /* some code using `this` */ }
var bar = {};
var baz = {};
bar.foo = foo; // same as bar["foo"] = foo;
baz.foo = foo; // same az baz["foo"] = foo;
In the above code, this usages inside foo will neither point to bar, nor baz. At the same time bar.foo will point to the very same instance as baz.foo, for foo is also an object.
We have a lot of setup JS code that defines panels, buttons, etc that will be used in many other JS files.
Typically, we do something like:
grid.js
var myGrid = .....
combos.js
var myCombo = .....
Then, in our application code, we:
application.js
function blah() {
myGrid.someMethod()
}
someother.js
function foo() {
myCombo.someMethod();
myGrid.someMethod();
}
So, should we be using the var myGrid or is better to use window.myGrid
What's the difference?
A potentially important difference in functionality is that window.myGrid can be deleted, and var myGrid can not.
var test1 = 'value';
window.test2 = 'value';
console.log( delete window.test1 ); // false ( was not deleted )
console.log( delete window.test2 ); // true ( was deleted )
console.log( test1 ); // 'value' ( still accessible )
console.log( test2 ); // ReferenceError ( no longer exists )
I would suggest creating a namespace variable var App = {};
App.myGrid = ...
That way you can limit the pollution of the global namespace.
EDIT: Regarding the number of variables issue - 2 possible solutions come to mind:
You can further namespace them by type(Grids, Buttons, etc) or by relationship(ClientInfoSection, AddressSection, etc)
You encapsulate your methods in objects that get instantiated with the components you have
ex: you have
function foo() {
myCombo.someMethod();
myGrid.someMethod();
}
becomes:
var Foo = function(combo, grid) {
var myCombo = combo;//will be a private property
this.myGrid = grid;//will be a public property
this.foo = function() {//public method
myCombo.someMethod();
myGrid.someMethod();
}
}
App.myFoo = new Foo(someCombo, someGrid);
App.myFoo.foo();
this way you limit the amount of little objects and only expose what you need (namely the foo function)
PS: if you need to expose the internal components then add them to this inside the constructor function
One nice use of window.variable is that you can check it without having a javascript error. For example, if you have:
if (myVar) {
//do work
}
and myVar is not defined anywhere on the page, you will get a javascript error. However:
if (window.myVar) {
//do work
}
gives no error, and works as one would expect.
var myVar = 'test' and window.myVar = 'test' are roughly equivalent.
Aside from that, as other said, you should descend from one global object to avoid polluting the global namespace.
In global scope the two are in fact equivalent functionality-wise. In function scope, var is certainly preferable when the behaviour of closures is desired.
I would just use var all of the time: firstly, it's consistent with the usually preferred behaviour in closures (so it's easier to move your code into a closure if you decide to do so later), and secondly, it just feels more semantic to me to say that I'm creating a variable than attaching a property of the window. But it's mostly style at this point.
The general answer to the question would be to use var.
More specifically, always put your code in an Immediately Invoked Function Expression (IIFE):
(function(){
var foo,
bar;
...code...
})();
This keeps variables like foo and bar from polluting the global namespace. Then, when you explicitly want a variable to be on the global object (typically window) you can write:
window.foo = foo;
JavaScript has functional scope, and it's really good to take full advantage of it. You wouldn't want your app to break just because some other programmer did something silly like overwrote your timer handle.
In addition to other answers, worth noting is that if you don't use var inside a function while declaring a variable, it leaks into global scope automatically making it a property of window object (or global scope).
To expand on what Liviu said, use:
App = (function() {
var exports = {};
/* code goes here, attach to exports to create Public API */
return exports;
})();
By doing that you can hide some of your implementation specific code, which you may not want exposed by using var's inside. However, you can access anything attached to the exports object.
I have this inside the HTML that is creating an object in JavaScript
var myObject = new MyClass();
I know that after this I can refer to myObject and use it.
The problem is that I have the instantiation done in an anonymous way e.g.
new MyClass()
Is there a way to find then the instance so I can reuse it later in the code ? Any idea appreciated.
for example
lastOfMe = null
function myClass() {
lastOfMe = this;
this.x = 123;
}
new myClass();
alert(lastOfMe.x)
this is totally ugly though
It depends of how MyClass works...
It could have saved all the instances in a class property, but in most cases, you must assign the result of the instantiation to a variable...
Anonymous objects are just that. If you want to use your object again, why create it anonymously?
If you really must do this, then just ensure that your object will register itself somewhere, like as a property of a global or similar, so you can grab it later.