How to retrieve the constructor's name in JavaScript? - javascript

Assume the following program:
var SomeConstructor = function() { };
var instance = = new SomeConstructor ();
The expression instance instanceof SomeConstructor yields True, so instance has to know somehow that it was constructed by the function SomeConstructor. Is there way to retrieve the name SomeConstructor directly from instance?
(In my problem at hand, I have a hierarchy of prototypes implementing possible signals in my application. I have to access the type of a signal which shall be equivalent to the constructor used to create that signal.)

On Chrome (7.0.544.0 dev), if I do:
function SomeConstructor() { }
var instance = new SomeConstructor();
console.log(instance.constructor.name);
it prints 'SomeConstructor'...but if SomeConstructor is defined as an unnamed function as you have it, it will print an empty string instead.
If I print instance.constructor it prints the same thing as it does if I print SomeConstructor in the code you have. The instanceof operator need only compare these two values to see that they are equal to be able to return true.

This code will get the name of the constructor, as long as it is not an anonymous function:
obj.constructor.toString().match(/function (\w*)/)[1];
Why would you need the class name? Let's say you want to save and restore class instances via JSON. You could store the class name in a "type" property, and then use a resolver function in JSON.parse to restore the objects. (See the sample code on this page).
So, in theory you could use the code above to make a generalized serializer that could handle any class instance, but parsing function strings is very inefficient. This overhead can be avoided by requiring all the classes you are going to store to provide the type explicitly:
function Foo() {}
Foo.prototype.type = 'Foo';
This seems silly and redundant, which is why I started on the quest to obtain the class name implicitly. But in the end I have to give in: there is no acceptable solution in JS :-(

No. You can use x.constructor to get a direct reference to C, but it's an anonymous function so there's no way of getting its name.
If it were defined like so:
function C() { };
x = new C();
Then it would be possible to use x.constructor.toString() and parse out the name of the function from the returned string. Some browsers would also support x.constructor.name[1].
[1] https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/name

You can also declare your class this:
var C = function C() { };
Now your C class constructor is a named function (no longer an anonymous function) meaning you can do:
x = new C();
console.log(x.constructor.name); // output: C

This code of yours that needs to know the constructor, can it access the constructor function itself? If so, you can just do that instanceof thing.
It seems that you need to know it by name. This sounds dangerous. Someone can create another constructor that happen to have the same name and it will pass (unless that's what you want, of course).

At least in React it might be
this.default.name

Related

Check if object has method, without instantiating it

function object1(){
}
object1.prototype.myMethod = function(){};
function object2(){
this.myMethod = function(){};
}
I need to write an if statement that can check if any given object has the myMethod function, without creating an instance of said object. Is this possible?
This: testMe.prototype.hasOwnProperty('myMethod') would work only for object1, but for object2 will return false.
What is this for? I'm trying to emulate interfaces. I need to check if a function respects my interface before working on it and I want to leave the user total freedom on how this function is declared. Creating an instance of that function to check for it's properties sounds like opening a bottle with "water" written on it to check if there is water inside.
There is no way you can check if an object will have some instance methods without instantiating it, because you can add a new method anywhere:
var myObj= {};
...
if (myObj.newMethod) { //false
...
}
myObj.newMethod=function(){...};
if (myObj.newMethod) { //true
...
}
The second one isn't working without instantiating due to assigning this method on instantiating object, only. The code in body of function object2 is its "constructor" and it's run on instantiation only, obviously.

Object methods assigned to variables or function arguments fail when invoked

I'm learning javascript right now, seems like beautiful functional language to me, it is wonderful move from PHP, I should have done this earlier. Although, I cannot figure this one out:
var v1 = (/[abc]/).test;
v1('a');
says test method called on incompatible undefined, I'm trying to store the test method of that regex into variable and invoke it later.
but it works with my own functions:
function foo(){
return 'I\'m foo';
}
var f = foo;
f(); // returns I'm foo
It should work on methods too, since functions are just methods of parent object anyway, right?
Ultimately, the reason I'm trying this is to be able to write something like this:
var a = ['a', 'b', 'c'];
a.every( (/[abc]/).test );
to check each array member against that regex.
Why doesn't this work? Is it limitation in passing built-in functions around? Or am I just doing something wrong?
PS: If you grind your teeth now and muffling something about bad practices, screw good practices, I'm just playing. But I'd like to hear about them too.
it works with my own functions
You are not using this inside the function. Consider this example:
var obj = {
foo: 42,
bar: function() {
alert(this.foo);
}
};
var f = obj.bar;
f(); // will alert `undefined`, not `42`
It should work on methods too, since functions are just methods of parent object anyway, right?
"Method" is just a colloquial term for a function assigned to a property on object. And functions are standalone values. There is no connection to the object a function is assigned to. How would this even be possible, since a function could be assigned to multiple objects?
Why doesn't this work?
What this refers to inside a function is determined at run time. So if you assign the function to a variable and call it later
var v1 = (/[abc]/).test;
v1('a');
this inside the function will refer to window, not to the regular expression object.
What you can do is use .bind [MDN] to explicitly bind this to a specific value:
var a = ['a', 'b', 'c'];
var pattern = /[abc]/;
a.every(pattern.test.bind(pattern));
Note though that since .bind returns a function, the only advantage over using a function expression is that it is a tad shorter to write.
Is it limitation in passing built-in functions around?
No, the problem exists for every method/function because that's how functions work. The nice thing about built-in functions though is that they often explicitly tell you when this is referring to the wrong type of object (by throwing an error).
Learn more about this.
If you store just a method, it does not carry with it a reference to your object - it just stores a reference to the .test method, but no particular object. Remember, a method is "just" a property on an object and storing a reference to a method doesn't bind it to that object, it just stores a reference to the method.
To invoke that method on a particular object, you have to call it with that object.
You can make your own function that calls the method on the desired object like this:
var v1 = function(x) {
return /[abc]/.test(x);
}
Then, when you do this:
v1('a');
It will execute the equivalent of this in your function:
/[abc]/.test('a');
But, it isn't entirely clear why you're doing that as you could also just define the regex and call .test() on it several times:
var myRegex = /[abc]/;
console.log(myRegex.test('a'));
console.log(myRegex.test('b'));
console.log(myRegex.test('z'));
The test function expects this to be a regular expression. The expression /[abc]/.test gives an unbound function (it does not remember that it belongs to /[abc]/). When you invoke it like you do, this will be undefined and the function will fail.
You can use bind to make the function remember the object it belongs to:
var v1 = /[abc]/.test.bind(/[abc]/);
or
var v1 = RegExp.prototype.test.bind(/[abc]/);
Your reference to the method has lost its knowledge of what it was a method of.
This isn't so much good practice as just the way JS works.
You can do:
var v1 = /[abc]/;
v1.test('a');
If you must encapsulate the test method, then you could do:
var v1 = function(str){
return /[abc]/.test(str);
};
v1('a');
I don't know if this is an acceptable solution, but you can do:
v1 = function(exp) { return (/[abc]/).test(exp); }
v1('a');

How do I inherit a function from a base object and overwrite it in javascript

What I am trying to do is have a child object provide its own implementation for a function defined in a base object. As far as I've understood so far prototypes are the best (only!) way to go about doing this.
Note also that I am currently developing using the game engine: Turbulenz and as such I am trying to follow / stick to their style as closely as possible. In the engine "classes"/objects are defined and created in the following manner
function baseObject() { }
baseObject.prototype =
{
myMember1: 1,
myMember2: 2,
myMethod: function myMethodFn() {
return this.myMember1 + this.myMember2;
}
}
baseObject.Create = function baseObjectCreateFn
{
var o = new baseObject();
return o;
}
This would allow me to do the following
var anObject = baseObject.Create();
var someValue = anObject.myMethod(); // should return 3
What I would like to be able to do now is to create a new object that inherits all the properties of baseObject while allowing me to overwrite its myMethod function to for example subtract the two member values instead of add.
Would I be correct in saying that I will have to create another object then alter its prototype? The part thats throwing me most is that the definition of the baseObject's prototype is defined as an object literal and so I'm unsure of the syntax to overwrite one of its members, i.e. would the following be valid or not? :
function childObject() {}
childObject.prototype = baseObject.Create() // would this inherit from baseObject?
// or should it be: childObject.prototype = new baseObject();
// this is the part thats confusing me as the syntax
// doesn't quite match the original base objects prototype
// syntax and I'm unsure if that will matter
childObject.prototype.myMethod = function myMethodFn() {
return this.myMember1 - this.myMember2;
}
childObject.Create = function childObjectCreateFn
{
var o = new childObject();
return o;
}
var aChildObject = childObject.Create()
var anotherValue = aChildObject.myMethod() // would this return -1 as expected?
To summarise I'm trying to create an object that will overwrite a function that exists in a base object by inheriting the function from the base object and changing it, how do I do this? Thanks for your time.
You have it correct.
As for the syntax confusion, there is no real difference between
thing.prototype.myMethod = function () { ... }
and
thing.prototype = { myMethod: function() { ... } };
except for the fact that in the second one you are setting the prototype all at once (to an object literal), and if you do it again, you'll overwrite the prototype all at once with a new object literal. But because it is an object literal, you can't do inheritance this way (everything declared with naked braces { ... } is just an instance of Object of no special type). If you stick with the first syntax you'll always be ok.
Note that when you put:
childObject.prototype.myMethod = function myMethodFn() { ... }
The part where you put myMethodFn is actually ignored. The function is named myMethod by the fact that this is where you assigned it.
Similarly, where you have
childObject.Create = function childObjectCreateFn
you don't need childObjectCreateFn (it's ignored), and you need to put parentheses () somewhere after function or it's a syntax error.
Moving on to the reason why this works, every created object in Javascript has a prototype. When you call a method on that object, it first looks inside the object itself to see if a key corresponding to the name of the method exists. If not, it looks in the prototype object for the same thing, and if it's not there, it goes to that object's prototype, and so on, until it gets to the root Object, which has no prototype.
In this way you can override an implementation merely by naming it the same thing, but having it appear earlier in the prototype chain. That's exactly what you're doing on childObject. It retains the functionality of baseObject because you created an instance of baseObject to serve as childObject's prototype. Then you augmented childObject's prototype with a new method of the same name, but one that comes earlier in the prototype chain.

What object is being returned by .responseXML()?

I am trying to create a prototype/class that inherits from the object that is returned by a specific function. But I dont know what that object's name is?
For the instance var xhr = XMLHttpRequest(); what object is returned by xhr.responseXML;? Is it XMLDocument? Or maybe XMLDOM?
Also if I create the object var xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); and call xmlDoc.load("xmlFile.xml" ); will it return the same type of object as xhr.responseXML;?
I am trying to do the following:
function XMLHandler()
{
this.xmlFile = "defaultXML.xml";
}
// Make XMLHandler inherit from Javascript object
XMLHandler.prototype = new XMLDocument();
XMLHandler.prototype.constructor = XMLDocument;
You shouldn't include unrelated questions in the same post. To address your second question about declaring a function within a "class":
Your first syntax, declaring it within the constructor, will pointlessesly overwrite myClass.prototype.publicFunct to point to a newly created function every time the constructor is called. That is, you will be creating an extra copy of the function with each call to the constructor, with myClass.prototype.publicFunct always pointing to the most recently created copy - or undefined until the constructor has been called at least once. Don't do this.
Your second option is simply invalid syntax in JavaScript.
Your third syntax is prefered. This will add the function to the prototype once.
Remember: JavaScript doesn't have classes as such, though you can sort of simulate them if you think it is worth the bother.
I can tell by your recent questions that you are thinking like Java, which this is not.
First question:
responseXML is different for each browser. Firefox gives a nsIDOMDocument, IE gives an IXMLDOMDocument and Webkit browsers depend on the responseType setting but will probably be Document. Since you cannot predict what it will be stop trying to extend it. In most cases the type isn't made available by the browser's API so javascript cannot extend it anyway.
Moreover, since JavaScript's inheritance is not class based you are forced into doing this:
XMLHandler.prototype = new XMLDocument();
...which simply does not work for your purpose. Any instance of XMLHandler will be built on an unrelated, empty document and not the document returned by responseXML. You have to use a wrapper here.
Second Question:
Of your 3 methods the first is equivalent to the last but more wasteful because it repeatedly sets the same function to the same prototype. The second is nonsensical, the syntax is broken. These are your real options:
// Instance method, every instance is given a copy of the function upon "new"
function MyClass()
{
this.publicFunct = function()
{
alert("public function");
};
}
// Prototypal method, only one copy of the function shared by all instances
function MyClass()
{
}
MyClass.prototype.publicFunct = function()
{
alert("public function");
};
// Shorthand method, same as prototypal but handy for several members at once
// It prevents MyClass from being a descendent of another type
function MyClass()
{
}
MyClass.prototype = {
// A colon is only acceptable in object notation
publicFunct: function()
{
alert("public function");
}
};
I would go with a prototypal method for efficiency unless you need to selectively add functions to a class. Your use of "public function" (also "class") seems like another symptom of an OOP background, there aren't any private functions in JavaScript so "public" has no place, all member functions are public. If at some point you do need a private function you can fake the effect with a closure.
(function() {
// Assignments are mostly global
MyClass = function() {};
MyClass.prototype.publicFunct = function()
{
privateFunct();
};
// These statements affect local scope
var foo = 'bar';
function privateFunct()
{
alert("public function");
}
})(); // These extra brackets cause the contents to be executed immediately
Having said that it is rare to need private functions and all JavaScript is visible anyway so it's not secret really. The above could be thwarted like this:
thief = {};
MyClass.prototype.publicFunct.call(thief);
// privateFunct is called by publicFunct in the context of the thief
You might as well accept that functions are public. You can go a step further and give up on classes altogether. Objects are just objects that happen to have some functions and those functions can even be shared with completely different objects.

