PDA

View Full Version : Javascript Guru Needed



Erayd
19-12-2006, 09:31 PM
I'm having a bit of a problem with a function I'm trying to write.

The idea is to add a prototype method to the String object, to enable it to return the first x characters of the string, and remove them from the original object - kind of like what shift() is for arrays. This is what I have so far:
function protoStringShift() {
String.prototype.shift = function(n) {
var s = this.substr(0, n);
this = this.substr(n);
return(s);
};
}The problem is caused by assigning a value to this - if I remove that line it all works fine, but if I leave it in I get an assignment error. Is there any way of assigning a value to this (or to be more precise, some way of changing the string value that this stores)? I've tried both Google and ##javascript on freenode, but I haven't had much luck.

The intended destination is the new ChatF1 software.

Cheers,
Steve

gum digger
19-12-2006, 11:20 PM
wrong forums..i think

Greg
19-12-2006, 11:52 PM
wrong forums..i thinkNegative. There's tons of help here, eg:

His "String.prototype.shift = function" is incorrect. It should be "String.prototype.shift = function = I ask for help but Greg ain't got the faintest idea" function_help = non-existant"

Erayd
20-12-2006, 12:07 AM
Not helpful Greg - I did say 'Javascript Gurus' in the title for a reason. You're right that this isn't a programming forum; I only posted here because I was having trouble finding a solution elsewhere.

Greg
20-12-2006, 12:13 AM
Not helpful Greg - I did say 'Javascript Gurus' in the title for a reason. You're right that this isn't a programming forum; I only posted here because I was having trouble finding a solution elsewhere.

edited

Erayd
20-12-2006, 12:16 AM
Apologies, I guess I'm just a little grumpy this evening. /me edits post.

Greg
20-12-2006, 12:23 AM
Mine edited too.

Erayd
20-12-2006, 12:29 AM
Thanks. Next time I gotta remember to take a few deep breaths before hitting the 'post' button.

Greg
20-12-2006, 12:31 AM
LOL Well no-one took offence. And if you ask Metz, then he'll make a mockery of us both for being wimpy! :lol:

Erayd
20-12-2006, 12:34 AM
Too true, too true. He certainly adds a bit of spice to things :D

TGoddard
20-12-2006, 12:57 AM
You can't assign to "this". Javascript variables are references, not values. You could do something like this in C++, but it simply doesn't make sense in Javascript. It also violates good design principles.

The solution to this is to return an array containing the components. This is more general, does not alter the object itself in any way and can be used more flexibly. You might also like to consider not altering the String prototype. Just because you can do it doesn't make it a good idea - this is how you create horrible naming conflicts that are very difficult to diagnose and debug. Try this:

splitStringAtIndex = function(string, index) {
var a = string.substr(0, index);
var b = string.substr(index);
return([a,b]);
};

... somewhere else ...
components = splitStringAtIndex(string, 5);
string = components[0];
suffix = components[1];

EDIT: I just looked at your signature again and you obviously know PHP. I believe PHP variables represent a value, so I see where the confusion came from. You may like to read up on this - most scripting languages use reference variables.

Erayd
20-12-2006, 01:30 AM
Thanks for that TGoddard - I didn't know that about Javascript variables, and it certainly explains why I was having problems. Unfortunately though, the whole reason I was trying to define a prototype method was because I wanted to avoid the array stuff - in an ideal world, I want to be able to do something like while(s = someString.shift(5)) {doSomething();}, with String::shift automatically updating the variable. In effect, it would be using someString as a FIFO buffer (not quite but you get the idea). I could define shift() externally, but then it gets messy - I was hoping to define a method that could be used across all instances of String.

The goal is to write a Javascript parser to unserialize a PHP serialized multidimensional array, as this would keep a lot of the flexibility of using XML, but without the overhead of the XML parsers - resulting in less server & client load, and a whole lot less DOM access / XML code.

TGoddard
20-12-2006, 02:14 AM
A good way to handle something like this is to make all of the iteration and indexing logic internal and simply tell it what to do with each bit:

String.prototype.forEachFragment = function(fragmentLength, action) {
string = this;
while (string.length > 0) {
components = splitStringAtIndex(string, fragmentLength - 1);
action(components[0]);
string = components[1];
}
}

...

sequence = "ATCCGATAGCATAGCCGT"
aa = new Array();
sequence.forEachFragment(3, function(fragment) {aa.push(getNucleotide(fragment))}); // Does this work? I'm not sure how function scope works in Javascript.

By the way, as it turns out your original sample is actually overriding an existing function called "split". If a library you were using depended on it then you would have serious problems. It is always best to use very specific names if you have to add your own functions to an existing namespace/object.

Erayd
20-12-2006, 08:18 AM
By the way, as it turns out your original sample is actually overriding an existing function called "split". If a library you were using depended on it then you would have serious problems. It is always best to use very specific names if you have to add your own functions to an existing namespace/object.Yikes! Why does it do that - my method is called shift, and I was under the impression that in order to override the 'split' method, mine would also need to be named 'split'. I did take a look at the existing String methods to avoid conflicts, but obviously this wasn't enough.

