1

Ok peep's so I know it's bad practice to mess with prototypes but here it is anyway...


Array.prototype.rev=
    function(){
        this.reverse();
    }

Works fine! Updates the source array variable, ary, as expected eg:

ary = [123, 456];
ary.rev();

// result:  ary == [456, 123]

My problem comes when writing a similar property for String.

What I would like to do is something like this...

String.prototype.rev=
    function(){
        this.split('');
        this.reverse();
        this.join('');
    }

Seems simple enough right! Split the string, reverse it, and join it back together so the original string variable, str, is a reverse of it's former self, as was with the ary above!

Thing is: Although this.split() has been called it needs to be stored as a variable, ie:

split = this.split('');

And there-in lies the this = this problem...

Now split is defined, it takes the focus away from editing the source variable and it's not like I can just say at the end of the function:

this = split;

As this is 'immutable' or what ever it is when they mean it is static and unchangeable?


Getting to the point! My Question is this...

str = 'abc'

I want to be able to say str.rev() not str = str.rev() and get the result of str = 'cba' where str === 'cba', catch my drift?!

All work-around's and tuition welcome peep's, I just ask that u know what ur talkin' 'bout. thx

LostInCyberSpace
  • 413
  • 4
  • 19
  • 7
    The String objects in JavaScript are immutable. So you cannot change them. – thefourtheye Jan 26 '15 at 10:19
  • Interestingly, the spec (at least the ES5 version) doesn't seem to actually *say* strings are immutable anywhere -- it just doesn't define any way of changing them, and so they're immutable by fiat. – T.J. Crowder Jan 26 '15 at 10:36
  • maybe something to look into for the next version? seems silly not to have the option... – LostInCyberSpace Jan 26 '15 at 10:46
  • @LostInCyberSpace: Not to be able to modify strings in place? Having immutable strings is generally a Good Thing, not least because it lets the JavaScript engine combine strings used in various different places to reduce memory overhead. Strings are immutable in a many modern languages, including Java (although you can hack them with reflection) and C#. – T.J. Crowder Jan 26 '15 at 10:52
  • Best thing is just to post questions to SO. Someone will help. – T.J. Crowder Jan 26 '15 at 11:29

1 Answers1

7

My problem comes when writing a similar property for String...

The main issue here is that strings are immutable in JavaScript; you cannot change a string in place. Because of that, it's impossible to define a rev method that would behave like this:

var a = 'abc';
a.rev();        // <== This can't work this way
console.log(a); // cba

Instead, your rev should do what all other String methods do: Return a new string with the updates.

A secondary issue is that your code in your rev method doesn't work, because you're not saving the results of things like this.split(''); anywhere, but the way split works, it returns an array with the entries.

Here's a version of rev that addresses both issues:

String.prototype.rev=
    function(){
        return this.split('').reverse().join('');
    };

Then:

var a = 'abc'.rev();
console.log(a);  // cba

Example:

String.prototype.rev = function(){
  return this.split('').reverse().join('');
};

var a = 'abc'.rev();
snippet.log(a);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

This is how all of the standard string methods (toLowerCase, replace, substring, ...) work, by returning the result.


The all-on-one-line version might not be hyper clear (and is hard to debug), here's the split-apart version for clarity:

String.prototype.rev=
    function(){
        var characters = this.split('');
        characters.reverse();
        return characters.join('');
    };

(Note that Array#reverse reverses the array in place and returns the array reference; the fact it also returns the array reference is what makes the all-in-one-line version possible.)


Side note: If you're going to play around with prototypes, consider using Object.defineProperty rather than just assigning:

Object.defineProperty(String.prototype, "rev", {
    value: function() { ... }
});

...so that the new properties are non-enumerable (don't show up in for-in loops). Doesn't matter that much with String, but a lot of people still incorrectly use for-in for looping through arrays, so...

Example:

Object.defineProperty(String.prototype, "rev", {
  value: function(){
    return this.split('').reverse().join('');
  }
});

var a = 'abc'.rev();
snippet.log(a);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • so it needs to be a chain based return, not individual statements? ill give it a go... – LostInCyberSpace Jan 26 '15 at 10:25
  • 1
    @LostInCyberSpace: There are two changes, I should have highlighted that. 1) Just writing `this.split('');` doesn't do anything, because while it splits the string, you are then just throwing away the resulting array. You have to save that somewhere. In this case, since all you're doing with that array is reversing it and then joining it, I could write it all on one line. 2) You need to *return* the result of your overall operation. – T.J. Crowder Jan 26 '15 at 10:28
  • forgive me @T.J.Crowder i use both `Object.defineProperty` & `Object.defineProperties` this is just short-hand! – LostInCyberSpace Jan 26 '15 at 10:33
  • @T.J.Crowder, could you please elaborate your answer why returning make immutable to be mutable or something that works... – Bhojendra Rauniyar Jan 26 '15 at 10:33
  • @BhojendraNepal: I don't understand what you're asking. The above works. You can't modify strings in-place in JavaScript, because the spec doesn't define any mutator methods for them. At all. So they're immutable until/unless a future specification chooses to create mutator methods for them (which is ***extremely*** unlikely). – T.J. Crowder Jan 26 '15 at 10:37
  • @T.J.Crowder: enlighten me anyway... i'm still using (for...in)?! – LostInCyberSpace Jan 26 '15 at 10:41
  • You mean using return is a mutator method? Any link would describe better. Thanks. – Bhojendra Rauniyar Jan 26 '15 at 10:42
  • @BhojendraNepal: No. Strings are immutable. Using `return` returns a **new** string, it doesn't change the one you're operating on. `toLowerCase` isn't a mutator method; a mutator method is a method that changes the object you call it on, like `Array#sort` does. None of `String`'s methods do that. – T.J. Crowder Jan 26 '15 at 10:42
  • @LostInCyberSpace: All the gory details: http://stackoverflow.com/questions/9329446/for-each-over-an-array-in-javascript/9329476#9329476 – T.J. Crowder Jan 26 '15 at 10:42
  • @T.J.Crowder: So it can't be done the way i want `'abc'.rev()` as opposed to `var a = 'abc'.rev()` as although strings are NOT immutable there is yet no possible way of achieving this goal?! – LostInCyberSpace Jan 26 '15 at 10:54
  • @LostInCyberSpace: Strings are immutable in JavaScript, and so your `rev` cannot work as you've asked. The fact that the spec appears to make them immutable by fiat (not specifying any way to change them) rather than an explicit "strings are immutable" statement doesn't matter one way or the other; they're immutable either way, and I very much doubt that will ever change. You can only implement `rev` as above, *returning* a new string, just as all the other `String` methods do. – T.J. Crowder Jan 26 '15 at 11:06