Overwrite source variable with .split() result - javascript

Is there any trouble splitting variables that were previously split and overwrite the original variable while doing so?
Example:
arr = str.split(" ");
arr = arr[0].split("/");
I tested it and it works. But:
Is it risky to do this?
Will it behave as I expect at all times, and on all browsers?

That will be fine in all browsers. There's no risk.
You are simply assigning the variable arr to refer to something new, it doesn't matter what it used to refer to. (This doesn't actually "overwrite the older array", but if there are no other references to the old array the garbage collector will take care of it.)
You can also do it in one line:
arr=str.split(" ")[0].split("/");
Note that according to MDN, .split() always returns an array with at least one element, even if the source string was empty or didn't contain the separator.
EDIT: If both source string and separator are empty strings .split() seems to return an empty array. I.e., "".split("") returns []. Thanks Munim for pointing that out. (But "".split(" ") returns [""] so there will be no problem for purposes of this question.)

not risky at all if you know that arr is getting totally overwritten. It may be bad practice to do this for larger pieces of code or if other people are going to read it but there's nothing wrong with this logic-wise.
if you want to get more cryptic, try this:
arr=str.split(" ")[0].split("/");
of course you have to make sure that all the various pieces evaluate (if for instance, you have no spaces, then the [0] will be null and you'll get an error.
if you know that you ALWAYS have a space in str then this will be the hardest to read version of the code above ;)

Related

Is [0] equivelate to a space, and does the fact there is one part in different brackets matter?

var _$_f307 = ["className","animation-window","getElementsByClassName","body","animation-window animate","bl45","st.0ff","!!!","innerHTML","rocket-code";]
document[_$_f307[3]][_$_f307[2]](_$_f307[1])[0][_$_f307[0]] = _$_f307[4];
The given code sample is probably the result of code minification or obfuscation. To understand such code, it is a good idea to transform it into something more readable by replacing cryptic identifiers such as _$_f307[3] with their values, here "body":
document["body"]["getElementsByClassName"]("animation-window")[0]["className"] = "animation-window animate";
This is still a bit unreadable, so you could replace the bracket notation for property access with dot notation:
document.body.getElementsByClassName("animation-window")[0].className = "animation-window animate";
That's it, a readable line of JavaScript code which changes the CSS class of the first HTML element having class "animation-window". See https://developer.mozilla.org/en-US/docs/Web/API/Element/className for details.
PS: getElementsByClassName() returns an array and [0] returns the first value of that array. Most often, checking the documentation helps you to quickly find answers to such questions.

What's wrong with using join and match to implement an inArray in javascript?

I just came up with an inArray implementation for javascript and it's working fine.
Its weird but short, and i've got this feeling that there's something wrong with it, but i'm not sure what it is:
Array.prototype.inArray = function (itm) {
return this.join("|").match( new RegExp('\\b'+itm+'\\b','ig') );
}
UPDATE: this is supposed to be a general implementation of an inArray feature. I'm not sure which is more expensive, doing a loop or creating a regex
I don't know what your implementation requirements are, but keep these in mind:
you'll be matching a stringified version of the Array members, not the actual members
the \\b will allow any word break, including punctuation, giving false positives.
it would only be useful for single word entries in the Array, otherwise you could get false positives
you'll be returning null or and Array of "matches". Not sure if that's what you'd want.
I'm sure these just scratch the surface.
If you are implementing a very narrow functionality, it could work, but would be not be adequate for general use.
Use underscore.js intersection() method to find out if your array contain an element or even a series of elements:
if(_.intersection(yourArray, [item]).length){
//do stuff
}
you can check for multiple items by pushing them into an array too. It also covers any type of object

JavaScript String as Array: Read but no Write

