Defining custom objects and functions in JavaScript (Part 2) [duplicate] - javascript

This question already has answers here:
How to execute a JavaScript function when I have its name as a string
(36 answers)
Closed 8 years ago.
Based on a question I asked prior to this, how would I qualify this string...
"MyCustomObject.prototype.foo.bar"
to this:
window['MyCustomObject']['prototype']['foo']['bar']
in object form? (it must not qualify to...
"window['MyCustomObject']['prototype']['foo']['bar']"
...as a string!).
As a reference, consider the following...(the code is wrong...it needs fixing (without the eval keyword))
var fn = "MyCustomObject.prototype.foo.bar";
var ptr = fn.split('.');
var ptrPath = 'window'
for(var index = 0; index < ptr.length; index++) {
ptrPath += '[\'' + ptr[index] + '\']';
}
ptrPath = function() {
alert("Hello");
}
should resolve to this;
var inst = new MyObject();
inst.foo.bar(); //alerts...."Hello"

I modified the answer in this question to suit your needs.
var getPropertyByName = function (fullString, context) {
var namespaces = fullString.split(".");
var functionName = namespaces.pop();
for (var i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
return context[functionName];
};
getPropertyByName('MyCustomObject.foo.bar', window);
http://jsfiddle.net/jbabey/4GVUK/

You could try this way:
var fn = "foo.prototype.bar";
var ptr = fn.split('.');
var func = ptr.reduce(function(a, b){
return a[b] ? a[b] : a;
}, window);
The working demo.

Finally after much effort, I have figured out the solution.
The idea behind the Object.implement function is to allow a developer to:
Define an object/function by name (E.G. "Custom" or "Custom.prototype.foo.bar"), regardless of that objects existence.
Define the object/functions context (E.G window)
Define the object/function implementation
define whether to override the object/function if an implementation already exists.
Consider the Object.implement code sample:
Object.implement = function(fn, context, implementation, override) {
var properties = fn.split('.');
var fnName = properties.pop();
for(var index = 0; index < properties.length; index++) {
if(!context[properties[index]]) {
context[properties[index]] = { };
}
context = context[properties[index]];
}
if(!context[fnName] || override) {
context[fnName] = implementation;
}
};
I can now use this to safely create/implement objects and functions. Consider this a bit like a "shim" feature, where if a function does not exist, an implementation can be provided, however with the added functionality that existing functionality can be over-ridden as well:
Object.implement("HashTable", window, function() { }, true);
Object.implement("HashTable.prototype.bar", window, function() { alert("Hello World") }, true);
var ht = new HashTable();
ht.bar();
It works in FireFox...I have yet to test in other browsers!

Related

Is multiple inheritance possible in javascript? [duplicate]

This question already has answers here:
does javascript support multiple inheritance like C++
(4 answers)
Closed 9 years ago.
I have a situation here. I have two modules(nothing but javascript function) defined like this:
Module1:
define(function(){
function A() {
var that = this;
that.data = 1
// ..
}
return A;
});
Module2:
define(function(){
function B() {
var that = this;
that.data = 1;
// ...
}
return B;
});
How to inhert both modules inside other module?
1) In js everything is just an object.
2) Javascript inheritance uses prototype inheritance and not classic inheritance.
JavaScript doesn't support multiple inheritance.
To have both of them inside the same class try to use mixins that are better anyhow:
function extend(destination, source) {
for (var k in source) {
if (source.hasOwnProperty(k)) {
destination[k] = source[k];
}
}
return destination;
}
var C = Object.create(null);
extend(C.prototype,A);
extend(C.prototype,B);
mixins:
http://javascriptweblog.wordpress.com/2011/05/31/a-fresh-look-at-javascript-mixins/
inheritance in js:
http://howtonode.org/prototypical-inheritance
http://killdream.github.io/blog/2011/10/understanding-javascript-oop/index.html
Here you go a little demonstration of the functionality you want to achieve:
var obj1 = function() {
var privateMember = "anything";
this.item1 = 1;
}
var obj2 = function() {
this.item2 = 2;
}
var objInheritsBoth = function() {
obj1.call(this); // call obj1 in this context
obj2.call(this);
this.item3 = 3;
}
var x = new objInheritsBoth();
console.log(x.item1, x.item2, x.item3); // 1 2 3

Extending/overriding in JavaScript?

