Could someone please explain the significance of prototype.init function in JavaScript and when it is called during object instantiation?
Why would you want to overwrite it with an empty function?
I am reading the JavaScript for Web book and am stuck on the this for the past few hours...what is piece of code supposed to achieve?
var Class = function(){
var klass = function(){
this.init.apply(this, arguments);
};
klass.prototype.init = function(){};
// Shortcut to access prototype
klass.fn = klass.prototype;
// Shortcut to access class
klass.fn.parent = klass;
...
}
This is just too much magic for me...:)
I'm not sure what you don't understand. init is simply a method like any other, that happens to be called in the constructor and with the same parameters as the constructor. If it's empty then it's just because the person who wrote it didn't need to put anything in it for now but wanted to lay down the groundworks of his class.
function Foo(a, b, c) {
this.init.apply(this, arguments); //This simply calls init with the arguments from Foo
}
Foo.prototype.init = function(a, b, c) {
console.log(a, b, c);
}
var f = new Foo(1, 2, 3); //prints 1 2 3
http://jsfiddle.net/Hmgch/
what is piece of code supposed to achieve?
Confusion.
var Class = function() {
// initialization logic
}
// Shortcut to access prototype
Class.fn = klass.prototype;
// Shortcut to access class
Class.fn.constructor = Class;
Related
I am working with Javascript and Appdescriptors in JSON format.
What I want to do is creating a instance of a Class, where the classname is saved as string in oModelConf[sModelName].type. If that is not the case I want to take "sap.ui.model.odata.ODataModel"
Related Question offers this solution:
function instantiate(className, args) {
var o, f, c;
c = window[className]; // get reference to class constructor function
f = function(){}; // dummy function
f.prototype = c.prototype; // reference same prototype
o = new f(); // instantiate dummy function to copy prototype properties
c.apply(o, args); // call class constructor, supplying new object as context
o.constructor = c; // assign correct constructor (not f)
return o;
}
This is not a very good solution I think.
EDIT It does not work for me because my class is not defined on window, so window[className] is undefined. I do not know where my function is defined in SAPUI5
A second Solution:
eval(`a = new ${oModelConf[sModelName].type || "sap.ui.model.odata.ODataModel"}(sServiceUrl, true);`);
This is not a better solution because we should not use eval().
Are there any better solutions?
EDIT2
Because of the url in pimskies answer I found an other solution:
Since window.sap.ui.model.odata.ODataModel is the same as sap.ui.model.odata.ODataModel and window.sap is the same as window[sap]
I could take my string, and replace all . with ][, put the right brackets to front and end.
I will not code that because it is not a going solution.(I should not have coded the evalthing too...)
You could use jQuery.sap.getObject to access the class:
var ModelClass = jQuery.sap.getObject(oModelConf[sModelName].type || "sap.ui.model.odata.ODataModel");
var model = new ModelClass();
Edit: An other way (which i would recommend if you use AMD)
If you are using the modern AMD modules and you don't know if the module containing your class has already been loaded, you should use sap.ui.require() to load the module asynchronously. It requires the module to be specified via its unified resource name (the conversion is probably the most ugly part):
var className = oModelConf[sModelName].type || "sap.ui.model.odata.ODataModel";
var urn = className.replace(".", "/"); //Convert to unified resource name
sap.ui.require([urn],function(ModelClass){
//This function is called when the module is available
var model = new ModelClass();
...
});
Maybe map the string to a class?
function Foo() {
console.log('new foo');
}
function Bar() {
console.log('new bar');
}
var objects = {
'foo': Foo,
'bar': Bar
};
var cls = objects.foo || Bar;
new cls();
https://jsfiddle.net/ckd56d9v/1/
Or take a look at this answer: https://stackoverflow.com/a/9804142/5930258
What not combine the two? Since window[className] is failing, replace it with
oModelConf[className].type || sap.ui.model.odata.ODataModel...
function instantiate(className, args) {
var o, f, c;
c = oModelConf[className] || sap.ui.model.odata.ODataModel;
f = function(){}; // dummy function
f.prototype = c.prototype; // reference same prototype
o = new f(); // instantiate dummy function to copy prototype properties
c.apply(o, args); // call class constructor, supplying new object as context
o.constructor = c; // assign correct constructor (not f)
return o;
}
I'm kind of new to javascript. I'm so confused that javascript Objects!!
My code skeleton is bellow...
var jCanvas = new function(){
this.init = function(canvasID){
...
};
var DrawingManager = new function(){
drawInfos = []; // DrawInfo objects will be pushed into this
this.mouseState = MouseState.released;
...
};
function DrawInfo(bm, cl, id, x, y){
...
}
function Point(x, y){
...
}
var MouseState = new function(){
...
};
var Color = new function(){
...
};
var BrushMode = new function(){
...
};
};
I want jCanvas to be singleton class Object.
in jCanvas object, there are many singleton classes such as DrawingManager, MouseState, Color, BrushMode. And 2 more classes which are not singleton classes(Point, DrawInfo)
What I want is that, in DrawingManager, I want to access other classes and singleton class objects.
Problem is browser gives error that "MouseState is undefined".
I think I'm too familiar with Java, C# etc... I want my program to have good structure but this javascript make me so confused and don't know how to make good design pattern..
Please help me out..
To declare functions, don't use the new keyword. Only use it when creating instances of objects.
In JavaScript, you can declare a "class" like this (the body of the function is the constructor):
function MyClass (arg1) {
this.myClassProperty = arg1;
}
And then instantiate it:
var myObj = new MyClass();
If you want to create a singleton, the best method is to use an immediately invoked function:
var MySingleton = (function() {
var myPrivateFunction = function() { ... };
var myExportedFunction = function() { ... };
var myPrivateVar = 5;
return {
myExportedFunction: myExportedFunction
};
})();
Here, you create an anonymous function and immediately run it. It is kind of a more advanced concept though.
Or you can simply create an object:
var MySingleton = {
myProperty: 1,
myFunction: function() { ... },
...
};
Singleton classes in JavaScript make no sense. Either make a constructor ("class" for Java people) to instantiate multiple objects, or make an object. There is no point in making a constructor that you will only ever use once, then have the code to sanity-check whether or not you actually do use it only once. Just make an object.
The reason for the error is probably (but I might be wrong, I'm guessing about the rest of your code) the misunderstanding between var x = function ... and function name() ... forms. To whit:
var a = function() { console.log("a"); }
function b() { console.log("b"); }
a(); // a
b(); // b
c(); // c
d(); // TypeError: d is not a function
function c() { console.log("c"); }
var d = function() { console.log("d"); }
They are identical in effect, but they differ in whether they are hoisted to the top of the scope or not. var d is hoisted, just like function c() { ... } - so the variable d will exist, but will be undefined, since the assignment is not hoisted. Having both styles of function declarations is inconsistent unless you have a good reason for it; pick one of them and stick to it, is what I'd recommend.
May I ask how can I call function c on below situation?? Thank you very much for your advice.
var Foo = function(el){}
Foo.prototype.d = function(){
// I want to call function c here, how can I do??
};
$.fn.a = function(){
return {
b: new Foo(this)
};
};
$.fn.a.prototype.c = function(){ alert(1); }; //function c
$(el).a().b.d() <-reach c...
You don't have an instance of a that was constructed with the new keyword. So you will have to use call or apply.
Foo.prototype.d = function(){
$.fn.a.prototype.c.apply(this, arguments);
};
This will run c on the Foo instance - is that what you want? If you just want to call the function without an specific execution context you can use $.fn.a.prototype.c().
This probably isn't the best way to architect this - if you want to call it as a member function of Foo don't add it as a member function of $.fn.a.
I'm a little confused over a line of JavaScript code that I came across and I'd like to understand its purpose:
(function ($, window) {
var example;
example = function (a, b, c) {
return new example.fn.init(a, b, C);
};
example.fn = example.prototype = {
init: function (a, b, c) {
this.a= a;
this.b= b;
this.c= c;
}
};
example.fn.init.prototype = example.fn; //What does this line accomplish?
$.example = example;
}(window.jQuery, window));
As I understand it, the line in question is assigning the prototype of a child object to itself, which effectively is the prototype of the base example object... Why might one want to do this?
The code sample in your question implements a multi-purpose function/object the same way jQuery does with its jQuery (usually aliased to $) object.
Objects created with the example() function are actually instantiated by the example.fn.init() constructor. Assigning example's prototype to example.fn.init's ensures the members exposed by example are also exposed by objects instantiated by init().
The relevant parts of the jQuery source are:
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
}
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
// Actual implementation of the jQuery() function...
}
// Other jQuery.fn methods...
};
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
It looks like the whole definition of example.fn is entirely useless. (Maybe it's intended to mimic the jQuery fn object?)
It seems that the author wanted that these following calls would produce the same results:
var x = $.example(a, b, c); // Build by function call
var y = new $.example.fn.init(a, b, c); // Build by a constructor call
As example and example.fn.init have the same prototype, x and y defined above would have the same interface. In a cumbersome way, IMO.
It's possible to enforce a "constructor-like" behavior in a function call using a simpler syntax (also known as a self-invoking constructor pattern):
function example(a, b, c) {
if (!(this instanceof example)) {
return new example(a, b, c);
}
this.a = a;
this.b = b;
this.c = c;
}
var x = example(a, b, c); // Constructor invoked by function call
var y = new example(a, b, c); // Constructor invoked explicitly
I am mlearning javascript and have some trouble creating an onject via prototype.
I have this:
<script type="text/javascript">
function myclass(a, b, c) {
if (arguments.length) { this.Init(a, b, c); }
}
myclass.prototype.Init = function(a, b, c) {
this.param1 = a;
this.param2 = b;
this.param3 = c;
};
myclass.prototype.Print = function() {
alert(this.param1 + '-' + this.param2 + '-' + this.param3);
};
var myObject = myclass(3, 5, 6);
myObject.Print();
</script>
but I get an error on line with this.Init(a, b, c);
Error: Object doesn't support this property or method
You forgot the new keyword when you declare myObject:
var myObject = new myclass(3, 5, 6);
Just out of curiosity is there a particular reason you have a separate "init" method?
The function that defines your "class" is called the "constructor" and you can just perform the setup there. If you wanted to "re-initialize" the object, then it may be helpful but it doesn't seem to serve a point here.
For instance:
// You might as well start wrapping your code now:
var myExample = (function myExample () {
// A common convention is to start the name of constructors with a
// capital letter, one reason is it help makes it more obvious
// when you forget the new keyword...Whether you use it or not
// is up to you. Also note, calling it "MyClass" is a little
// misleading because it's not a "class" really. You might
// confuse yourself if you think of it as a class too much.
// If you're wondering why I put the name twice, it's because
// otherwise it would be an anonymous function which can be
// annoying when debugging. You can just use var MyClass = function () {}
// if you want
var MyClass = function MyClass(a, b, c) {
// This will set each parameter to whatever was provided
// or if nothing is provided: null. If you leave out
// the || "" part then any
// time a value is not provided the parameter will
// return "undefined". This may be what you want in some cases.
this.param1 = a || "";
this.param2 = b || "";
this.param3 = c || "";
};
// likewise it's convention to start most variables/functions lowercase
// I think it's easier to type/looks better, but do as you please.
MyClass.prototype.print = function print() {
alert(this.param1 + '-' + this.param2 + '-' + this.param3);
};
var myObject = new MyClass();
myObject.print();
}());
The "wrapping" is
(function () {
//your code here
}());
It's mostly pointless here, but it's something you'll have to start doing eventually so might as well start now. That's just one way to "wrap" there are others as well.
Basically, the way your script was written, if the user ran another script that had a function called MyClass, it could overwrite yours or vice versa, causing problems.
The "wrapping" keeps it all within that function. If you need to make something available to outside stuff, you can expose it.
per comment:
You can access functions and variables from inside the wrapper by exposing them to the outside like so:
var myApp = (function myApp(){
// The constructor for our "class", this will be available from outside because
// we will expose it later
var myClass = function(){
//code to set up "class" etc
// See how we can use private function within myApp
privateFunction();
};
// Here we set up the private function, it will not be available outside myApp
// because will will not expose it
var privateFunction = function(){ };
// Another public function that we will expose later
var otherPublic = function(){};
//now we expose the stuff we want public by returning an object containing
// whatever it is we want public, in this case it's just myClass and otherPublic
return { myClass: myClass, otherPublic: otherPublic };
}());
Note in that example we are just exposing the constructor, if you wanted instance of the object
you'd have to collect them in a variable and expose that variable like:
var theInstance = new myClass();
return { theInstance : theInstance };
It would now be available outside myApp as myApp.theInstance
You can also use a more basic wrapping scheme:
var myApp = {
myClass: function(){
//if we want to call another function in myApp we have to do it like so:
myApp.publicFunction();
},
publicFunction: function(){},
someString: "this is a string"
};
There myApp is just an object literal containing your functions etc. The main difference is that EVERYTHING in myApp can be accessed from outside via myApp.name or myApp[name];