Is it possible to add instance methods to all "classes" in JavaScript? - javascript

This is more of an exploratory question, seeing how the core JavaScript stuff works. I realize the convention is to not override any core JavaScript classes, but I just can't seem to wrap my head around this one.
You can create what acts like "class methods" in JavaScript by adding to the core Function prototype like this:
Function.prototype.class_method = function() {
console.log("class method called")
}
var User;
User = (function() {
function User() {}
return User;
})();
User.class_method(); // "class method called"
My question is, is there a way to add "instance methods" in a similar way? Something crazy like this, but what's below doesn't work (or make any sense):
alias = Function.prototype.constructor;
Function.prototype.constructor = function() {
child = this;
child.prototype.instance_method = function() {
console.log("instance method called");
}
alias.apply(child);
}
var user = new User();
user.instance_method(); // method doesn't exist
It's almost like you'd need to override the Function class' constructor method and access the prototype from there. Is this possible?
It does work if you add to the Object.prototype like this:
Object.prototype.instance_method = function() {
console.log("instance method");
}
var user = new User();
user.instance_method(); // "instance method called"
But that doesn't seem right either, mainly because seeing the output in the node.js console from console.log({}); change is confusing:
console.log({});
// {};
Object.prototype.instance_method = function() {
console.log("instance method");
}
console.log({});
// {"instance_method": [Function]}

If you are using node.js, you should be able to use Object.defineProperty [MDN] and make the new property non-enumerable:
Object.defineProperty(Object.prototype, 'instance_Method', {
value: function() {
console.log("instance method");
},
enumerable: false // it's already the default
});
This was introduced in ECMAScript5, so only newer browsers will support it.

It's important to understand when the prototype comes into play. It's simply an object that is a property of a function. It only has meaning when you use the new keyword. Example:
var Widget = function(val) {
this.value = val;
};
Widget.prototype.getValue = function() {
return this.value;
};
var widget1 = new Widget('test');
widget1.getValue(); // test
var widget2 = new Widget('test2');
widget2.getValue(); // test2
When new is used, the js interpreter will create a hidden _proto_ property on the instance. This proto link is simply a reference to the prototype object of the constructor function, e.g., Widget at the time the constructor was called.
When you override the Function constructor, you are literally adding something that will be on the _proto_ property of every function created after you modified Function.prototype.
If you make the statement child.prototype... = ... in your base 'class' constructor function, then that prototype will not have meaning until something 'instantiates' child, e.g., var child = new child();.
A great Resource.
To answer your question about 'instance methods', you simply need to do something like the following:
var Widget = function() {
this.method = function() {
return 'instance method';
};
};
Widget.prototype.method = function() {
return 'class method';
};
var widget1 = new Widget();
widget1.method(); // instance method
delete widget1.method;
widget1.method(); // class method
This is due to javascript's implementation of Prototypical Inheritance. The proto link I spoke of before is key here. When widget1 was first created, inside the constructor function Widget, method was attached specifically to widget1. This method will not be available to other instances. However, method on the prototype is shared across all instances of Widget.
At runtime, when the js interpreter sees widget1.method();, it first sees if widget1 has method as a property directly on it (objects in js are just hashmaps in essence, in which the keys are called 'properties'). It finds the instance method as a property in this case. However, once you delete the instance method, it will attempt to follow the _proto_ link, which is just an object reference to Widget.prototype (at the time the constructor was called). Widget.prototype.method is defined; therefore, the interpreter will execute that. If no method function is found when continuing to follow _proto_ links, it'll be a run-time error.

Related

Constructor and prototypes in javascript