I want to write a small game using JavaScript and <canvas> but first I want to nail the "correct" or at least common approach to working with Objects.
One topic I am having trouble understanding in particular is how I could implement overriding of method.
When I create an Object, I may have this:
function MyObject()
{
var base = {};
base.i = 0;
base.update = function()
{
base.i ++;
}
return base;
}
Then when I create another Object that should start with the same members, I use this:
function AnotherObject()
{
var base = new MyObject();
base.j = 0;
return base;
}
I want to add more content to AnotherObject.update() while still running the logic I have in MyObject.update(), but when I do this within AnotherObject():
base.update = function()
{
j ++;
}
Then I of course lose the logic I added in MyObject.update().
How can I write AnotherObject.update() so that it also calls the original update() method defined by MyObject?
First, I'd suggest you read this excellent excellent MDN article. It will enlighten you.
You can achieve subclassing this way:
function MyObject() {
this.i = 0;
}
MyObject.prototype.update = function() {
this.i++;
}
function AnotherObject() {
MyObject.call(this);
this.j = 0;
}
AnotherObject.prototype = new MyObject;
AnotherObject.prototype.constructor = AnotherObject;
AnotherObject.prototype.update = function() {
MyObject.prototype.update.call(this);
this.j++;
}
obj = new AnotherObject();
console.log(obj.i); //0
console.log(obj.j); //0
obj.update();
console.log(obj.i); //1
console.log(obj.j); //1
console.log(obj instanceof MyObject) //true
console.log(obj instanceof AnotherObject) //true
+1 for zzzzBov's comment. You're using base when you should be using prototype. Not within the constructor function, but rather after the constructor function to further refine the class definition.
function MyObject() {
this.value = 5;
}
MyObject.prototype.update = function() {
this.value++;
}
Var newObject = new MyObject();
newObject.update =function() {
value--;
}
As others have suggested you should follow prototype based inheritance. That is the right way to do it.
But as a solution to what you have done so far you can do as shown below
function MyObject() {
var base = {};
base.i = 0;
base.update = function () {
this.i++;
}
base.show = function () {
console.log("i is " + this.i);
}
return base;
}
function AnotherObject() {
var base = new MyObject();
base.j = 0;
var update = base.update; // proxy variable that refers to original `update`
base.update = function () {
update.call(this); // invoke original `update`
this.j++;
}
var show = base.show; // proxy variable that refers to original `show`
base.show = function () {
show.call(this); // invoke original `show`
console.log("j is " + this.j);
}
return base;
}
var t = AnotherObject();
t.update();
t.show();

Question about the efficiency of closure/encapsulation in JavaScript

I'm somewhat new to JavaScript, so bear with me if this is a dumb question.
Let's say that I've got a "class" that looks like this:
var obj = function () {
var val;
return {
setVal: function(newVal) {
val = newVal;
},
getVal: function() {
return val;
}
};
};
Assuming my syntax is correct, this defines a class with a "private" property named "value," with methods to set/get the property. Now, I will create two objects from this class:
var myObj = obj();
var yourObj = obj();
Does this create a separate setVal() and getVal() method for each object? If not, why not? If so, is this a serious concern when building efficient web applications? Is the trade-off (if any) of efficiency for closure worth it in most/all contexts? Am I dumb?
Thanks,
Gerard
var obj = function () {
var val;
return {
setVal: function(newVal) {
val = newVal;
},
getVal: function() {
return val;
}
};
};
what this function does is as following :
create variable named val
create new object
create a new function and assign it to field setVal
create a new function and assign it to field getVal
return object.
So your always creating 4 new things.
This isn't really a problem if you have less then a 1000 objects on the page. Refactoring it away is a micro optimisation.
The alternative would be to not rely on local variables and use this._val to indicate that val is private.
It does do so conceptually. However, since this is such a common pattern, modern JavaScript JITers know how to optimize it away so that there is only one copy of the code stored in memory, with appropriate pointer redirections to make it work with the relevant closure.
EDIT: although I am not really up for spelunking through source code, here's some basic proof. Download the Chrome dev channel release, and take heap snapshots before and after running the following code:
var obj = /* as above */;
var objs = [];
for (var i = 0; i < 10000; ++i) {
objs.push(obj());
}
Then do the same for this code:
function Obj() { }
Obj.prototype.setVal = function (value) { this._val = value; };
Obj.prototype.getVal = function () { return this._val; };
var objs = [];
for (var i = 0; i < 10000; ++i) {
objs.push(new Obj());
}
You will find the heap snapshots to show the same numbers for "Code" in both cases, so indeed the optimization I describe is being performed.

Javascript Namespace declaration