For JavaScript in most browsers*, you can read a character from a String by treating it like an Array. However, in all the browsers I've tried (IE9, Chrome, Firefox), you can't write to it like an Array.
For example:
var string = 'hello world';
alert(string[0]);//alerts 'h'
alert(string);//alerts 'hello world'
string[0]='j';
alert(string[0]);//alerts 'h'
alert(string);//alerts 'hello world'
This has repercussions for more than just JavaScript developers:
jelloPeople.roam();
Does anybody know the reasoning behind this?
For example, I've looked at Mozilla's documentation, and they allude to it but don't give an explanation:
"..trying to set a character via indexing does not throw an error, but the string itself is unchanged."
Bottom Line: It is strange and confusing to me that some array properties were given to Strings and not others.
UPDATE:
Ok, so JavaScript Strings are immutable objects, but why? It seems like operations such as the above would be faster if they weren't immutable (change 1 character as opposed to making a new 11 character string). In fact, I don't see a case with String functions where performance would be impacted negatively if they weren't immutable, but I see several where performance would be improved. Also, there is no true multi-threading in JavaScript, so no advantage to immutables there.
(removed and will research this and possibly ask in a new quesion)
*Not IE 6 or 7
This simply because javascript strings are immutable by design; once created they cannot be changed.
I think it might be because strings in JavaScript are immutable. Notice that every string function doesn't actually change the string itself, but returns a new one. This is the same for changing characters directly, it wouldn't work with an immutable model.

Writing my own split method