I'm reading a snippet of code that defines a constuctor
var Resource = function(data) {
angular.extend(this, data);
}
and then subsequently defines a method to it.
Resource.query = function(url) {
console.log(url);
}
Can I ask how this works? I know functions are objects as well, and is this the equivalent of the following? But if so, then what happens to the constructor function?
var data = {};
data.query = function(url) {
console.log(url);
}
Also, why wouldn't we simply define it on the prototype instead?
Resource.prototype.query = function(url) {
console.log(url);
}
http://jsfiddle.net/HPg6A/
You would define methods on the prototype only if they are meant to be called on specific instances. When methods are defined directly as constructor members, it's usually to mimic static methods.
Basically, when a method relates very closely to a class, but doesn't make much sense as an instance method, it can be implemented as a static method.
I think that you will agree with me that the second example makes more sense and if you do, you already understood the difference.
1-
var user = new User();
user.findUser('somequery').then(...);
2-
User.findUser('somequery').then(...);
I know functions are objects as well, and is this the equivalent of the following
There's nothing more to what you say. It's just like any other property on any other object.
Also, why wouldn't we simply define it on the prototype instead?
The difference is that each object created using the constructor would then have that method in their prototype chain. This isn't true for properties defined on the constructor itself.
That is:
var Resource = function() {}
Resource.one = function() {
console.log("one");
}
Resource.prototype.two = function() {
console.log("two");
}
var r = new Resource();
r.two(); // => "two"
r.one(); // => TypeError: r.one is not a function
And:
Resource.one(); // => "one"
Resource.two(); // => TypeError: Resource.two is not a function
You might call one a static method, but the language doesn't treat it differently than any other function (unlike methods defined using, say, static in Java).

MooTools get Classname in Class (not CSS)?

I'm using the JavaScript Framework MooTools in which it is possible to create classes similar to Object-Orientation.
I dont know if it is somehow possible to alert the classname 'TestClass' within the class.
var TestClass = new Class({
Extends: Module,
initialize: function() {
//constructor which is called and should alert the Classname itself
alert(this.classname); (pseudocode)
}
});
Someone has an idea?
Thx in advance!
This is pretty easy as a workaround but a Class can be anonymous (like a function) and reflection is meaningless then.
Compare the(a) host object's enumerables with the instance's constructor. Not a cheap thing but still. Won't work very well if you use deep namespaces, for example: window.App.admin.controllers.view.Login since you'd need to either recursively look for it or know it's hosted by window.App.admin.controllers.view
// define the class in the current scope / global object
this.foo = new Class();
// directly into scope
var Foo = new Class();
// define the class in a namespace
var namespace = {
bar: new Class()
};
// get the variable class name we need to use from any source into a variable...
var dynamic = 'foo';
// make the instances
var instance1 = new this[dynamic]();
var instance2 = new namespace.bar();
var instance3 = new Foo();
function getClassNameOfInstance(mootoolsClassInstance, context) {
// query the context (this or custom object) for the instance we are working with
return Object.keyOf(context || this, mootoolsClassInstance.constructor);
}
// use it on the global object
console.log("instance1 is: ", getClassNameOfInstance(instance1)); // foo
// use it on the namespace object
console.log("instance2 is: ", getClassNameOfInstance(instance2, namespace)); // foo
// use it on the current scope.
console.log("instance3 is: ", getClassNameOfInstance.call(this, instance3)); // Foo
see it work here: http://jsfiddle.net/dimitar/c8pR4/
here is an example anonymous Class, a useful pattern if you don't plan on instantiating something more than once:
var instance = new (new Class({ ... }))(args);
I did write about this a while ago - http://fragged.org/working-with-dynamic-class-names-in-mootools_1395.html
A better / more sensible approach will be to manually give IDs to all Classes that need them, eg:
var Request.CORS = new Class('Request.CORS', { ... });
var i = new Request.CORS();
i.$className; // 'Request.CORS'
this is a pattern common in AMD (define('id', [deps], fn)), DOJO (declare('id', [deps], obj)) etc.
To extend your MooTools to support that you could do something like this:
http://jsfiddle.net/rnbW6/5/ - which will add a Request.JSON.prototype.$className property or getter (via Object.defineProperty config if avail).
If you go that route, you can even do a Class factory so your dependency resolution can be like Class.require('Request.CORS') and you won't ever need to save your definitions into global variables outside of the reference in your Class closure.

jQuery Pattern - is this valid or is there a better way?

