I am attempting to build my first custom object and it looks something like this:
function URLObject()
{
this.syllables = new Array();
etc...
this.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
}
var myobj = new URLObject();
myobj.AdtoSyllables("text");
The execution of the above code results in the JS engine printing out the following:
This is Sylcount: NAN
-or-
This is SylCount: undefined.
I have looked at information in Head First Javascript, in the Javascript bible, and on various JS websites. All of them cover in exhaustive detail the use of arrays of objects, but none of them discuss arrays within objects.
And yet I am doing something wrong here and I do not know what. Can anyone help?
Here you go:
function URLObject()
{
this.syllables = [];
etc...
}
URLObject.prototype.addToSyllables = function(aWord) {
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
var myobj = new URLObject();
myobj.adtoSyllables("text");
.prototype adds the function declared after it to every object constructed by the constructor function. (in your case every object that was instantiated by new URLObject())
Firstly, the code as posted actually works for me on Chrome and Firefox; so this must depend on the JavaScript engine, or else there's something funky going on.
Update: I suspect what may be confusing you is some separate call to AddtoSyllables (in code you haven't shown us) where suddenly this.syllables is no longer defined. This is where the behavior of this can get confusing. I've created a jsFiddle to hopefully explain how it works a bit better for you.
http://jsfiddle.net/J3tUb/
That said, it is often very possible to write code like this without having to use this (or the prototype) at all. For instance:
function createURLObject() {
// Use closed-over locals instead of attaching properties.
var syllables = new Array();
function AddToSyllables(AWord) {
// Since syllables is closed over, it is accessible here
// (but WON'T be accessible outside this scope).
syllables.push(AWord);
return syllables.length;
}
// Expose whatever functionality you want to be "public"
// in the returned object.
return {
AddToSyllables: AddToSyllables
};
}
var myObj = createURLObject();
myObj.AddToSyllables("text");
It is, of course, valuable to understand JavaScript's quirky (and surprising, to most developers coming from other languages) behavior with respect to this. That said, once you do understand it, I suspect you will find that it can often be avoided altogether.
you need to do this :
function URLObject()
{
var that = this;
that.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
etc...
Like this you can add method and attributes to one object.
The issue you are having is that the function AddtoSyllables is not a member function or method of the URLObject. It is just a nested function with no object attachments, so all usages of this will result in returning the dom window object. The correct way of declaring the AddtoSyllables function is this:
function URLObject()
{
//...
}
URLObject.prototype.AddtoSyllables = function (AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
To explain the reasons of the behavior in the question, I'd like to clarify that objects in javascript are treated like a map, dictionary or a key-value pair (use the term what suits you best). Using the syntax x.y = value; is equivalent putting the value value into the map x with key y. Having the code:
this.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
adds the AddtoSyllables function as an entry to the object this points to.
The code
myobj.AdtoSyllables(...)
is equivalent to
myobj["AdtoSyllables"](...) // now a retreiaval operation
or even
var fn = myobj["AdtoSyllables"];
fn (...);
Inside the AdtoSyllables function, this is used. Against common expectations, it is not a pointer to the myobj.
The cause of this is that AddtoSyllables is treated as a static method of the URLObject class (as OOP guys would understand it), or even a loose static function (like in C). To make JS treat it like a member of the URLObject object (an instance method to OOP guys), JS must be told to do so. This is achieved through the URLObject.prototype.AddtoSyllables = .... which equivalents to declaration of an instance method.
From an alternative point of view:
function foo() { /* some code using `this` */ }
var bar = {};
var baz = {};
bar.foo = foo; // same as bar["foo"] = foo;
baz.foo = foo; // same az baz["foo"] = foo;
In the above code, this usages inside foo will neither point to bar, nor baz. At the same time bar.foo will point to the very same instance as baz.foo, for foo is also an object.
Related
[Edited] Important! Function is treated as object, not value. So this question is invalid because it is based on a wrong assumption. This edit serves as a note to avoid confusing anyone who read this question.
Let's say I have a function expression of foo
var foo = function() {
return this.member;
}
and I have the following class and instantiate many objects of it with "foo" as the callback function.
var simpleClass = function(callback) {
this.member = "I am an instance variable";
this.callback = callback;
}
var a = new simpleClass(foo);
var b = new simpleClass(foo);
var c = new simpleClass(foo);
.
.
.
Since in JavaScript arguments are passed by value, we are copying the value([Edited]actually it should be object) of foo to a, b, c and other variables' callback. If my understanding is correct, then foo will be copied n times, each occupying certain memory space for each object.
Base on this understanding, I have some performance questions regarding this situation:
Does copying functions to multiple variables harm the performance?
Since each copies of "foo" as simpleClass object's "callback" occupies space, if there are really many simpleClass object(e.g. in a DOM library I have thousands of DOM objects which has the same function css()), will it harm the performance significantly? Or most JavaScript engine has mechanism to tackle this situation and it generally won't harm at all?
In situation where potentially hundreds or thousands of object will be created. Is it always a good practice to put those shared functions to the prototype of an object?
Since all the object instance share the same class prototype, if we put the "foo" function to the prototype of simpleClass, then there should have only one copy of the "foo" and every object instance will just execute the prototype copy of "foo" when needed. Is this a good practice we should follow?
I try to search for similar keywords but couldn't find the right wordings to find the solution to this problem. Please correct my wordings if I make anything unclear. And of course if I have any misunderstandings please correct me too. I appreciate everyone's help.
I don't understand this well enough to give you an authoritative answer but I can say this:
then foo will be copied n times, each occupying certain memory space for each object.
This is incorrect. foo is a variable pointing to a function. foo is not the function, if you did var bar = foo, bar now also points to the function, the same function. So the function is not copied. A reference to the function is assigned to this.callback.
In situation where potentially hundreds or thousands of object will be created. Is it always a good practice to put those shared functions to the prototype of an object?
What is and isn't good practise in JavaScript is up for debate. Some people like to use class/prototype, other people use object literals. It's definitly true though that prototype can help reduce the memory footprint of your application. See it like this: if you're using prototype you're giving the JavaScript engine more information about the object, ie. that your object is similar to all these other objects. The JavaScript engine should be able to make optimizations based on that. I can't say too much about the exact numbers, it might vary wildly per vendor.
Your code sample is equivalent to this:
function foo() {}
function myClass() {
this.foo = foo;
}
var instance = new myClass();
If you used prototypes you'd write:
function myClass() {}
myClass.prototype.foo = function () {};
var instance = new myClass();
If you used object literals you'd have:
function foo() {};
function create_myClass() {
return {
foo: foo
};
}
var instance = create_myClass();
In all the cases above the function foo is never copied. In these cases below you do create a new copy of foo every time:
function myClass() {
this.foo = function () {}; // new copy every time
}
var instance = new myClass();
function create_myClass() {
return {
foo: function () {}; // new copy every time
};
}
As for performance. This is the tip I always give: don't start optimizing until you run into a measurable problem. Always measure with real data. Additionally, if you think your way of doing things is good then it's likely that JavaScript engine vendors will optimize for that method.
In javascript reference is copied not the object itself so you can't assign the value to callback to change the function from inside constructor. You your code all those object will share the function, look at this snipet:
var foo = function() {
return this.member;
}
var simpleClass = function(callback) {
this.member = "I am an instance variable";
this.callback = callback;
}
var a = new simpleClass(foo);
var b = new simpleClass(foo);
alert(a.callback === b.callback ? 'shared' : 'not shared');
(Obviously I'm not sure what the title of this should be.)
I'd like to be able to modify the prototypes of native objects with minimal risk (because trust me; I have heard over and over again how it's a mortal javascript sin).
My train of thought goes something like this: I can greatly reduce the possibility of conflicts if I can add my custom functions to a single object on a prototype rather than directly adding them to the prototype itself.
If I have the code,
String.prototype.foo = function() {
//do stuff
};
...obviously the keyword this references the string that called it. However, if I do something like,
String.prototype.foo = {};
String.prototype.foo.bar = function() {
//do stuff
};
...the keyword this references the object foo.
If there some way to overcome this?
The only way to overcome this would be to override the context using call:
String.prototype.foo.bar.call('hello'))
which works, but is pretty ridiculous.
You're better off (as you've already heard) avoiding modifying native prototypes, and instead having an object with your methods accepting the string as a parameter.
Well, there's a couple of ways to do this, depending on how much work you want to put in.
Using bind is the most straightforward way, but you have to define the string as a variable so you can pass a reference of it to bind:
String.prototype.foo = function() { console.log(this); }
String.prototype.foo.bar = function() { console.log(this); }
var g = "hi there";
g.foo() // Yields g
g.foo.bar() // Yields String.prototype.foo()
g.foo.bar.bind(g)() // Yields g again.
There may be another very hackish way to produce the desired result by creating getters and setters on String.prototype.foo so that String.prototype.foo.bar activates a function that returns a function bound to the instance that foo refers to. ??? Confusing.
What might be the best solution to reduce the possibility of conflicts, is to take advantage of prototypal inheritance and create your own sub prototype of the native String.
function MyString(string) {
this.foo = function() { //whatever };
this.foo.bar = (function() {}).bind(this);
this.toString = function() { return string; } // because toString is not generic.
}
MyString.prototype = new String();
Here, you're creating your own "sub-prototype" of the String prototype. It inherits all the properties of the String prototype and adds its own, all without altering the native strings at all. BONUS: this.foo and this.foo.bar will both refer to your instance.
var instance = new MyString("hi");
instance.foo(); // this == instance
instance.foo.bar(); // this == instance
instance.replace("i", "e"); // returns "he"
This maybe wasn't the answer you were looking for, but hopefully it will at least be helpful.
I'm trying to do a reusable module, with lesser code. Will something like this work? (Well, not really going to work, it's just an example to give you the idea)
var test = function(foo) {
var bar = new foo(); // The keyword foo is from the parameter
}
The parameter is actually a string. So if I passed "FooBar", a FooBar object will be created.
It's like saying:
var test = function('FooBar') {
var bar = new 'FooBar'();
}
Are there other elegant ways which would fit the solution I'm looking for?
Many thanks!
If foo is a constructor function, then your code will work just fine (I'm curious why you didn't just try it). You can see it work here: http://jsfiddle.net/jfriend00/yT6Vk/.
If you want advise on other/better ways to solve your problem, you'll have to back up and describe more about what you're really trying to do.
There are alternate ways of doing things like this such as factory functions or a single function that examines it's arguments to decide which type of object to create, but without more info on exactly what problem you're trying to solve, we can't really say whether other methods are better/worse than what you already have.
A disadvantage of this method is that you haven't allowed for any arguments to be passed to the constructor.
I would use Douglas Crockford's method
var booze = {
beer:'ale',
wine: 'pinot noir'
}
//test(X)
var createObject = function(o){
function F () {}
F.prototype = o
return new F()
}
var test = function () {
var x = createObject(booze)
return x;
}
test()
I've seen objects defined in two different ways, which function similarly, but are, of course, fundamentally different. You can do it either like this:
var myobject = {property: 'hello',
act: function() {
this.property += ' world';
}};
and like this:
function myobject() {
this.property = 'hello';
this.act = function() {
this.property += 'world';
}
}
The second method could create objects like so
var newobj = new myobject();
but you could do something similar using the first notation by making the object the return value of a function. The new keyword has the advantage of being able to pass parameters that can be used to initialize the properties of the object, but you could just as easily add an init function to the first kind of object.
Just wondering if besides these two differences, if there was a fundamental difference that made one method definitely better than the other method.
The second is better because you can reuse it. In addition, the constructor property of the constructed object is different in each case.
That aside, the second method wastes space by allocating a new function to the act property each time you call the constructor. (Note that the first method also wastes space in the same way.) Use prototypes instead:
function MyConstructor () {
this.property = 'hello';
}
MyConstructor.prototype = {
act: function () {
this.property += 'world';
}
};
MyConstructor.prototype.constructor = MyConstructor;
var obj = new MyConstructor ();
var f = function () {};
function g () {}
if (typeof(f) === typeof(g)) {
alert(typeof(f) + "\n" + f + "\n" + g);
}
The types are identical and variable f has an anonymous function assigned to it. Since f is a named variable with a function as its value it is a function that is not anonymous. JavaScript is a lambda language of downward inheritance that allows accidental creation of global variables. With regard to complex instances of inheritance where closures are used across the variance namespace scopes you have to be sure where your variables are defined to prevent collisions, especially with consideration for reuse. The first convention forces strict awareness of variable declaration, because the function must be declared before it can be executed. The second convention supplies no such awareness, which is potentially problematic with regards to instantiation and invocation as closure in complex logic prior described. Fortunately, JSLint is smart enough to throw an error when a function is used before it is declared. Since the two conventions are identical in representation I would suggest only using the one that is not open to abuse from flawed and sloppy programming.
In summary if g and f are both named variables with a function as assignment then always do it the right way using the first convention where you declare your variable using the var keyword.
javascript:
canDo="b:c=function(){}";
canNot="function a:d(){}";
eval(canDo);
alert(["Can do ",canDo,
".\n\n\nConfirmed result is: \n\n b:c=",
eval("b:c")
].join(""));
alert(
confirm(
"Click OK to confirm this is not valid (can NOT do):\n\n" + canNot) ?
eval(canNot) : "Test will fail if attempted and 'a:d' will not exist."
);
displays, in FireFox:
Can do b:c=function(){}.
Confirmed result is:
b:c=function () {
}
and
Click OK to confirm this is not valid (can NOT do):
function a:d(){}
which gives a runtime error if OK is chosen.
Let's say I instantiate an object in Javascript like this:
var myObj = new someObject();
Now, is it possible to obtain the var object's name as string 'myObj' from within one of the class methods?
Additional details (edited):
The reason why I would like to get the name of the variable holding reference to the object is that my new myObj would create a new clickable DIV on the page that would need to call a function myObj.someFunction(). As I insert the new DIV I need to know the name of the variable holding reference to the object. Is there maybe a better way of doing this?
You are right, sorry for the mixup in terminology.
The reason why I would like to get the name of the variable holding reference to the object is that my new myObj would create a new clickable DIV on the page that would need to call a function myObj.someFunction(). As I insert the new DIV I need to know the name of the variable holding reference to the object. Is there maybe a better way of doing this?
Shog9 is right that this doesn't make all that much sense to ask, since an object could be referred to by multiple variables. If you don't really care about that, and all you want is to find the name of one of the global variables that refers to that object, you could do the following hack:
function myClass() {
this.myName = function () {
// search through the global object for a name that resolves to this object
for (var name in this.global)
if (this.global[name] == this)
return name
}
}
// store the global object, which can be referred to as this at the top level, in a
// property on our prototype, so we can refer to it in our object's methods
myClass.prototype.global = this
// create a global variable referring to an object
var myVar = new myClass()
myVar.myName() // returns "myVar"
Note that this is an ugly hack, and should not be used in production code. If there is more than one variable referring to an object, you can't tell which one you'll get. It will only search the global variables, so it won't work if a variable is local to a function. In general, if you need to name something, you should pass the name in to the constructor when you create it.
edit: To respond to your clarification, if you need to be able to refer to something from an event handler, you shouldn't be referring to it by name, but instead add a function that refers to the object directly. Here's a quick example that I whipped up that shows something similar, I think, to what you're trying to do:
function myConstructor () {
this.count = 0
this.clickme = function () {
this.count += 1
alert(this.count)
}
var newDiv = document.createElement("div")
var contents = document.createTextNode("Click me!")
// This is the crucial part. We don't construct an onclick handler by creating a
// string, but instead we pass in a function that does what we want. In order to
// refer to the object, we can't use this directly (since that will refer to the
// div when running event handler), but we create an anonymous function with an
// argument and pass this in as that argument.
newDiv.onclick = (function (obj) {
return function () {
obj.clickme()
}
})(this)
newDiv.appendChild(contents)
document.getElementById("frobnozzle").appendChild(newDiv)
}
window.onload = function () {
var myVar = new myConstructor()
}
Short answer: No. myObj isn't the name of the object, it's the name of a variable holding a reference to the object - you could have any number of other variables holding a reference to the same object.
Now, if it's your program, then you make the rules: if you want to say that any given object will only be referenced by one variable, ever, and diligently enforce that in your code, then just set a property on the object with the name of the variable.
That said, i doubt what you're asking for is actually what you really want. Maybe describe your problem in a bit more detail...?
Pedantry: JavaScript doesn't have classes. someObject is a constructor function. Given a reference to an object, you can obtain a reference to the function that created it using the constructor property.
In response to the additional details you've provided:
The answer you're looking for can be found here: JavaScript Callback Scope (and in response to numerous other questions on SO - it's a common point of confusion for those new to JS). You just need to wrap the call to the object member in a closure that preserves access to the context object.
You can do it converting by the constructor to a string using .toString() :
function getObjectClass(obj){
if (typeof obj != "object" || obj === null) return false;
else return /(\w+)\(/.exec(obj.constructor.toString())[1];}
You might be able to achieve your goal by using it in a function, and then examining the function's source with toString():
var whatsMyName;
// Just do something with the whatsMyName variable, no matter what
function func() {var v = whatsMyName;}
// Now that we're using whatsMyName in a function, we could get the source code of the function as a string:
var source = func.toString();
// Then extract the variable name from the function source:
var result = /var v = (.[^;]*)/.exec(source);
alert(result[1]); // Should alert 'whatsMyName';
If you don't want to use a function constructor like in Brian's answer you can use Object.create() instead:-
var myVar = {
count: 0
}
myVar.init = function(n) {
this.count = n
this.newDiv()
}
myVar.newDiv = function() {
var newDiv = document.createElement("div")
var contents = document.createTextNode("Click me!")
var func = myVar.func(this)
newDiv.addEventListener ?
newDiv.addEventListener('click', func, false) :
newDiv.attachEvent('onclick', func)
newDiv.appendChild(contents)
document.getElementsByTagName("body")[0].appendChild(newDiv)
}
myVar.func = function (thys) {
return function() {
thys.clickme()
}
}
myVar.clickme = function () {
this.count += 1
alert(this.count)
}
myVar.init(2)
var myVar1 = Object.create(myVar)
myVar1.init(55)
var myVar2 = Object.create(myVar)
myVar2.init(150)
// etc
Strangely, I couldn't get the above to work using newDiv.onClick, but it works with newDiv.addEventListener / newDiv.attachEvent.
Since Object.create is newish, include the following code from Douglas Crockford for older browsers, including IE8.
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o
return new F()
}
}
As a more elementary situation it would be nice IF this had a property that could reference it's referring variable (heads or tails) but unfortunately it only references the instantiation of the new coinSide object.
javascript: /* it would be nice but ... a solution NOT! */
function coinSide(){this.ref=this};
/* can .ref be set so as to identify it's referring variable? (heads or tails) */
heads = new coinSide();
tails = new coinSide();
toss = Math.random()<0.5 ? heads : tails;
alert(toss.ref);
alert(["FF's Gecko engine shows:\n\ntoss.toSource() is ", toss.toSource()])
which always displays
[object Object]
and Firefox's Gecko engine shows:
toss.toSource() is ,#1={ref:#1#}
Of course, in this example, to resolve #1, and hence toss, it's simple enough to test toss==heads and toss==tails. This question, which is really asking if javascript has a call-by-name mechanism, motivates consideration of the counterpart, is there a call-by-value mechanism to determine the ACTUAL value of a variable? The example demonstrates that the "values" of both heads and tails are identical, yet alert(heads==tails) is false.
The self-reference can be coerced as follows:
(avoiding the object space hunt and possible ambiguities as noted in the How to get class object's name as a string in Javascript? solution)
javascript:
function assign(n,v){ eval( n +"="+ v ); eval( n +".ref='"+ n +"'" ) }
function coinSide(){};
assign("heads", "new coinSide()");
assign("tails", "new coinSide()");
toss = Math.random()<0.5 ? heads : tails;
alert(toss.ref);
to display heads or tails.
It is perhaps an anathema to the essence of Javascript's language design, as an interpreted prototyping functional language, to have such capabilities as primitives.
A final consideration:
javascript:
item=new Object(); refName="item"; deferAgain="refName";
alert([deferAgain,eval(deferAgain),eval(eval(deferAgain))].join('\n'));
so, as stipulated ...
javascript:
function bindDIV(objName){
return eval( objName +'=new someObject("'+objName+'")' )
};
function someObject(objName){
this.div="\n<DIV onclick='window.opener."+ /* window.opener - hiccup!! */
objName+
".someFunction()'>clickable DIV</DIV>\n";
this.someFunction=function(){alert(['my variable object name is ',objName])}
};
with(window.open('','test').document){ /* see above hiccup */
write('<html>'+
bindDIV('DIVobj1').div+
bindDIV('DIV2').div+
(alias=bindDIV('multiply')).div+
'an aliased DIV clone'+multiply.div+
'</html>');
close();
};
void (0);
Is there a better way ... ?
"better" as in easier? Easier to program? Easier to understand? Easier as in faster execution? Or is it as in "... and now for something completely different"?
Immediately after the object is instantiatd, you can attach a property, say name, to the object and assign the string value you expect to it:
var myObj = new someClass();
myObj.name="myObj";
document.write(myObj.name);
Alternatively, the assignment can be made inside the codes of the class, i.e.
var someClass = function(P)
{ this.name=P;
// rest of the class definition...
};
var myObj = new someClass("myObj");
document.write(myObj.name);
Some time ago, I used this.
Perhaps you could try:
+function(){
var my_var = function get_this_name(){
alert("I " + this.init());
};
my_var.prototype.init = function(){
return my_var.name;
}
new my_var();
}();
Pop an Alert: "I get_this_name".
This is pretty old, but I ran across this question via Google, so perhaps this solution might be useful to others.
function GetObjectName(myObject){
var objectName=JSON.stringify(myObject).match(/"(.*?)"/)[1];
return objectName;
}
It just uses the browser's JSON parser and regex without cluttering up the DOM or your object too much.