I was reading Prototypes in javascript and I have written 2 small js codes which are outputting exactly same. I just want to know what is the difference between them:
Code 1:
String.sam = function() { alert('fine') };
'ok'.sam();
Code 2 with prototype:
String.prototype.sam = function() { alert('fine') };
'ok'.sam();
Please clarify the difference and the better way to use the code.
Thanks
Your first example doesn't work. What you are doing is creating a static method on the string object so you would have to call it statically
//OK
String.sam();
//not OK, raises error
'hello'.sam();
In your second example the keyword this will refer to the instance of the string you call it on. So you can do something like
String.prototype.sam = function() {
console.log( this.toUpperCase() );
}
'hello'.sam(); // HELLO
This technique, although powerful is frowned upon in certain quarters. It is known as Guerrilla patching, Monkey punching or similar things.
There are a few reasons it is considered bad:
Hard to debug (you've changed the language)
Easy to break other code on the page that is not aware you've altered a prototype
Possible clashes with future enhancements of the core.
Probably lots more
I think, your first method adds only for this special property the alert() method. If you want create another instance, you have to do the same thing again. With protoype you define it more generally so you don't have to do the same thing again for another instance.
Perhaps http://www.javascriptkit.com/javatutors/proto.shtml will help you to understand it better.
Related
I just want to make sure I understand this basic idea correctly, and no matter how I phrase it, I'm not coming up with completely relevant search results.
This is faster:
function () {
$('#someID').someMethod( $('#someOtherID').data('some-data') );
}
than this:
function () {
var variableOne = $('#someID'),
variableTwo = $('#someIDsomeOtherID').data('some-data');
variableOne.someMethod( variableTwo );
}
is that correct?
I think the question may be "Is declaring variables slower than not declaring variables?" :facepalm:
The particular case where I questioned this is running a similarly constructed function after an AJAX call where some events must be delegated on to the newly loaded elements.
The answer you will benefit from the most is It does not make a difference.
Declaring variables and storing data in them is something you do so that you do not have to query that data more than once. Besides this obvious point, using variables rather than chaining everything into one big expression improves readability and makes your code more manageable.
When it comes to performance, I can't think of any scenario where you should debate declaring a variable or not. If there's even an absolute difference in speed, it would be so small that you should not see this as a reason to not use that variable and just leaving your code to becoming spaghetti.
If you want to use the element $('#someID') again and again
Then decelaring variable would be useful and caching $('#someId') is recommended.
var x = $('#someId')'
I've recently been playing with javascript, HTML5, chrome extensions, jQuery, and all that good stuff. I'm pretty impressed so far with the possibilities of javascript, the only thing I struggle with is structuring my code and keeping it tidy. Before I know it, functions are scattered all over the place. I've always done my programming in an object oriented manner (C++ and C#), and I find myself not being able to keep things tidy. It feels like I always end up with a bunch of static util functions, were I to 'think' in C#.
I've been looking for some information on objects in javascript, but it seems to come down to wrapping functions in functions. Is this a good way of structuring your codebase? On the surface it seems a bit hackish. Or are there other ways of keeping things tidy for an OO mindset?
One important aspect to remember about Javascript is that it is a prototypical language. Functions can be objects, and anything can be put on the object, often affecting related objects in the process. There's no official way to 'extend' an object because of this. It's a concept that I still have a hard time understanding.
Javascript 'acts' like any other OOP language for the most part, with some exceptions, namely extending objects (http://jsweeneydev.net84.net/blog/Javascript_Prototype.html).
After extensive research, I did find a very, very light-weight way to simulate expanding objects (I'm using using it in my GameAPI). The first field is the parent object, the second is the object that expands.
extend : function(SuperFunction, SubFunction) {
//'Extends' an object
SubFunction.prototype = new SuperFunction();
SubFunction.prototype.constructor = SubFunction;
},
This link might clear up some problems and misconceptions:
http://www.coolpage.com/developer/javascript/Correct%20OOP%20for%20Javascript.html
Personally, I tend to be anti-framework, and I haven't seen a framework yet that doesn't force the programmer to significantly change their programming style in this regard anyway. More power to you if you find one, but chances are you won't really need one.
My best advise is to try to adapt to Javascript's prototypical style, rather than force old methodologies on it. I know it's tricky; I'm still trying to myself.
Best of luck diggingforfire.
I generally follow the make-an-anonymous-function-then-call-it pattern. Basically, you create an inner scope and return a single object containing your interface. Nothing else escapes, because it's all trapped within the function scope. Here's an example using jQuery:
var FancyWidget = (function($) {
// jQuery is passed as an argument, not referred to directly
// So it can work with other frameworks that also use $
// Utility functions, constants etc can be written here
// they won't escape the enclosing scope unless you say so
function message(thing) {
alert("Fancy widget says: " + thing);
}
// Make a simple class encapsulating your widget
function FancyWidget(container) {
container = $(container); // Wrap the container in a jQuery object
this.container = container; // Store it as an attribute
var thisObj = this;
container.find("#clickme").click(function() {
// Inside the event handler, "this" refers to the element
// being clicked, not your FancyWidget -- so we need to
// refer to thisObj instead
thisObj.handleClick();
});
}
// Add methods to your widget
FancyWidget.prototype.handleClick = function() {
this.container.find("#textbox").text("You clicked me!");
message("Hello!");
};
return FancyWidget; // Return your widget class
// Note that this is the only thing that escapes;
// Everything else is inaccessible
})(jQuery);
Now, after all this code executes, you end up with one class, FancyWidget, which you can then instantiate.
You can define multiple classes this way too; instead of using return FancyWidget, you can return an object literal instead:
return {
FancyWidget: FancyWidget,
Frobnicator: Frobnicator,
// Nested namespaces!
extra: {
thing: thing,
blah: blah
}
};
One of the best OOP javascript libraries out there is Google's Closure library http://closure-library.googlecode.com/svn/docs/index.html
It's structured in a way that OOP programmers will be familiar with especially if you come from a java/C# background. Have a look at the source code of any file and it should feel right at home as an OOP programmer. http://closure-library.googlecode.com/svn/docs/closure_goog_graphics_canvasgraphics.js.source.html
I have never used this personally, but have seen backbone.js referenced many times to this question. See at: http://documentcloud.github.com/backbone/
Using some framework designed to meet similar requirements may be a good idea.
But there are some things you should really follow to be efficient:
remember about closures in JavaScript and do not forget about var keyword,
use callbacks where possible and reasonable, JavaScript is asynchronous by nature,
I am creating an object inside of an enclosure. Also in the enclosure are private properties that the object's functions can access - and this works as expected.
My issue: I want others to be able to extend my object with functions of their own (functions from a different context), but those functions will also need access to the same private properties - and I have not been able to find a way to make this work.
I've tried various configurations of .call, and also wrapping their function in a new function, amongst other things. I feel like I've gotten close to a solution, but have just fallen short.
Here's a bit of simplified example code that accurately reflects my situation:
//extension object
//fn2 can be any function, with any number of arguments, etc.
var obj1 = {};
obj1.fn2 = function (s1, s2){ console.log(priv); };
//actual object
var obj2 = (function (){
//private property
var priv = "hello world";
//return object
var obj3 = {};
//return object's native fn (works)
obj3.fn = function (s){ console.log(priv); };
//extension happens here - but is obviously not correct
obj3.fn2 = obj1.fn2;
//return object
return obj3;
})();
//try output
obj2.fn("goodbye world"); //works
obj2.fn2("goodbye world", "thx 4 teh phish"); //fails
Any insight would be appreciated. And I totally understand if what I want just isn't possible - but it sure seems like it should be :P
EDIT: Thank you all for the responses. I fully understand that the properties are more easily accessed as public, and that normally inherited objects won't have access to them otherwise. However, since the new function is being attached to the original object I have to believe there's a way to use the original context and not the context the new function was created in.
Now, I'm the first to say that eval is evil - and, in fact, I've never used it, or even considered using it, before. However, I'm trying everything I can think of to make this work - and I stumbled across this (seemingly) working solution:
obj3.fn2 = eval(obj1.fn2.toString());
So, if I check to make sure that obj1.fn2 is a typeof function, is there any way this could be harmful to my code? It doesn't execute the function, so I can't see how - but maybe I'm missing something?
Javascript doesn't have a "protected" analog. You either get super private or completely public. From here you can choose to:
Reconsider your class design, and have the subclasses depend only on the public interface of the parent class.
Add getter and setter functions to the public interface. Not necessarily the best thing though as you might just as well make the properties public (besides best practice issues and whatnot)
Just use public properties instead. This is the "natural" way to do OO inheritance in Javascript and is usually not a problem if you use a donvention like adding an underscore to the beggining of the name. As a bonus you can use the prototypal inheritance feature (it is nice knowing how to use this instead of only closure-based classes)
function Base(){
this._priv = "Hello world"
};
Base.prototype = {
fn: function(){
console.log(this._priv);
}
}
var obj2 = new Base();
obj2.fn = function(){ ... }
I hate to answer my own question - seems like a bit of a faux pas - but c'est la vie. (because I woke up French today?)
So, while I found that the eval() solution I presented last night in the edit to my original question does seem to be a valid solution, and a proper use of eval for retaining the object's context within the new function, it is far from perfect.
Firstly, it works in FF, but both IE and Chrome seem to hate it (those were the next ones I tried, and I quit trying others after they both failed). Though I'm sure it could probably be made to work across browsers, it seems like a hassle.
Secondly, it does give quite a bit of power to the new function, and as I look at my code more I do like the idea of controlling exactly what these new functions being added to my object get access to.
Thirdly, .eval() is typically pretty slow - and it turns out that .apply() (which is typically faster) just may work well enough.
This is because I realized at some point last night that no new functions on this object will need to set any of the private variables (at least, I'm fairly certain they won't) - and .apply() works fine to pass the values through for them to read.
I'm sure there's more to it than just those 3 things, but for now I think I'm going to go with more of a 'wrapper' solution - something like this:
var f = function (){
var fauxThis = {};
fauxThis.priv = priv;
obj1.fn2.apply(fauxThis, arguments);
};
obj3.fn2 = f;
//(To be placed where I had "obj3.fn2 = obj1.fn2;")
I am certainly willing now to consider the use of eval() in very specific cases - and may even revisit this specific use of it before I make my final decision of which direction to take. (especially if I can think of a case where the private value would need to be set)
Thanks all for your input!
The quickest and easiest solution is to prefix any supposedly private properties with the underscore (_).
Personally I like to bottle my private properties into a single object which would be placed on the object, like so:
obj.publicProp = 20;
obj._.privateProp = true;
I wouldn't worry so much about it though, the underscore is basically a universal symbol for private so those using the script will know that it's private and shouldn't be touched. Or, better yet, just leave it out of the public documentation ;)
There are other methods and you can use which do emulate "true" protected variables, but they're not the best as they avoid garbage collection, and can be clunky to use.
Adding methods to native JavaScript objects like Object, Function, Array, String, etc considered as bad practice.
But I could not understand why?
Can some body shed light on this?
Thanks in advance.
Because you might happen to use a library that defined a function with the same name, but working another way.
By overriding it, you break the other's library's behaviour, and then you scratch your head in debug mode.
Edit
If you really want to add a method with a very unpleasant name like prependMyCompanyName(...) to the String prototype, I think it's pretty much risk-free from an overriding point of view. But I hope for you that you won't have to type it too often...
Best way to do it is still, in my humble opinion, to define for example, a MyCompanyUtils object (you can find a shortcut like $Utils), and make it have a prepend(str,...) method.
The two big reasons in my opinion are that:
It makes your code harder to read. You write code once and read it many number of times more. If your code eventually falls into the hands of another person he may not immediately know that all of your Objects have a .to_whatever method.
It causes the possibility of namespace conflicts. If you try to put your library which overrides Object.prototype into another library, it may cause issues with other people doing the same thing.
There is also the effect that augmenting the Object prototype has on for...in loops to consider:
Object.prototype.foo = 1;
var obj = {
bar: 2
};
for (var i in obj) {
window.alert(i);
}
// Alerts both "foo" and "bar"
In the ASP.NET ajax library, there is a line that makes me confused.
Type.prototype.registerClass = function Type$registerClass(typeName, baseType, interfaceTypes) {
//..
this.prototype.constructor = this;
//..
}
I know that (this.prototype.constructor === this) == true, so what is significance of this line? I remove the line, and test the library with some code. It seems it is okay. What is the purpose of this line?
I'm not familiar with the asp.net libs, but:
A common pattern in Javascript, especially when trying to simulate class based systems, is to reassign the prototype object to an instance of another object, rather than just adding properties to the prototype object JS gives you. One issue with this is that it gives you the wrong constructor - unless perhaps one resets with a 'correct' value.
My guess would be that at some point before this.prototype.constructor = this;, some object was assigned to the prototype property, which overwrote prototype.constructor. This trick is often used when inheriting object prototypes easily, but still being able to call instanceof to see whether an object instance is of a certain type.
Hard to tell anything more specific than that in this case and a seriously old question, however it might be useful to somebody.