I'm trying to understand the syntax of how to put together a JavaScript function as an object.
Q: Is this the right way to do it?
The reason why I ask is because I'm looking at it in Firebug and I was hoping to be able to drill down and see the value of myVar and myVariable, but instead Firebug only says that "this" is an object Object.
var myObject = {
init: function() {
var myVar = 1;
myObject.myVariable = 2;
console.log('"this" when called as an object: ' + this);
}
}
myObject.init();
Also, what's the funny little syntax to call it directly upon declaration? Something about (), but when I remove the last line and put () at the end of the declaration, I get a syntax error.
This will create a string:
'"this" when called as an object: ' + this
But this is not a string, so its toString() prototype gets called. That's why you only see [object Object].
If you want to have Firebug display the actual object, do a simple console.log(this) or to see the contents directly use console.dir(this).
The "funny little syntax" doesn't really apply here, because you're not really creating a "function object" — that's just an object with a property whose value is a reference to a function object.
However, though it's been done to death on Stackoverflow, you're probably talking about something like this:
var myobject = (function() {
var something = { whatever: "for example" };
return {
init: function() {
this.foo = "hello";
// initialize
},
getSomething: function() { return something.whatever; }
};
})();
Now "myobject" is initialized by a call to an anonymous function, which will be thrown away right after that statement. The closure formed by the function invocation, however, remains alive.
Here is a nice reference for JavaScript object creation
Related
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.
var a = {
text : 3,
logText : function () {
console.log(this.text);
},
callLogText : function() {
logText();
}
};
a.callLogText();
This will genernate a ReferenceError: logText is not defined error message.
Instead, you prefix this to the logText() method, it will be ok. No error msg will pop.
var a = {
text : 3,
logText : function () {
console.log(this.text);
},
callLogText : function() {
this.logText();
}
};
I really cant figure out the reason.
You need to learn the JavaScript scoping rules. This blog post gives a good introduction.
In a nutshell, JavaScript follows some rules when you use a variable name (for the purpose of this explanations, function definitions are pretty much like variable declarations).
What probably confuses you is this:
var a = { b: ...};
var a = function() { var b = ... }
In both cases, you get a new variable a. In the first case, it's an object with a property b. In the second case, it's a function which has a nested scope in which a new variable b is defined.
JavaScript will look in the current and all parent scopes for variables. But object definitions are no scopes. As far as JavaScript is concerned, the property b is invisible unless you make it visible by using the special variable this which always references the "current" object (in your example, that is a).
Since the properties of the object a are not "in scope", JavaScript can't find logText() unless you tell it to look in this. If you don't say anything, JavaScript will look in the current scope (the body of the function callLogText), then the parent scope (in which a is defined) and then in any parent scopes of that.
It's not a quirk. It's how most languages function when it comes to objects.
logText() is a method of the a object, not a function.
You need to call methods internally as this.methodName() or externally as object.methodName().
logText(); is to execute a global function logText which is undefined.
this.logText(); is to execute the function a.logText.
Calling
logText();
means somewhere there is a function named logText(), but here you have defined logText() as a property of an object, so to access the logText() you have to refer it with the help of the object it is defined in. In this case it is in the same object so you refer to the same object by saying this.
EDIT
With the number of responses saying "you can make private things!" below, I'm going to add this to the top as well:
I know you can emulate private variables within a closure. That is not what I'm asking. I'm asking, given the two examples below where I'm "exporting" EVERYTHING from the closure, what is the fundamental difference between these two examples.
Given these two methods of creating objects/methods:
var test = {}
test = (function(){
var a_method = function(print_me){
return "hello "+print_me;
}
return {print_me: a_method};
})();
test.print_me2 = function(print_me2){
return "hello "+print_me2;
}
test.print_me('world');
>>> returns "hello world"
test.print_me2('world');
>>> returns "hello world"
I understand that the first method allows for private variables (which as a python developer at heart i don't really care to use), but both seem rather equivilent to me, only the first one looks "cooler" (as in all the big javascript people seem to be doing it that way) and the second way looks very passé.
So, like, what is the difference?
I've looked through the closure questions here -- most of them center around what or why do you use them; I understand their utility, I just want to know why you'd do the first over the second and what benefits it has.
I'd prefer hard evidence over conjecture -- not looking for a "this is how the cool kids are doing it" or "i heard that mozilla does better memory usage when you use a closure", but rather qualitative evidence towards one being 'better' than the other.
The difference between the methods is the anonymous function wrapper that creates a closure, but also that the first method replaces the entire object while the second method just sets a property in the existing method.
There are different ways of adding methods to an object. You can put them there when you create the object:
var test = {
print_me: function(text) { return "hello " + text; }
};
You can add a method as a property to an existing object:
var test = {};
test.print_me = function(text) { return "hello " + text; };
You can make a constructor function, and add methods to its prototype:
function Test() {}
Test.prototype.print_me = function(text) { return "hello " + text; };
var test = new Test();
As Javascript has a prototype based object model, the last one is how methods were intended to be created. The other ways are just possible because an object property can have a function as value.
You can use a function wrapper around any code where you want local variables, so you can do that with the second way of setting the property:
test.print_me2 = (function(){
var method = function(print_me2) {
return "hello "+print_me2;
}
return method;
})();
In the first example, the closure is used to keep local variables out of the global scope.
var thisIsGlobal = 2;
var test = (function () {
var thisIsLocal = 3;
return function () {
return thisIsLocal;
};
}());
What you get is a function test which when invoked returns the value of the local variable thisIsLocal. There is no way to change the value of the variable. You can be look at it as to a private variable.
The first method you present (an anonymous function which is executed immediately) keeps your program out of the global scope. Within that private scope you can decide what properties you want to expose as your API:
(function(win){
var a, b, c = 1;
function init(){
return aa(b);
}
function exit(){
if(cc()){
return a;
}
}
function aa(){
}
function bb(){
}
function cc(){
}
win.myProgram = {init: init,
exit: exit };
})(window);
// We now have access to your API from within the global namespace:
myProgram.init();
//etc
I'm trying to round out my Javascript knowledge. This seems like such a simple thing, yet it's puzzling me.
I have a need to store a method name as a variable. Reducing my test case to the smallest possible size, results in the following:
var someobj = {
someMethod: function() {
console.log('woo');
},
somevariable: this.someMethod
}
There are no callbacks, everything's nice and simple.
console.log(someobj.someMethod);
Returns:
[Function]
Great. But:
console.log(someobj.somevariable)
Returns:
undefined
I was expecting it to return '[Function]'. Why is this?
Thanks.
When declaring objects in JSON - format, there is no this keyword. (well, there is, but i refers to the this of the outer context, for example window in a global context) You cannot access the current object in such a declaration.
You will thus need to set that variable afterwards, something like this:
var someobj = {
someMethod: function() {
console.log('woo');
}
}
someobj.somevariable = someobj.someMethod;
I've opened jQuery 1.7.1 library and wanted to study the code, but I've found a that functions are declared in strange way (for me). For example:
show: function() {
//some code here
},
I learned to define function on this way:
function show() {
//some code here
}
Can someone explain me why show function is not written on second way (like in most tutorials on internet)?
This is because it is within an object. Object Literals have their properties defined in this way:
{
name: value,
//OR
'name': value
}
Where value can be nearly anything such as a number, string, function, or even another object. In JavaScript you can also declare anonymous functions and assign them to a variable. In fact, the following declarations have the same effect:
//declares the myFunc1 function
function myFunc1() {}
//declares an anonymous function and assigns it to myFunc2
var myFunc2 = function() {};
//you can now call either like so:
myFunc1();
myFunc2();
So, combining those two concepts if I have an object and I want one of its properties to be a function I would do it like so:
var myObj = {
name: 'My Object',
init: function() {
return 'Initializing!';
},
version: 1.0
};
alert(myObj.init());
You would then get the output: Initializing!. Make sure to check out the great documentation and tutorials on the Mozilla Developer Network, including their JavaScript Tutorial Series
Hope this helps!
Writing it the first way is in essence, setting a function as property of an object.
For example:
// I can create a new empty object
var myObject = {};
// or I can create a new object with a basic property
var myObject = {
color: "blue"
};
// I can also create an object with methods (like jQuery)
var myObject = {
color: "blue",
showColor: function(){
alert(this.color);
}
};
// and you can use the object like this
myObject.showColor(); // calls the showColor method and will alert "blue"
This helps jQuery to encapsulate, namespace, and organize code.
Here are a couple of pretty good write-ups:
Why do you need to invoke an anonymous function on the same line?
http://en.wikibooks.org/wiki/JavaScript/Anonymous_Functions
http://www.evotech.net/blog/2008/07/javascript-object-literals-a-definition/
The first declaration, i.e., show: function, defines show to be a field in an object having type function. The second declares a function named show within the current scope (possibly global?)
they're being described as a js object function. In this case:
var jQuery = {
show: function(){
//some code here
}
}
so you access it like jQuery.show() for example.
I would say Chad's answer is most accurate for in depth research. You should look into them as they can revolutionize how you write js in a very clean way that is much less likely to conflict with other libraries.