The above way of doing things looks promising, but still isn't much good to me unless I can pass the string as a pointer rather than as a normal variable - where the problem comes in is needing the original string to be modified in addition to returning a value. A function like that took a string pointer as an argument would fit this, or a prototype function on String, provided that I can get some kind of writable handle. I can't just modify the original string inline with the rest of the code though - this operation needs to be performed many, many times, in a lot of different places and doing it with several (of the same) code lines every time would result in serious bulk.

gum digger
20-12-2006, 11:17 AM
Negative. There's tons of help here

Sorry

Greg
20-12-2006, 12:19 PM
SorryShhh. No need to be sorry. Besides, you might invoke the wrath of Metla at us for being wimpy daffodil kissing babies. ;)

TGoddard
20-12-2006, 07:52 PM
Yikes! Why does it do that - my method is called shift, and I was under the impression that in order to override the 'split' method, mine would also need to be named 'split'. I did take a look at the existing String methods to avoid conflicts, but obviously this wasn't enough.

My apologies, I thought your method was named "split" and didn't re-read it. This doesn't cause a problem immediately, but what would happen if another library or tool also tried to create a "shift" method? It is a good idea to try to pick names which are more likely to be unique.


The above way of doing things looks promising, but still isn't much good to me unless I can pass the string as a pointer rather than as a normal variable - where the problem comes in is needing the original string to be modified in addition to returning a value. A function like that took a string pointer as an argument would fit this, or a prototype function on String, provided that I can get some kind of writable handle. I can't just modify the original string inline with the rest of the code though - this operation needs to be performed many, many times, in a lot of different places and doing it with several (of the same) code lines every time would result in serious bulk.

Javascript strings appear to be immutable, just like Java ones. This means that you cannot change them after creation. You cannot modify an existing string, only create new strings from it. Javascript doesn't have pointers - all variables are references. When you pass a parameter no copying of objects takes place. When no references to an object exist any more, it will be garbage collected.

What exactly are you trying to do here? Perhaps with some context it might be easier to work out a way of performing the task in a clean way.

Erayd
21-12-2006, 01:18 AM
...but what would happen if another library or tool also tried to create a "shift" method?This will never happen here - ChatF1 is entirely my own creation, and written in a text editor - it uses no exteral libraries or tools. I also don't plan to use anything external, as it was partly a project that I could use to learn AJAX techniques. I also enjoy reinventing the wheel; I find it's a good way to learn new things. However you do raise a good point, and it's certainly something for me to bear in mind for other projects.


What exactly are you trying to do here? Perhaps with some context it might be easier to work out a way of performing the task in a clean way.What I am trying to do is write a parser for PHP serialized arrays that will take a string, and generate a multidimensional Javascript array from it. This saves the overhead of using XML parsers, but keeps all the things I was using XML for in the frst place. In order to get the data from the string, I need to read it in sections n characters long. The first thing I looked for was a shift method like Array has, but found there wasn't one. As it's a method I would use a lot elsewhere too, I decided to write it, as parsing strings of various types is something that the ChatF1 software needs to do a lot of, and at the moment the technique it uses is quite inefficient in terms of code bulk, and has a limited flexibility.


Javascript strings appear to be immutable, just like Java ones. This means that you cannot change them after creation. You cannot modify an existing string, only create new strings from it.If this is the case, is there some way to cause the original reference to point to something else(a new String containing the new value), and simply allow the old String to die?

Erayd
23-12-2006, 12:59 AM
^ bump

TGoddard
23-12-2006, 12:53 PM
Don't reinvent this particular wheel! It has already been solved a thousand times. Since you control both the server and the client (and security is not too mch of a concern) you can simply generate JSON on the server (using one of the many PHP JSON libraries) and eval it in the browser to get your array back out.

Why are you trying to split at a particular index here? The code for this is simple:



String.prototype.multiSplit = function(delimiters) {
delimiters = delimiters.slice();
var delimiter = delimiters.shift();
var output = this.split(delimiter);
if (delimiters.length > 0) {
for (var i = 0; i < output.length; ++i) {
output[i] = output[i].multiSplit(delimiters);
}
}
return output;
}


var myString = "This is one array;This is another"
myString.multiSplit([";", " "])

produces [["This","is","one","array"],["This","is","another"]]

This takes an array of delimiters and splits it into a multidimensional array. Notice that this method does not alter the original objects in any way as there is no good reason for it to do so.

When writing code you should try to be aware of which methods only access information from an object and which alter it ("mutators"). Mutators should be as simple as possible, it should be clear what they do and you should never use a mutator when you don't need to. By minimising side effects you make your code much more flexible and easier to debug.

About the naming thing - this is a valid point. Since this is a browser application, however, you must always assume that custom Javascript libraries may be loaded. Some vendors extend their implementation beyond the standard. It is easy enough to use a more descriptive name and will make your code more reliable.

Erayd
24-12-2006, 04:43 PM
Yeeehah, thanks TGoddard - I had no idea JSON existed, it's the perfect solution to my problem, and does it without abstracting so much that I don't learn anything. Time to get cracking on the next bit :D

Thanks again,
Bletch