What is the proper way to declare a namespace? I've just read "Developing Large Web Applications" and the author suggests using:
if (!window.YourNamespace) {
YourNamespace = {};
}
seems easy enough.. but I see all the javascript libraries for declaring namespaces and alternate methods. Isn't there a standard way to do this? Any problems with the above?
I've seen this convention used several places.
window.YourNamespace = window.YourNamespace || {};
The mentioned namespace-declarating-way by book author is indeed quite good one. But when you need to repeat it in several files and the namespace has several subnamespaces, it can get quite tedious:
if (!window.Foo) {
Foo = {};
}
if (!window.Foo.Bar) {
Foo.Bar = {};
}
if (!window.Foo.Bar.Baz) {
Foo.Bar.Baz = {};
}
etc...
Instead you should write a simple function that takes care of declaring the namespaces for you:
function namespace(ns) {
var parts = ns.split(/\./);
var obj = window;
for (var i=0; i<parts.length; i++) {
var p = parts[i];
if (!obj[p]) {
obj[p] = {};
}
obj = obj[p];
}
}
Now you can declare the whole nested namespace with just one line:
namespace("Foo.Bar.Baz");
In ExtJS framework this is basically what Ext.ns() function does. I don't really know about other libraries.
var Utils = {
namespace : function(name) {
return window[name] = window[name] || {};
}
};
or if you prefer your way use:
if (typeof window.YourNamespace === 'undefined') {
YourNamespace = {};
}
There is no standard way as you'll see between frameworks but they do go beyond the basics so that for example X.Y.Z, it will create all objects in that chain if they don't already exist.
bob.js handles namespaces like this:
bob.ns.setNs('YourNamespace', {
/*define your members here. e.g.:*/
method1: function () { /*...*/ }
});
// now, merge another, sub-namespace.
bob.ns.setNs('YourNamespace.YourSubNamespace', {
method2 function () { /*...*/ }
});
//call methods:
YourNamespace.method1();
YourNamespace.YourSubNamespace.method2();
Automating namespaces declaration in javascript is very simple as you can see:
var namespace = function(str, root) {
var chunks = str.split('.');
if(!root)
root = window;
var current = root;
for(var i = 0; i < chunks.length; i++) {
if (!current.hasOwnProperty(chunks[i]))
current[chunks[i]] = {};
current = current[chunks[i]];
}
return current;
};
// ----- USAGE ------
namespace('ivar.util.array');
ivar.util.array.foo = 'bar';
alert(ivar.util.array.foo);
namespace('string', ivar.util);
ivar.util.string.foo = 'baz';
alert(ivar.util.string.foo);
Try it out: http://jsfiddle.net/stamat/Kb5xY/
Blog post: http://stamat.wordpress.com/2013/04/12/javascript-elegant-namespace-declaration/
Some example of namespace function:
namespace = function(ns){
arr = ns.split(".")
parent = window
var temp
while( ( temp = arr.shift()) !== undefined){
parent[temp] = parent[temp] || {}
parent = parent[temp]
}
}
You can then use it as:
namespace("your.own.namespace")
your.own.namespace.Car= function () {
this.speed = 30;
}

How can I construct an object using an array of values for parameters, rather than listing them out, in JavaScript?

