I'm new to Javascript's Object Oriented programming (from C++ area).
I want to know the best practice of calling member function from constructor.
Following is a working piece of code:
Obviously the "initialize" is declared ahead of the invocation "this.initialize();"
function Foo() {
this.initialize = function() {
alert("initialize");
};
this.hello = function() {
alert("helloWorld");
this.initialize();
};
this.initialize();
};
var f = new Foo();
f.hello();
If I change the code as following, it will fail at "this.initialize();".
Question 1 Why is that? Won't the Javascript Engine firstly read in all member function declarations of an object?
function Foo() {
this.initialize(); //failed here
this.initialize = function() {
alert("initialize");
};
this.hello = function() {
alert("helloWorld");
this.initialize();
};
};
var f = new Foo();
f.hello();
Then I made the change like this.
The function "initialize" is executed on construction, however, the calling for "this.initialize()" in function "hello" failed.
function Foo() {
this.initialize = function() {
alert("initialize");
}();
this.hello = function() {
alert("helloWorld");
this.initialize(); //failed here
};
};
var f = new Foo();
f.hello();
Question 2: is the first piece of code the only way of calling member function from the constructor?
Update:
if I have to define a function before using it, Question 3: why following code works?
function Foo() {
this.hello = function() {
alert("helloWorld");
this.initialize();
};
this.initialize();
};
Foo.prototype.initialize = function() {
alert("initialize");
};
var f = new Foo();
f.hello();
Question 4:
Why following code succeeded? (considering the "future" function is defined after calling)
alert("The future says: " + future());
function future() {
return "We STILL have no flying cars.";
}
In the first case, you are calling initialize before it is defined (on the next line).
In the second case, you are assigning the return value of the function (undefined in this case) to this.initialize, so when you try to invoke it as a function later, you get your error.
You may want to look further into the prototype pattern for making class-like structures - Douglas Crockford wrote a lot of useful stuff on this and it's useful for introductory learning: http://javascript.crockford.com/prototypal.html is a good start.
My answers inline (kind of)
Question 1 Why is that? Won't the Javascript Engine firstly read in all member function declarations of an object?
No, if they are defined as in your example, they will be executed in order, as the method doesn't exist yet, it will throw.
This way would be a different case (not OO, but to ilustrate):
function Foo(){
initialize(); //This would work
function initialize(){ ... } //Parser defines its function first
}
In this case, the parser does define the function declarations first, it's a different case.
The function "initialize" is executed on construction, however, the calling for this.initialize() in function "hello" failed.
this.initialize = function() {
alert("initialize");
}(); //This executes the function!
The problem with the above code is that you're not assigning the function to this.initialize, you're assigning the result of its execution, in this case undefined (because there is no return inside the function)
for example, if the code were:
this.initialize = function() {
return 2;
}();
then this.initialize would be... 2 !! (not a function).
Hope this helps. Cheers
Calling a method from constructor :
var f = new Foo();
function Foo() {
this.initialize(); //failed here
};
Foo.prototype.initialize = function() {
alert("initialize");
};
Execution Process:
1) All functions are created (that are defined at the root)
2) Code is executed in order
3) When Foo is created/constructed it executes the code.
It try's to run Initialize() but it doesn't find it,
it throws an internal exception that is caught and
then creates the Prototype method and executes it.
4) If the Foo.Prototype.initialize line came BEFORE the,
"var f = new Foo()" then the initialize function would have existed.
This process occurs for every line of execution.
Related
window.onerror = function(e){alert(e)};
function main(){
this.work = [];
this.start_working = function() {
try{
if(this.work.length > 0){
var y = this.work.shift();
y.func(y.args);
}
}
catch(e){alert(e)};
};
this.add_work = function(f, a){
this.work.push({func:f, args:a});
};
this.foo = function(){
function footoo(){alert("bar");}
this.add_work(footoo);
};
this.foothree = function(){
this.add_work(this.foo);
};
this.start = function(){
setInterval(function(){this.start_working();}.bind(this), 1);
};
};
x = new main();
x.start();
x.foothree();
This is the watered down version of a function I am using elsewhere to run animations sequentially.
Expected behavior:
this.foothree is processed by the interval adding foo to the interval. this.foo is then processed adding footoo to the interval which is finally processed alerting "bar".
Problem:
when this.foothree is processed, an error is thrown:
TypeError: this.add_work is not a function.
Why don't I use something simpler:
Basically I need a function which allows me to compose a more complex animation made of simpler animations to the queue to be processed so I can reuse that animation. Foothree in this instance is just simulating a call which would add the real animation, footoo, to the queue to be processed. Footoo would be composed of simpler animations, foo, which would be executed sequentially.
this returns the [[ThisValue]] property of the EnvironmentRecord of the LexicalEnvironment of the ExecutionContext of the running function (see the spec).
Its value depends on how the function is called. If you call
this.foo = function(){
function footoo(){alert("bar");}
this.add_work(footoo);
};
in the function being declared there is no add_work method.
You should adopt var _self = this; pattern in order to point the correct calling context.
Basically the code should be rewritten as follows:
function main(){
var _self = this;
this.work = [];
this.start_working = function() {
try{
if(_self.work.length > 0){
var y = _self.work.shift();
y.func(y.args);
}
}
catch(e){alert(e)};
};
this.add_work = function(f, a){
_self.work.push({func:f, args:a});
};
this.foo = function(){
function footoo(){alert("bar");}
_self.add_work(footoo);
};
this.foothree = function(){
_self.add_work(_self.foo);
};
this.start = function(){
setInterval(function(){_self.start_working();}, 1);
};
};
Edit:
removed .bind(this) from original code.
This question has two components.
First it is a question about this in JavaScript aka the "target" or "receiver" of a function.
The target of a function in JavaScript depends on whether you are in strict mode, how the function was called and whether it was bound using bind.
Assuming strict mode (you should always put 'use strict'; at the top of your JavaScript):
foo(); // this inside foo will be undefined
a.foo(); // this inside foo will be a
a.foo.call(o); // this inside foo will be o
a.foo.apply(o); // this inside foo will be o
a.foo.bind(o)(); // this inside foo will be o
The second aspect to this question is what the author is attempting to do. I am pretty sure the complexity he is introducing to chain animations is unnecessary, and that he should be using requestAnimationFrame, but discussion of this would require another question.
Example:
function foo() {
document.write('foo', this, '<br/>');
bar();
}
function bar() {
document.write('bar', this, '<br/>');
}
foo();
document.write('------<br/>');
foo.call({});
With this code:
function thing(){
function majig(){
alert("done");
}
}
var mything = new thing();
mything.majig();
I'm getting this error:
TypeError: mything.majig is not a function
I've done javascript for some time, and I've done functions as part of functions and called them before. I know it has to be something simple I'm missing or forgetting, but various websearches (and poking around here) are getting me deeper theory answers, or examples that seem to indicate that this should work.
I know TypeError: foo is not a function usually means a syntax error. I've looked up examples, and it looks like I have the syntax right (I've tried a few variations with no success).
It's got to be some dumb simple mistake, but I'm just not catching it right now. What do I do in my function to make the mything.majig(); run properly?
You have declared a function in thing, but it's not attached to this at all. Try this:
function thing(){
this.majig = function() {
alert("done");
}
}
var mything = new thing();
mything.majig();
Alternately:
function thing() {
return {
majig: function() {
alert("done");
}
};
}
Or, better yet:
function thing() { }
thing.prototype.majig = function () {
alert('done');
}
The syntax is not what you think it means. It's not a member declaration. It's an inner function. Inner functions work just like local variables - they're only accessible in the scope of the outer function:
function foo () {
function bar () {}
bar(); // accessible here
}
bar(); // undefined here
If your function is a constructor, then to add a member function to the object that it constructs you'd add it to the constructor's prototype:
function Foo () {}
Foo.prototype.bar = function () {}; // bar is a member of object Foo
var f = new Foo();
f.bar(); // call member function
Objects in javascript are dynamic. They behave more like maps/hashes do in other languages. This means you can add a member function directly to an object instead of a constructor's prototype:
var f = {};
f.bar = function () {};
f.bar(); // call member function
Following the logic above, since this in a constructor refers to the object being constructed, you can also dynamically add a function to this. This is typically called "decoration" since it is effectively an ad-hoc version of the decorator design pattern:
function Foo () {
this.bar = function () {}
}
var f = new Foo();
f.bar();
I found code similar to this in a legacy app:
var Example = function (var1, var2, var3) {
this.prop1 = var1;
this.prop2 = var2;
this.prop3 = var3
};
Example.prototype = function () {
var showAlert = function (message) {
alert(message);
}
};
var example = new Example(null, null, null);
So I tried to access the prototype method like this:
example.showAlert("hello");
Here is the jsfiddle: http://jsfiddle.net/64dkjke1/
It doesn't work . . . the showAlert method is undefined. The prototype is equal to a function that defines other functions inside . . . hopefully I'm just overlooking something simple here.
How can I access this prototype function?
Thank you.
If you have no problem changing the original code, you can do the following to have the prototype receive an object using IIFE:
Example.prototype = (function () {
return {
showAlert : function (message) {
alert(message);
}
}
})();
var example = new Example(null, null, null);
example.showAlert("hello");
Fiddle
Was it like this instead, attaching an object to the prototype? It's difficult to determine what the issue is because you say that the code you've posted is only similar to the code in the legacy app, so we can't really know for sure.
Example.prototype = {
showAlert: function (message) {
alert(message);
}
}
You can't, cause
var showAlert = function (message) {
alert(message);
}
is private.
you can do this:
function abc(){
var myPrivateVar = "Hello";
this.alert = function(){
alert(myPrivateVar);
}
}
new abc().alert();
but not this
var a = new abc();
alert(a.myPrivateVar);
You cannot access the function showAlert() (as you have already figured out) The reason for this is simple.
Example.prototype = function ()
Does not extend your prototype by a function but overrides the whole prototype (which you usually don't want to do unless you are very aware of what you're doing). In JavaScript the prototype of a class is a function itself. You have access to your prototype by calling myClass.prototype which will return your prototype object.
The prototype can be extended (like every other object in JavaScript aswell)
quick example:
Example.prototype.showAlert = function(message){ alert(message); };
now you could call:
Example.prototype.showAlert("Hi");
// or calling it from an instance of Example:
var myExample = new Example();
myExample.showAlert("Hi")
So what your fiddle does is it replaces the whole prototype with this:
function () {
var showAlert = function (message) {
alert(message);
}
};
One could argue that this new function does not serve well as a prototype, but still IS callable (to come back to your original question). You can call it like this:
Example.prototype()
But nothing will happen since the only thing happening in this function is that it will declare a 'private' function inside this prototype-scope, which never gets called.
// start of prototype function
var showAlert = function (message) {
alert(message);
}
// end of prototype function
I cannot imagine this is what your intention was, so my advice is to stick to extending prototypes (but even that only if you have to).
In below example about Scope, I dont understand that how could a variable is running as a function? in here var f is running as f(). However, is this a sound method to run f in JavaScript? Why? Is it because var f stored a function?
var myFunction = function() {
var foo = "hello";
var myFn = function() {
console.log( foo );
};
foo = "ddd";
return myFn;
};
var f = myFunction();
f(); // "ddd"
Thanks!
This line of code will run the function myFunction and assign its return value to f.
var f = myFunction();
myFunction returns a reference to the function myFn. As a result, f is now a reference to myFn and when you attempt to call f using f() it calls myFn because that is where the reference points.
jsFiddle Demo
There is a similar approach which returns an object with functions
var init = function(){
return {
hello: function(){ console.log("hello"); },
world: function(){ console.log("world"); }
};
};
Which could then be used like this:
var f = init();
f.hello();
f.world();
In scripting languages in general and functional programming. You can use functions as you would a variable. For example: in both paradigms typically(not aware of any languages that don't) functions can be passed as parameters, etc...
Functions are objects in javascript, so they can be assigned to variables and passed around like any other value. And eventually they can be executed.
What's happening here is that myFunction returns a function, which can then of course be executed.
Let me simplify your example:
// function that returns a function.
var foo = function() {
// declare a function, but don't run it right now.
var fn = function() {
return "bar";
};
// return the function object.
return fn;
}
var someFn = foo(); // function object is returned from foo()
someFn(); // "bar" is returned
// Which means you could also do this!
// the first () executes foo, second () executes the function returned by foo()
foo()() // "bar" is returned
In this example, foo() returns a function. This function is saved to the local variable someFn and then executed.
Functions that return functions are a little tricky to wrap you head around sometimes, but it's one of the most powerful features of javascript as it allows you do some very tricky things.
Suppose I have:
var myfunc = function() {
// do stuff
}
myfunc.foo = function() {
//do other stuff
};
Now myfunc has a property foo that is a function, great. Is there a way to create myfunc from the get-go in this state? That is, I want foo to be defined when myfunc is created. The syntax, I would imagine, is something like:
var myfunc = {
:function() {
// do stuff
},
foo: function() {
// do other stuff
}
}
Except that's wrong.
You can place an anonymous function inside an object, however the only plausible way of doing this is to call the anonymous function when the object is initialised, otherwise the function will never be able to be called - it's anonymous!
Here's a JSFiddle: http://jsfiddle.net/g105b/99K5F/
var myfunc = function() {
this.foo = function() {
console.log("myfunc.foo called!");
};
(function() {
console.log("Anonymous function called.");
})();
};
// Initialising "myfunc" will call the anonymous function.
var instance = new myfunc();
// Now the foo method can be called.
instance.foo();
A little confused as to what functionality you are looking to gain here...
If you want some code to execute when the myfunc is defined, you could use the module pattern:
var myfunc = (function() {
var self = {};
// any initialization code can go here
alert("myfunc init code");
self.somePublicMethod = function () {
}
return self;
}());
This can also be called an immediate function, a function that is defined and executed at the same time.
From within the closure, and code that is not defined as part of another function will be executed when the object is defined, so when you do something like this:
myfunc.somePublicMethod()
the alert would have already been fired.
(This answer written before the first half of the question was significantly revised)
Now myfunc has a property foo that is a function
No, it doesn't.
You called it with myfunc() so this is a reference to the global window object, thus you are creating window.foo.
Possibly what you are looking for is:
function myfunc () {
// do stuff when myfunc is called
}
myfunc.foo = function () {
// do stuff when myfunc.foo is called
};
or perhaps:
function myfunc () {
// do stuff when myfunc is instantiated
this.foo = function () {
// Add a foo property to this when myfunc is instantiated
// ... which is only worth while if you are doing pretty
// ... odd stuff with the variables that are passed in
}
}
var instance = new myfunc();
or maybe:
function myfunc () {
// do stuff when myfunc is instantiated
}
myfunc.prototype.foo = function () {
// Have a foo function on every instance of myfunc
}
var instance = new myfunc();
… but you've abstracted the problem you are trying to solve away in your question, so it is hard to tell what you are actually trying to achieve.
You can use jQuery:
var myFunc = jQuery.extend(
function() { ... },
{
bar: "wioll haven be",
foo: function() { alert(myFunc.bar); }
}
);
myFunc();
myFunc.foo();
This is mostly code acrobatics, this is probably the closest you'll get:
var myfunc;
(myfunc = function(){}).foo = function(){};
There is no practical difference in declaring methods later though, since javascript is single-threaded.