I found out earlier today that split() doesn't work if attached to a single value.
I would like to write my own split() method so that if I sent it a single value, it creates an array with a single value.
Q: Should I change the split prototype or write a function?
var SPLIT=function(X) {
return X.toString().split()
}
To clarify, split() does work with a "single value". The problem in your last question was that the value returned was not a string, and hence the .toString() is necessary.
In my opinion, there's no need to write another function for this. Simply remember to convert your values to a string before calling .split() on it.
If you must have a function that does this, then to answer your question, create a new function and don't modify the prototype. While it may seem harmless to modify the prototype of Number or Object in this case, it's generally considered bad practice as other code (e.g. libraries you're using) may not be expecting it.

Are JavaScript strings immutable? Do I need a "string builder" in JavaScript?

Does javascript use immutable or mutable strings? Do I need a "string builder"?
They are immutable. You cannot change a character within a string with something like var myString = "abbdef"; myString[2] = 'c'. The string manipulation methods such as trim, slice return new strings.
In the same way, if you have two references to the same string, modifying one doesn't affect the other
let a = b = "hello";
a = a + " world";
// b is not affected
However, I've always heard what Ash mentioned in his answer (that using Array.join is faster for concatenation) so I wanted to test out the different methods of concatenating strings and abstracting the fastest way into a StringBuilder. I wrote some tests to see if this is true (it isn't!).
This was what I believed would be the fastest way, though I kept thinking that adding a method call may make it slower...
function StringBuilder() {
this._array = [];
this._index = 0;
}
StringBuilder.prototype.append = function (str) {
this._array[this._index] = str;
this._index++;
}
StringBuilder.prototype.toString = function () {
return this._array.join('');
}
Here are performance speed tests. All three of them create a gigantic string made up of concatenating "Hello diggity dog" one hundred thousand times into an empty string.
I've created three types of tests
Using Array.push and Array.join
Using Array indexing to avoid Array.push, then using Array.join
Straight string concatenation
Then I created the same three tests by abstracting them into StringBuilderConcat, StringBuilderArrayPush and StringBuilderArrayIndex http://jsperf.com/string-concat-without-sringbuilder/5 Please go there and run tests so we can get a nice sample. Note that I fixed a small bug, so the data for the tests got wiped, I will update the table once there's enough performance data. Go to http://jsperf.com/string-concat-without-sringbuilder/5 for the old data table.
Here are some numbers (Latest update in Ma5rch 2018), if you don't want to follow the link. The number on each test is in 1000 operations/second (higher is better)
Browser
Index
Push
Concat
SBIndex
SBPush
SBConcat
Chrome 71.0.3578
988
1006
2902
963
1008
2902
Firefox 65
1979
1902
2197
1917
1873
1953
Edge
593
373
952
361
415
444
Exploder 11
655
532
761
537
567
387
Opera 58.0.3135
1135
1200
4357
1137
1188
4294
Findings
Nowadays, all evergreen browsers handle string concatenation well. Array.join only helps IE 11
Overall, Opera is fastest, 4 times as fast as Array.join
Firefox is second and Array.join is only slightly slower in FF but considerably slower (3x) in Chrome.
Chrome is third but string concat is 3 times faster than Array.join
Creating a StringBuilder seems to not affect perfomance too much.
Hope somebody else finds this useful
Different Test Case
Since #RoyTinker thought that my test was flawed, I created a new case that doesn't create a big string by concatenating the same string, it uses a different character for each iteration. String concatenation still seemed faster or just as fast. Let's get those tests running.
I suggest everybody should keep thinking of other ways to test this, and feel free to add new links to different test cases below.
http://jsperf.com/string-concat-without-sringbuilder/7
from the rhino book:
In JavaScript, strings are immutable objects, which means that the
characters within them may not be changed and that any operations on
strings actually create new strings. Strings are assigned by
reference, not by value. In general, when an object is assigned by
reference, a change made to the object through one reference will be
visible through all other references to the object. Because strings
cannot be changed, however, you can have multiple references to a
string object and not worry that the string value will change without
your knowing it
Just to clarify for simple minds like mine (from MDN):
Immutables are the objects whose state cannot be changed once the object is created.
String and Numbers are Immutable.
Immutable means that:
You can make a variable name point to a new value, but the previous value is still held in memory. Hence the need for garbage collection.
var immutableString = "Hello";
// In the above code, a new object with string value is created.
immutableString = immutableString + "World";
// We are now appending "World" to the existing value.
This looks like we're mutating the string 'immutableString', but we're not. Instead:
On appending the "immutableString" with a string value, following events occur:
Existing value of "immutableString" is retrieved
"World" is appended to the existing value of "immutableString"
The resultant value is then allocated to a new block of memory
"immutableString" object now points to the newly created memory space
Previously created memory space is now available for garbage collection.
Performance tip:
If you have to concatenate large strings, put the string parts into an array and use the Array.Join() method to get the overall string. This can be many times faster for concatenating a large number of strings.
There is no StringBuilder in JavaScript.
The string type value is immutable, but the String object, which is created by using the String() constructor, is mutable, because it is an object and you can add new properties to it.
> var str = new String("test")
undefined
> str
[String: 'test']
> str.newProp = "some value"
'some value'
> str
{ [String: 'test'] newProp: 'some value' }
Meanwhile, although you can add new properties, you can't change the already existing properties
A screenshot of a test in Chrome console
In conclusion,
1. all string type value (primitive type) is immutable.
2. The String object is mutable, but the string type value (primitive type) it contains is immutable.
Strings are immutable – they cannot change, we can only ever make new strings.
Example:
var str= "Immutable value"; // it is immutable
var other= statement.slice(2, 10); // new string
Regarding your question (in your comment to Ash's response) about the StringBuilder in ASP.NET Ajax the experts seem to disagree on this one.
Christian Wenz says in his book Programming ASP.NET AJAX (O'Reilly) that "this approach does not have any measurable effect on memory (in fact, the implementation seems to be a tick slower than the standard approach)."
On the other hand Gallo et al say in their book ASP.NET AJAX in Action (Manning) that "When the number of strings to concatenate is larger, the string builder becomes an essential object to avoid huge performance drops."
I guess you'd need to do your own benchmarking and results might differ between browsers, too. However, even if it doesn't improve performance it might still be considered "useful" for programmers who are used to coding with StringBuilders in languages like C# or Java.
It's a late post, but I didn't find a good book quote among the answers.
Here's a definite except from a reliable book:
Strings are immutable in ECMAScript, meaning that once they are created, their values cannot change. To change the string held by a variable, the original string must be destroyed and the variable filled with another string containing a new value...
—Professional JavaScript for Web Developers, 3rd Ed., p.43
Now, the answer which quotes Rhino book's excerpt is right about string immutability but wrong saying "Strings are assigned by reference, not by value." (probably they originally meant to put the words an opposite way).
The "reference/value" misconception is clarified in the "Professional JavaScript", chapter named "Primitive and Reference values":
The five primitive types...[are]: Undefined, Null, Boolean, Number, and String. These variables are said to be accessed by value, because you are manipulating the actual value stored in the variable.
—Professional JavaScript for Web Developers, 3rd Ed., p.85
that's opposed to objects:
When you manipulate an object, you’re really working on a reference to that object rather than the actual object itself. For this reason, such values are said to be accessed by reference.—Professional JavaScript for Web Developers, 3rd Ed., p.85
JavaScript strings are indeed immutable.
Strings in Javascript are immutable

Categories