Is this possible? I am creating a single base factory function to drive factories of different types (but have some similarities) and I want to be able to pass arguments as an array to the base factory which then possibly creates an instance of a new object populating the arguments of the constructor of the relevant class via an array.
In JavaScript it's possible to use an array to call a function with multiple arguments by using the apply method:
namespace.myFunc = function(arg1, arg2) { //do something; }
var result = namespace.myFunc("arg1","arg2");
//this is the same as above:
var r = [ "arg1","arg2" ];
var result = myFunc.apply(namespace, r);
It doesn't seem as if there's anyway to create an instance of an object using apply though, is there?
Something like (this doesn't work):
var instance = new MyClass.apply(namespace, r);
Try this:
var instance = {};
MyClass.apply( instance, r);
All the keyword "new" does is pass in a new object to the constructor which then becomes the this variable inside the constructor function.
Depending upon how the constructor was written, you may have to do this:
var instance = {};
var returned = MyClass.apply( instance, args);
if( returned != null) {
instance = returned;
}
Update: A comment says this doesn't work if there is a prototype. Try this.
function newApply(class, args) {
function F() {
return class.apply(this, args);
}
F.prototype = class.prototype;
return new F();
}
newApply( MyClass, args);
Note that
new myClass()
without any arguments may fail, since the constructor function may rely on the existence of arguments.
myClass.apply(something, args)
will fail in many cases, especially if called on native classes like Date or Number.
I know that "eval is evil", but in this case you may want to try the following:
function newApply(Cls, args) {
var argsWrapper = [];
for (var i = 0; i < args.length; i++) {
argsWrapper.push('args[' + i + ']');
}
eval('var inst = new Cls(' + argsWrapper.join(',') + ');' );
return inst;
}
Simple as that.
(It works the same as Instance.New in this blog post)
Hacks are hacks are hacks, but perhaps this one is a bit more elegant than some of the others, since calling syntax would be similar to what you want and you wouldn't need to modify the original classes at all:
Function.prototype.build = function(parameterArray) {
var functionNameResults = (/function (.{1,})\(/).exec(this.toString());
var constructorName = (functionNameResults && functionNameResults.length > 1) ? functionNameResults[1] : "";
var builtObject = null;
if(constructorName != "") {
var parameterNameValues = {}, parameterNames = [];
for(var i = 0; i < parameterArray.length; i++) {
var parameterName = ("p_" + i);
parameterNameValues[parameterName] = parameterArray[i];
parameterNames.push(("parameterNameValues." + parameterName));
}
builtObject = (new Function("parameterNameValues", "return new " + constructorName + "(" + parameterNames.join(",") + ");"))(parameterNameValues);
}
return builtObject;
};
Now you can do either of these to build an object:
var instance1 = MyClass.build(["arg1","arg2"]);
var instance2 = new MyClass("arg1","arg2");
Granted, some may not like modifying the Function object's prototype, so you can do it this way and use it as a function instead:
function build(constructorFunction, parameterArray) {
var functionNameResults = (/function (.{1,})\(/).exec(constructorFunction.toString());
var constructorName = (functionNameResults && functionNameResults.length > 1) ? functionNameResults[1] : "";
var builtObject = null;
if(constructorName != "") {
var parameterNameValues = {}, parameterNames = [];
for(var i = 0; i < parameterArray.length; i++) {
var parameterName = ("p_" + i);
parameterNameValues[parameterName] = parameterArray[i];
parameterNames.push(("parameterNameValues." + parameterName));
}
builtObject = (new Function("parameterNameValues", "return new " + constructorName + "(" + parameterNames.join(",") + ");"))(parameterNameValues);
}
return builtObject;
};
And then you would call it like so:
var instance1 = build(MyClass, ["arg1","arg2"]);
So, I hope those are useful to someone - they allow you to leave the original constructor functions alone and get what you are after in one simple line of code (unlike the two lines you need for the currently-selected solution/workaround.
Feedback is welcome and appreciated.
UPDATE: One other thing to note - try creating instances of the same type with these different methods and then checking to see if their constructor properties are the same - you may want that to be the case if you ever need to check the type of an object. What I mean is best illustrated by the following code:
function Person(firstName, lastName) {
this.FirstName = firstName;
this.LastName = lastName;
}
var p1 = new Person("John", "Doe");
var p2 = Person.build(["Sara", "Lee"]);
var areSameType = (p1.constructor == p2.constructor);
Try that with some of the other hacks and see what happens. Ideally, you want them to be the same type.
CAVEAT: As noted in the comments, this will not work for those constructor functions that are created using anonymous function syntax, i.e.
MyNamespace.SomeClass = function() { /*...*/ };
Unless you create them like this:
MyNamespace.SomeClass = function SomeClass() { /*...*/ };
The solution I provided above may or may not be useful to you, you need to understand exactly what you are doing to arrive at the best solution for your particular needs, and you need to be cognizant of what is going on to make my solution "work." If you don't understand how my solution works, spend time to figure it out.
ALTERNATE SOLUTION: Not one to overlook other options, here is one of the other ways you could skin this cat (with similar caveats to the above approach), this one a little more esoteric:
function partial(func/*, 0..n args */) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var allArguments = args.concat(Array.prototype.slice.call(arguments));
return func.apply(this, allArguments);
};
}
Function.prototype.build = function(args) {
var constructor = this;
for(var i = 0; i < args.length; i++) {
constructor = partial(constructor, args[i]);
}
constructor.prototype = this.prototype;
var builtObject = new constructor();
builtObject.constructor = this;
return builtObject;
};
Enjoy!
what about a workaround?
function MyClass(arg1, arg2) {
this.init = function(arg1, arg2){
//if(arg1 and arg2 not null) do stuff with args
}
init(arg1, arg2);
}
So how you can:
var obj = new MyClass();
obj.apply(obj, args);
One possibility is to make the constructor work as a normal function call.
function MyClass(arg1, arg2) {
if (!(this instanceof MyClass)) {
return new MyClass(arg1, arg2);
}
// normal constructor here
}
The condition on the if statement will be true if you call MyClass as a normal function (including with call/apply as long as the this argument is not a MyClass object).
Now all of these are equivalent:
new MyClass(arg1, arg2);
MyClass(arg1, arg2);
MyClass.call(null, arg1, arg2);
MyClass.apply(null, [arg1, arg2]);

Categories