I saw this article on polymorphic callable objects and was trying to get it to work, however it seems that they are not really polymorphic, or at least they do not respect the prototype chain.
This code prints undefined, not "hello there".
Does this method not work with prototypes, or am I doing something wrong?
var callableType = function (constructor) {
return function () {
var callableInstance = function () {
return callableInstance.callOverload.apply(callableInstance, arguments);
};
constructor.apply(callableInstance, arguments);
return callableInstance;
};
};
var X = callableType(function() {
this.callOverload = function(){console.log('called!')};
});
X.prototype.hello = "hello there";
var x_i = new X();
console.log(x_i.hello);
You'd need to change this:
var X = callableType(function() {
this.callOverload = function(){console.log('called!')};
});
to this:
var X = new (callableType(function() {
this.callOverload = function(){console.log('called!')};
}));
Notice the new as well as the parentheses around the callableType invocation.
The parentheses allows callableType to be invoked and return the function, which is used as the constructor for new.
EDIT:
var X = callableType(function() {
this.callOverload = function() {
console.log('called!')
};
});
var someType = X(); // the returned constructor is referenced
var anotherType = X(); // the returned constructor is referenced
someType.prototype.hello = "hello there"; // modify the prototype of
anotherType.prototype.hello = "howdy"; // both constructors
var some_i = new someType(); // create a new "someType" object
console.log(some_i.hello, some_i);
var another_i = new anotherType(); // create a new "anotherType" object
console.log(another_i.hello, another_i);
someType(); // or just invoke the callOverload
anotherType();
I really don't know how/where/why you'd use this pattern, but I suppose there's some good reason.
Related
Trying to implement a Javascript sandboxing scheme and now I've run into a bit of a wrinkle. I need to pass a "context" parameter to the code which will essentially serve as a handle to the "global" object, but so far no luck.
To illustrate the problem with a simple example, consider this bit of code:
var foo = new Function(" this.baz = this.mux; return this ");
foo.mux = "mux";
foo.call();
console.log(foo.baz);
console.log(foo.toString());
Output:
$> undefined
$> function anonymous() { this.mux; return this; }
It obviously doesn't work because the Function object doesn't seem to get it's own this like ordinary functions created with new.
So...is there any way to "reseat" a Function's this to point to itself beforehand (or just any other way around the issue)?
EDIT
Okay, so from what I understand from the comments section I'm going to need a constructed object.
var foo = new Function(" return new function(){ this.baz /* = ?? */; return this; } ");
Is there a way to somehow access the enclosing anonymous function's properties? Like "this.mux = foo.mux" (except of course "foo" isn't visible from that scope)?
I think your getting confused on what new Function( does,. It does not create an instance of an object, it just create a function. So like any object instances you will also need to use new on these.
So you need 2 steps..
create the function that you will be creating an object from..
with this function create an instance using new..
Below is a simple example..
var fcreate =
new Function('global', "this.global = global");
var f = new fcreate("hello");
console.log(f.global);
If your not bothered about instances, we can forget about this altogether, and just create a captured scope as a parameter..
eg..
var f = new Function("global", "console.log(global)");
f("This is a global to function");
f("This is another one");
You can pass foo as a parameter of call:
var foo = new Function(" this.baz = this.mux; return this ");
foo.mux = "mux";
foo.call(foo); // <-- this
Edit: Although the code above works, I wouldn't recommend it. You will be better off creating the function/class foo:
var Foo = function(mux){
this.baz = mux;
}
var foo = new Foo("mux");
console.log(foo.baz);
The best I could come up with that actually works.
var foo = new Function(" this.baz = this.mux; return this ");
var context = { mux: "mux" };
foo = foo.bind(context);
foo();
// context.baz == "mux"
Alright so this is in fact doable, and it's basically an extension of Keith's answer:
function verify(condition)
{
console.log(condition === true ? "pass" : "fail");
}
function test()
{
if(!(this instanceof test))
return new test();
var foo = new Function("mux", "return new function(){ this.baz = mux; return this; } ");
var bar = new foo(null);
verify(bar.baz === null);
var zim = new foo(this);
verify(zim.baz === this);
var qud = new foo(global);
verify(qud.baz === global);
};
test();
Output:
pass
pass
pass
A sincere thanks to everyone for helping me figure this one out - cheers!
* EDIT *
As per Keith's comments, the correct implementation would simply be:
function verify(condition)
{
console.log(condition === true ? "pass" : "fail");
}
function test()
{
if(!(this instanceof test))
return new test();
var foo = new Function("mux", "this.baz = mux; return this; ");
var bar = new foo(null);
verify(bar.baz === null);
var zim = new foo(this);
verify(zim.baz === this);
var qud = new foo(global);
verify(qud.baz === global);
};
test();
I'm always getting Cannot set property 'saySomething' of undefined but why?
Am I making a mistake somewhere?
var Person = new Object();
Person.prototype.saySomething = function ()
{
console.log("hello");
};
Person.saySomething();
Debugging tip: You get this ..of undefined errors when you try to access some property of undefined.
When you do new Object(), it creates a new empty object which doesn't have a prototype property.
I am not sure what exactly are we trying to achieve here but you can access prototype of function and use it.
var Person = function() {};
Person.prototype.saySomething = function() {
console.log("hello");
};
var aperson = new Person();
aperson.saySomething();
The prototype property exists on functions, not on instantiated objects.
var Person = new Object();
console.log(Person.prototype); // undefined
var Person2 = function () {}
console.log(Person2.prototype); // {}
This is useful because things put on the prototype of a function will be shared by all object instances created with that function (by using new).
var Person = function() {};
Person.prototype.saySomething = function() {
console.log("hello");
};
console.log(
new Person().saySomething === Person.prototype.saySomething // true. they are the same function
);
If all you want is to add a method to the person object, there's no need for a prototype:
var Person = {};
Person.saySomething = function() {
console.log("hello");
};
Person.saySomething();
You can even use object literal syntax:
var Person = {
saySomething: function() {
console.log("hello");
}
};
Person.saySomething();
i was trying out some code thought of posting it, might help others.
<script>
var MODULE = {};
MODULE = (function (my) {
my.anotherMethod = function () {
console.log("hello ");
};
my.newMethod = function(){
console.log("hi new method ");
}
return my;
}(MODULE));
MODULE.anotherMethod();
MODULE.newMethod();
</script>
And please not var MODULE ={}, if this is not initialized with {} then it give cannot set property.
I know i am late to the party but as you see there is no satisfying answer available to the question so i am providing my own.
In your case when you write
var Person = new Object();
you are creating an instance of Object type.
You can add a property using prototype property to the Object, not to the instance of Object.which you can use by the instance laterly.
so you can define like
Object.prototype.saySomething = function ()
{
console.log("hello");
};
now you can call it like this.
Person.saySomething();
You can check here.
var Person = function(name) {
this.canTalk = true;
this.name = name;
};
Person.prototype.greet = function() {
if (this.canTalk) {
console.log('Hi, I am ' + this.name);
}
};
bob = new Person('bob');
bob.greet();
Is it possible to change a constructor so that some extra action is run after an object is created. I tried something like:
var origFoo = Foo
Foo = function() {
origFoo.apply(this, arguments);
/* extra actions */
}
Foo.prototype = new origFoo();
but this has several problems like the constructor being run twice or changing the prototype chain.
You are very close. You should assign the Foo.prototype to the origFoo.prototype in order to get the same prototype chain. Everything else is spot on!
Example:
var Foo = function () {
console.log('OriginalFoo');
};
Foo.prototype.method1 = function () {
console.log('Method1');
};
OriginalFoo = Foo;
Foo = function () {
OriginalFoo.apply(this, arguments);
console.log('NewFoo');
};
Foo.prototype = OriginalFoo.prototype;
Foo.prototype.method2 = function () {
console.log('Method2');
};
var x = new Foo();
x.method1();
x.method2();
Demo: http://jsbin.com/ibatah/1/edit?js,console,output
PS: There still is the problem of static-like properties (Foo.prop), but i'm afraid i don't have a solution for that other than copying them one at a time.
EDIT: Solution for special constructors.
Indeed there are constructors which don't like to be called as functions ex: Image. To get over it, you can do the more awkard solution below. You take advantage of the fact that you can return an object from the constructor and it takes the place of the one created with new. In the overridden constructor you must always use this new object when calling methods instead of this.
var Foo = function(a,b,c) {
console.log('OriginalFoo',a,b,c);
};
Foo.prototype.prop1 = 'Property1';
Foo.prototype.method1 = function() {
console.log('Method1', this.prop1);
};
OriginalFoo = Foo;
Foo = function(a,b,c) {
var obj = new OriginalFoo(a,b,c);
obj.init('Changed...'); // or this.init.call(obj,'Changed!');
this.init('Not Changed'); // applies to a discarded object, has no effect
console.log('NewFoo');
return obj;
};
Foo.prototype = OriginalFoo.prototype;
Foo.prototype.prop2 = 'Property2';
Foo.prototype.method2 = function() {
console.log('Method2', this.prop2);
};
Foo.prototype.init = function(param) {
this.prop2 = param;
};
var x = new Foo('1','2','3');
console.log(x.prop1);
console.log(x.prop2);
x.method1();
x.method2();
Demo: http://jsbin.com/ibatah/2/edit?js,console,output
I'm trying to have a 'class' in JS which tracks how many instances of itself have been instantiated. I am attempting to do so like this...
var myNamespace = {};
myNamespace.myClass = function () {
//fails here as .getNetInstanceNo() not recognised...
var instanceNumber = myNamespace.myClass.getNextInstanceNo();
return {
instanceNo : function() { return instanceNumber; }
}
};
myNamespace.myClass.InstanceNo = 0; //static property?
//should the class itself have this method added to it...
myNamespace.myClass.prototype.getNextInstanceNo = function () { //static method?
return myNamespace.myClass.InstanceNo++;
};
var class1 = new myNamespace.myClass();
alert('class 1 has instance of ' + class1.instanceNo() );
However this fails as the getNextInstanceNo function is not recognised. Even though I think I'm adding it through the myClass.prototype.
What am I doing wrong?
prototype is an object from which other objects inherit properties, as in when you create an instance of an object and that object doesn't have a property/method, when called, the prototype of the class in which the object belongs to is searched for that property/method, here's a simple example:
function Animal(){};
Animal.prototype.Breathe = true;
var kitty= new Animal();
kitty.Breathe; // true (the prototype of kitty breathes)
var deadCat = new Animal();
deadCat.Breathe = false;
deadCat.Breathe; // false (the deadCat itself doesn't breath, even though the prototype does have breath
As you said yourself, you don't need to define getNextInstanceNo on prototype, since that's not how static methods are defined on JavaScript, leave it right right there on the class itself, instead you can define the instanceNo method on prototype, here's how:
var myNamespace = {};
myNamespace.myClass = function () {
this.instanceNumber = myNamespace.myClass.getNextInstanceNo();
};
myNamespace.myClass.prototype.instanceNo = function () {
return this.instanceNumber;
};
myNamespace.myClass.InstanceNo = 0;
myNamespace.myClass.getNextInstanceNo = function () {
return myNamespace.myClass.InstanceNo++;
};
var class1 = new myNamespace.myClass();
alert('class 1 has instance of ' + class1.instanceNo());
Quick and strange question:
I have an object (in this example is small but in the project is larger):
var myObject = {
hello: 1, // easier I think
'hey.ya': 5 // quite impossible but the first option is valid too
}
then I want to pass somehow to a function and use "hello" for example in a closure like this
function x(){
// my closure
return function(){this.init = function(){alert(hello)}, this.heyYa = function(){alert(/* I do not know how to call the other hey.ya variable */)}}
}
var myClass = x(), instance = new myClass(); instance.init();
thanks!
You need to use the myObject
var myObject = {
hello: 1,
'hey.ya': 5
}
function x(obj){
return function(){
this.init = function(){
alert(obj.hello)
},
this.heyYa = function(){
alert(obj['hey.ya'])
}
}
}
var myClass = x(myObject);
var instance = new myClass();
instance.init(); // alerts '1'
instance.heyYa(); // alerts '5'