Javascript: How to access a public variable in the same class?

I recently started programming JavaScript and thought everything would be good...
Well today I faced a problem I can't solve on my own.
My tutorial/ learning project has a class called model. In this class there are several private and one public variable. This variable is of type CustomEvent:
function Model(){
/**
* Array in which the questions are stored
*/
var questions=new Array();
var db;
var valuesSplit="*";
var tableName="quests";
this.myEvent=new CustomEvent("my event");
So as you can see "myEvent" is public and can be called from outside. In this case it is an event which can be subscribed (this is done outside this class by other objects that want to listen) and it can be fired (this is done in the same class). And this is my problem.
How can I access myEvent within the model class?
I tried:
this.myEvent.fire()
and:
myEvent.fire()
But I always get "myEvent is not defined".
Probably the first thing to say is: JavaScript doesn't have classes. The sooner you stop thinking of "JavaScript classes," the better off you'll be. :-) JavaScript has OOP, but not the kind with classes. Your Model function is called a constructor function.
You can access myEvent from any code that has a reference to the object created by new Model, which includes code in your constructor (via this — e.g., the way you're setting it up) and any function called with this referring to that object (or, of course, "externally" via someObjReference.myEvent).
So probably this.myEvent.fire() is what you want, but the code you're calling it from doesn't have the right this value. That's because in JavaScript, this is controlled entirely by how a function is called, not where the function is defined as it is in some other languages. See my blog articles Mythical methods and You must remember this for more details, but I've done a somewhat truncated discussion below.
Here's an example of a fairly standard way to set up a constructor function with useful methods that all instances share:
function Foo() {
this.myEvent = new CustomEvent("my event");
}
Foo.prototype.bar = function() {
this.myEvent.fire();
};
// Usage:
var f = new Foo();
f.bar(); // Fires the event indirectly, via the code in `bar`
f.myEvent.fire(); // Fires it directly
Note that that only works if bar is called with this referring to an object with a myEvent property. It's easy to call bar with this set to something else entirely:
document.getElementById("someID").onclick = f.bar;
When the click occurs, the bar function gets called, but this does not refer to an object created via Model. (It will refer to the element with the id "someID" instead.) And so this line in bar
this.myEvent.fire();
...will fail.
If you're used to class-based languages, you can see how this is totally different from, say, Java, C#, or C++. In those langauges, this inside bar will always refer to an object created via new Model. Not so JavaScript, which is both awkward and powerful.
This flexibility of functions (not being bound to any particular object) is one of the biggest things to get used to, and take advantage of, in JavaScript. The other is how functions are closures, which is powerful but not complicated.
So if this is set by how a function is called, how do you do that? There are two ways:
Call the function by referencing it from an object property in the same expression as the call. That's an awkward way of saying do this:
var f = new Foo();
f.bar(); // <== The key bit
f["bar"](); // <== Also works
The expression f.bar() does two things, which interact: The first thing it does is retrieve the property bar of the object referenced by f, and get that property's value (which is a function reference). Then it calls that function (because of the ()). The way JavaScript works, because you did those two things in the same overall expression, the interpreter sets this to f during the call to bar for you. But note this key distinction:
var f = new Foo();
var b = f.bar;
b(); // <== Different!
Now when the bar function gets called, this will not be set to f (it'll be set to the global object, which is window on browsers), because we've separated the property retrieval from the function call.
Alternately, you can use the built-in features of JavaScript function objects, their call and apply functions. call and apply do exactly the same thing, the only difference between them is how you supply the arguments for the function. Example:
var f = new Foo();
f.bar(1, 2): // <== Calls `bar` with `this` === `f` and passing in
// the arguments 1 and 2
var b = f.bar;
b.call(f, 1, 2); // <== Does the same thing as f.bar(1, 2)
var args = [1, 2];
b.apply(f, args); // <== Does the same thing as f.bar(1, 2)
E.g., call and apply allow you to set what this should be explicitly when you call the function. The only difference between them is that call accepts the arguments to give the function as further arguments to call, and apply accepts them as an array.
If you want to use myEvent in a non public function in your Model than you have to create another reference to the myEvent which isn't using the this reference of your Model. Because the this in another function is something else than in your Model function. The easiest way to bypass this problem is if you define a new variable in your Model:
var that = this;
Then you can call your myEvent like:
that.myEvent
The myEvent member should be visible both in the inner & outer scope of the object :
function Model(){
this.myEvent = 'some value';
this.canAccessEvent = function(){
return 'myEvent' in this;
}
}
var m = new Model();
// access from outside :
alert(m.myEvent);
// access from inside :
alert('Model can access the even? ' + m.canAccessEvent());
However, it is very possible that your new CustomEvent function doesn't exist or does not return a valid object making your myEvent variable to be undefined. I suggest you attribute some other value to the myEvent property and see if it is defined. If it is defined, then the problem lies in your CustomEvent function.

Categories

Resources