I've sort if fell into this organization of javascript and was wondering if I'm missing the point somewhere here, or if there's a more elegant way of doing this.
Basically I'm wrapping everything in a function (object) and then setting up methods on that object, then instantiating an instance of the wrapper object and passing in any options and dependencies.
I have a hunch there's a way to automatically run .init() and a few other tweaks that could be made. Am I doing it right?
function AppModuleCore(){
var AppModuleCore = this; //keep internals sane
// Various global vars, objects
AppModuleCore.defaultOptions = {};
AppModuleCore.init = function(opts) {
// todo: that thing where you extend an options object a la juery
AppModuleCore.bindEvents();
};
AppModuleCore.bindEvents = function() {
// bind events here, send to functions within AppModuleCore.<FUNCTIONNAME>();
// Example:
$("a#clicker").unbind("click");
$("a#clicker").click(function(event){
AppModuleCore.handleClickerClick(event);
});
};
AppModuleCore.handleClickerClick = function(event){
alert("clicker was clicked");
};
}
// --------------------------------------------------------------------
// instantiate AppModuleCore object and initialize with opts,
// dependency injection
// --------------------------------------------------------------------
$(document).ready(function(){
AppModuleCore = new AppModuleCore;
var options = {};
AppModuleCore.init(options);
});
OK, some points
Having your code wrapped in a constructor only really makes sense if
You're going to instantiate more than one
You have "public" methods on the object that you are going to call
Your code doesn't exhibit these characteristics. I say this because your jQuery selectors a#clicker are hard coded so I'm assuming that you wouldn't want to bind the same events to them more than once?
You'd be better off using a function (perhaps your init) or an object literal to limit your scope..
function init( options ) {
var defaultsOptions = {};
var privateVar = 'only in this scope';
//extend your default options with options here
//using jquery
options = $.extend( defaultOptions, options );
// this function is completely private to this scope
function privatefunction() {
//do stuff
}
function handleClickerClick( event ){
alert("clicker was clicked");
}
// you don't need to wrap your handler in an anonymous function unless
// you're doing some work to the event before forwarding:- just give a
// reference to your handler
// the handler has access to other members of this scope, we're in a closure
$(options.selector).click( handleClickerClick );
//etc
}
init( {selector: 'a#clicker'} );
On a stylistic note: when you alias this with the same name as the constructor and then add methods to the alias, it looks at first glance like you are adding static methods to the constructor. This may be confusing to someone who looks at your code later and doesn't notice the alias.
function C() {
// a static method i.e a property of the constructor, C not objects created with it
// it is a bit wierd that it is defined in the constructor but not unheard of
C.staticMethod = function(){};
//quite plainly a method of objects of this type, easy to understand
this.method = function(){};
}

Properties attaching to wrong object

I've adapted the Crockford object() function so that I can pass in some parameters and autorun an init function in the new object:
function object(o) {
function F() {}
F.prototype = o;
var params = Array.prototype.slice.call(arguments,1);
var obj = new F();
if(params.length) {
obj.init.apply(obj,params);
}
return obj;
}
This works fine most of the time, but within one object I have functions defined as follows:
MY.Object = function() {
function init(element, generator) {
build(element);
// more code after
}
function build(element) {
this._property = "example";
}
return {
init: init;
}
}();
If I then run
My.Object2 = object(MY.Object, "test param");
For some reason _property gets added to the Windows object. This stops if I make build a public method and call it using this.build().
Can anyone explain why this happens?
build, although you've defined it within your class, has no context when you're calling it. So, no context means that this references your window object (within a browser, at least). But, even though you don't have the proper this context, you can still access your variables you've declared within the "private" scope of your class.
Try using build.call(this, element) (function.call is similar to function.apply).
Just know that JavaScript doesn't quite behave the same way as other OO languages you may have used, and that classes, and the notion of private and public (among other language features) are a bit of a hack.

Javascript plugin creation

I want to create a plugin called 'myPlugin'. Which method should I use and what is the difference between these two methods? Please tell me the advantages too. I am from designing background and not much programming knowledge.
var myPlugin = {
myId:"testId",
create:function(){},
destroy:function(){}
}
OR
function myPlugin() {
this.myId = "testId";
this.create = function(){};
this.destroy = function(){};
}
The first method creates a singleton object, stored in a variable called myPlugin. Only one instance of the "plugin" exists in this form. If you know you will only need one instance, this approach is a good choice. You can also extend its capabilities to allow for both public and "private" properties by using the Module Pattern.
The second method defines an object constructor function, which will allow you to make multiple instances of the object using the new keyword. This will allow you to use as many copies of the object as you might need, and sets you up with the ability to add onto the object using its prototype.
I would go for something like:
function myPlugin () {
this.myId = "testId";
this.create = createFunction;
this.destroy = destroyFunction;
}
function createFunction() {
alert('createFunction() called');
}
function destryFunction() {
alert('destroyFunction() called');
}
my plugin = new myPlugin();

Categories