Asked  7 Months ago    Answers:  5   Viewed   34 times

Is there a commonly accepted technique for efficiently converting JavaScript strings to ArrayBuffers and vice-versa? Specifically, I'd like to be able to write the contents of an ArrayBuffer to localStorage and to read it back.

 Answers

81

Update 2016 - five years on there are now new methods in the specs (see support below) to convert between strings and typed arrays using proper encoding.

TextEncoder

The TextEncoder represents:

The TextEncoder interface represents an encoder for a specific method, that is a specific character encoding, like utf-8, iso-8859-2, koi8, cp1261, gbk, ... An encoder takes a stream of code points as input and emits a stream of bytes.

Change note since the above was written: (ibid.)

Note: Firefox, Chrome and Opera used to have support for encoding types other than utf-8 (such as utf-16, iso-8859-2, koi8, cp1261, and gbk). As of Firefox 48 [...], Chrome 54 [...] and Opera 41, no other encoding types are available other than utf-8, in order to match the spec.*

*) Updated specs (W3) and here (whatwg).

After creating an instance of the TextEncoder it will take a string and encode it using a given encoding parameter:

if (!("TextEncoder" in window)) 
  alert("Sorry, this browser does not support TextEncoder...");

var enc = new TextEncoder(); // always utf-8
console.log(enc.encode("This is a string converted to a Uint8Array"));

You then of course use the .buffer parameter on the resulting Uint8Array to convert the underlaying ArrayBuffer to a different view if needed.

Just make sure that the characters in the string adhere to the encoding schema, for example, if you use characters outside the UTF-8 range in the example they will be encoded to two bytes instead of one.

For general use you would use UTF-16 encoding for things like localStorage.

TextDecoder

Likewise, the opposite process uses the TextDecoder:

The TextDecoder interface represents a decoder for a specific method, that is a specific character encoding, like utf-8, iso-8859-2, koi8, cp1261, gbk, ... A decoder takes a stream of bytes as input and emits a stream of code points.

All available decoding types can be found here.

if (!("TextDecoder" in window))
  alert("Sorry, this browser does not support TextDecoder...");

var enc = new TextDecoder("utf-8");
var arr = new Uint8Array([84,104,105,115,32,105,115,32,97,32,85,105,110,116,
                          56,65,114,114,97,121,32,99,111,110,118,101,114,116,
                          101,100,32,116,111,32,97,32,115,116,114,105,110,103]);
console.log(enc.decode(arr));

The MDN StringView library

An alternative to these is to use the StringView library (licensed as lgpl-3.0) which goal is:

  • to create a C-like interface for strings (i.e., an array of character codes — an ArrayBufferView in JavaScript) based upon the JavaScript ArrayBuffer interface
  • to create a highly extensible library that anyone can extend by adding methods to the object StringView.prototype
  • to create a collection of methods for such string-like objects (since now: stringViews) which work strictly on arrays of numbers rather than on creating new immutable JavaScript strings
  • to work with Unicode encodings other than JavaScript's default UTF-16 DOMStrings

giving much more flexibility. However, it would require us to link to or embed this library while TextEncoder/TextDecoder is being built-in in modern browsers.

Support

As of July/2018:

TextEncoder (Experimental, On Standard Track)

 Chrome    | Edge      | Firefox   | IE        | Opera     | Safari
 ----------|-----------|-----------|-----------|-----------|-----------
     38    |     ?     |    19°    |     -     |     25    |     -

 Chrome/A  | Edge/mob  | Firefox/A | Opera/A   |Safari/iOS | Webview/A
 ----------|-----------|-----------|-----------|-----------|-----------
     38    |     ?     |    19°    |     ?     |     -     |     38

°) 18: Firefox 18 implemented an earlier and slightly different version
of the specification.

WEB WORKER SUPPORT:

Experimental, On Standard Track

 Chrome    | Edge      | Firefox   | IE        | Opera     | Safari
 ----------|-----------|-----------|-----------|-----------|-----------
     38    |     ?     |     20    |     -     |     25    |     -

 Chrome/A  | Edge/mob  | Firefox/A | Opera/A   |Safari/iOS | Webview/A
 ----------|-----------|-----------|-----------|-----------|-----------
     38    |     ?     |     20    |     ?     |     -     |     38

Data from MDN - `npm i -g mdncomp` by epistemex
Tuesday, June 1, 2021
 
themihai
answered 7 Months ago
96

Scroll down to the Conclusion section on the page you linked and download the provided NSData+Base64 files. Its the best solution I have seen so far and is incredibly easy to use. If you can learn anything about Cocoa, you can learn to use that project.


Example

NSString *originalString = [NSString stringWithFormat:@"test"]; 
NSData *data = [NSData dataFromBase64String:originalString];  
NSLog([data base64EncodedString]); 

The above will print out the original string after converting it to base64 and back to a normal unencoded string.

Saturday, June 12, 2021
 
Besnik
answered 6 Months ago
16

For a start, here is a simple example of custom serialization / deserialization:

function Person( name, sex, age ) {
    this.name = name;
    this.sex = sex;
    this.age = age;
}

Person.prototype.serialize = function () {
    var obj = this;
    return '{ ' + Object.getOwnPropertyNames( this ).map( function ( key ) {
        var value = obj[key];
        if ( typeof value === 'string' ) { value = '"' + value + '"'; }
        return '"' + key + '": ' + value;
    }).join( ', ' ) + ' }';
};

Person.deserialize = function ( input ) {
    var obj = JSON.parse( input );
    return new Person( obj.name, obj.sex, obj.age );
};

Usage:

First, we create a new instance object:

var person = new Person( 'John', 'male', 25 );

Now, we serialize that object into a string using the Person.prototype.serialize method:

var string = person.serialize();

This will give use this string:

{ "name": "John", "sex": "male", "age": 25 }

Finally, we deserialize that string using the Person.deserialize static method:

var person2 = Person.deserialize( string );

Now, person2 is an instance of Person and contains the same property values as the original person instance.

Live demo: http://jsfiddle.net/VMqQN/


Now, while the Person.deserialize static method is required in any case (it uses JSON.parse internally, and invokes the Person constructor to initialize a new instance), the Person.prototype.serialize method on the other hand, is only needed if the built-in JSON.stringify static method doesn't suffice.

In my example above var string = JSON.stringify( person ) would get the job done too, so a custom serialization mechanism is not needed. See here: http://jsfiddle.net/VMqQN/1/ However, your case is more complex, so you'll need to define a custom serialization function.

Wednesday, August 4, 2021
 
Jonesome Reinstate Monica
answered 4 Months ago
49

Those pseudo-properties you are seeing are something the developer console is putting there for your benefit. They aren't really there at all, as a property or a symbol (AFAIK), and even if they were it would be non-standard.

You can easily get a Uint8Array view of your buffer the standard way like this though:

new Uint8Array(myBuffer)
Sunday, August 22, 2021
 
Felipe Hoffa
answered 4 Months ago
12

It appears there isn't a more straightforward way to accomplish this.

Saturday, September 18, 2021
 
vlatkozelka
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share