Faking goto in JavaScript


What if I told you JavaScript had a limited form of the infamous goto statement? Surprised? Read on.

Labeled Statements

It is possible to add label identifiers to JavaScript statements and then use these identifiers with the break and continue statements to manage program flow.

While it might be better to use functions instead of labels to jump around, it is worth seeing how to jump around or interrupt loops using these. Let’s take an example:

// print only even numbers
loop:
for(let i = 0; i < 10; i++){
    if(i % 2) {
        continue loop;
    }
    console.log(i);
}
//0, 2, 4, 6, 8

// print only values less than 5
loop:
for(let i = 0; i < 10; i++){
    if(i > 5) {
        break loop;
    }
    console.log(i);
}
// 0, 1, 2, 3, 4, 5

There is a subtle difference between when labels can be used:

  • break statements can apply to any label identifier
  • continue statements can only apply to labels identifying loops

Because of this, it is possible to have the sample code below (yes it’s valid JavaScript too!)

var i = 0;
block: {
     while(true){
         console.log(i);
         i++;
         if(i == 5) {
             break block;
             console.log('after break');
         }
     } 
}
console.log('outside block');
// 0, 1, 2, 3, 4, outside block

Note

  1. continue wouldn’t work in the above scenario since the block label applies to a block of code and not a loop.
  2. The {} after the block identifier signify a block of code. This is valid JavaScript and you can define any block by wrapping statements inside {}. See an example below
{
let i = 5;
console.log(i);
}

// 5

Should I use this?

This is an arcane corner of JavaScript and I personally have not seen any code using this. However if you have a good reason to use this, please do add comments and references to the documentation. Spare the next developer after you some effort…

Related

  1. What you didn’t know about JSON.Stringify
  2. Why JavaScript has two zeros: -0 and +0
  3. JavaScript has no Else If
Advertisements

What you didn’t know about JSON.Stringify


JSON, the ubiquitous data format that has become second nature to engineers all over the world. This post shows you how to achieve much more with JavaScript’s native JSON.Stringify method.

A quick refresher about JSON and JavaScript:

  • Not all valid JSON is valid JavaScript
  • JSON is a text-only format, no blobs please
  • Numbers are only base 10.

1. JSON.stringify

This returns the JSON-safe string representation of its input parameter. Note that non-stringifiable fields will be silently stripped off as shown below:

let foo = { a: 2, b: function() {} };
JSON.stringify(foo);
// "{ "a": 2 }"

What other types are non-stringifiable? 

Circular references

Since such objects point back at themselves, it’s quite easy to get into a non-ending loop. I once ran into a similar issue with memq in the past.

let foo = { b: foo };
JSON.stringify(foo);
// Uncaught TypeError: Converting circular structure to JSON

// Arrays
foo = [foo];
JSON.stringify(foo);
// Uncaught TypeError: Converting circular structure to JSON

Symbols and undefined

let foo = { b: undefined };
JSON.stringify(foo);
// {}
// Symbols
foo.b = Symbol();
JSON.stringify(foo);
// {}

Exceptions

Arrays containing non-stringifiable entries are handled specially though.

let foo = [Symbol(), undefined, function() {}, 'works']
JSON.stringify(foo);
// "[null,null,null,'works']"

Non-stringifiable fields get replaced with null in arrays and dropped in objects. The special array handling helps ‘preserve’ the shape of the array. In the example above, if the array entries were dropped as occurs in objects, then the output would have been [‘works’]. A single element array is very much different from a 4 element one.

I would argue for using null in objects too instead of dropping the fields. That way, we get a consistent behaviour and a way to know fields have been dropped.

Why aren’t all values stringifiable?

Because JSON is a language agnostic format.

For example, let us assume JSON allowed exporting functions as strings. With JavaScript, it would be possible to eval such strings in some scenarios. But what context would such eval-ed functions be evaluated in? What would that mean in a C# program?  And would you even represent some language-specific values (e.g. JavaScript Symbols)?

The ECMAScript standard highlights this point succinctly:

It does not attempt to impose ECMAScript’s internal data representations on other programming languages. Instead, it shares a small subset of ECMAScript’s textual representations with all other programming languages.

2. Overriding toJSON on object prototypes

One way to bypass the non-stringifiable fields issue in your objects is to implement the toJSON method. And since nearly every AJAX call involves a JSON.stringify call somewhere, this can lead to a very elegant trick for handling server communication.

This approach is similar to toString overrides that allow you to return representative strings for objects. Implementing toJSON enables you to sanitize your objects of non-stringifiable fields before JSON.stringify converts them.

function Person (first, last) {
    this.firstName = first;
    this.last = last;
}

Person.prototype.process = function () {
   return this.firstName + ' ' +
          this.lastName;
};

let ade = new Person('Ade', 'P');
JSON.stringify(ade);
// "{"firstName":"Ade","last":"P"}"

As expected, the instance process function is dropped. Let’s assume however that the server only wants the person’s full name. Instead of writing a dedicated converter function to create that format, toJSON offers a more scalable alternative.

Person.prototype.toJSON = function () {
    return { fullName: this.process(); };
};

let ade = new Person('Ade', 'P');
JSON.stringify(ade);
// "{"fullName":"Ade P"}"

The strength of this lies in its reusability and stability. You can use the ade instance with virtually any library and anywhere you want. You control exactly the data you want serialized and can be sure it’ll be created just as you want.

// jQuery
$.post('endpoint', ade);

// Angular 2
this.httpService.post('endpoint', ade)

Point: toJSON doesn’t create the JSON string, it only determines the object it’ll be called with. The call chain looks like this: toJSON -> JSON.stringify.

3. Optional arguments

The full signature stringify is JSON.stringify(value, replacer?, space?). I am copying the TypeScript ? style for identifying optional values. Now let’s dive into the replacer and space options.

4. Replacer

The replacer is a function or array that allows selecting fields for stringification. It differs from toJSON by allowing users to select choice fields rather than manipulate the entire structure.

If the replacer is not defined, then all fields of the object will be returned – just as JSON.stringify works in the default case.

Arrays

For arrays, only the keys present in the replacer array would be stringified.

let foo = {
 a : 1,
 b : "string",
 c : false
};
JSON.stringify(foo, ['a', 'b']);
//"{"a":1,"b":"string"}"

Arrays however might not be as flexible as desired,  let’s take a sample scenario involving nested objects.

let bar = {
 a : 1,
 b : { c : 2 }
};
JSON.stringify(bar, ['a', 'b']);
//"{"a":1,"b":{}}"

JSON.stringify(bar, ['a', 'b', 'c']);
//"{"a":1,"b":{"c":2}}"

Even nested objects are filtered out. Assuming you want more flexibility and control, then defining a function is the way out.

Functions

The replacer function is called for every key value pair and the return values are explained below:

  • Returning undefined drops that field in the JSON representation
  • Returning a string, boolean or number ensures that value is stringified
  • Returning an object triggers another recursive call until primitive values are encountered
  • Returning non-stringifiable valus (e.g. functions, Symbols etc) for a key will result in the field being dropped.
let baz = {
 a : 1,
 b : { c : 2 }
};

// return only values greater than 1
let replacer = function (key, value) {
    if(typeof value === 'number') {
        return value > 1 ? value: undefined;
    }
    return value;
};

JSON.stringify(baz, replacer);
// "{"b":{"c":2}}"

There is something to watch out for though, the entire object is passed in as the value in the first call; thereafter recursion begins. See the trace below.

let obj = {
 a : 1,
 b : { c : 2 }
};

let tracer = function (key, value){
  console.log('Key: ', key);
  console.log('Value: ', value);
  return value;
};

JSON.stringify(obj, tracer);
// Key:
// Value: Object {a: 1, b: Object}
// Key: a
// Value: 1
// Key: b
// Value: Object {c: 2}
// Key: c
// Value: 2

5. Space

Have you noticed the default JSON.stringify output? It’s always a single line with no spacing. But what if you wanted to pretty format some JSON, would you write a function to space it out?

What if I told you it was a one line fix? Just stringify the object with the tab(‘\t’) space option.

let space = {
 a : 1,
 b : { c : 2 }
};

// pretty format trick
JSON.stringify(space, undefined, '\t');
// "{
//  "a": 1,
//  "b": {
//   "c": 2
//  }
// }"

JSON.stringify(space, undefined, '');
// {"a":1,"b":{"c":2}}

// custom specifiers allowed too!
JSON.stringify(space, undefined, 'a');
// "{
//  a"a": 1,
//  a"b": {
//   aa"c": 2
//  a}
// }"

Puzzler: why does the nested c option have two ‘a’s in its representation – aa”c”?

Conclusion

This post showed a couple of new tricks and ways to properly leverage the hidden capabilities of JSON.stringify covering:
  • JSON expectations and non-serializable data formats
  • How to use toJSON to define objects properly for JSON serialization
  • The replacer option for filtering out values dynamically
  • The space parameter for formatting JSON output
  • The difference between stringifying arrays and objects containing non-stringifiable fields
Feel free to check out related posts, follow me on twitter or share your thoughts in the comments!

Related

  1. Why JavaScript has two zeros: -0 and +0
  2. JavaScript has no Else If
  3. Deep dive into JavaScript Property Descriptors

How to detect page visibility in web applications


You are building a web application and need the application to pause whenever the user stops interacting with the page; for example, the user opens up another browser tab or minimizes the browser itself. Example scenarios include games where you want to automatically pause the action or video/chat applications where you’d like to raise a notification.

The main advantage of such an API is to prevent resource wastage (battery life on mobile, internet bandwidth or unnecessary computing tasks). Definitely, something to have in mind especially for developers targeting mobile devices. So how would you this?

Can I use event listeners?

Technically, you could use a global event listener on the window object to listen for focus/blur events however, this can not detect browser minification. Also, the blur/focus event would be fired whenever the page loses focus; however, it is possible that a webpage is still visible despite losing focus – think about users having multiple monitors.

The good news is that this is possible with the PageVisibilityAPI which comes with the browsers and this post shows how to use this.

Deep dive into details

The Document interface has been extended with two more attributes – visibilityState and hidden.

Hidden

This is true whenever the page is not visible. What counts as being not visible includes lock screens, minimization, being in a background tab etc.

VisibilityState

This can be one of 4 possible enums explaining the visibility state of the page.

  • hidden: page is hidden, hidden is true
  • visible: page is visible, hidden is false
  • prerender: page is being pre-rendered and not visible. Support for this is optional across browsers and not enforced
  • unloaded: page is being unloaded; hidden would also be false too. Support for this is also optional across browsers

Show me some code!

document.addEventListener('visibilitychange',function(){
    if(document.hidden) {
        console.log('hidden');
    } else {
        console.log('visible');
    }
}, false);

Browser support

You can have it in nearly all modern browsers except Opera mini. Also, you might need to specify vendor prefixes for some of the other browsers. See this.

Conclusion

There it is; you now know a way to effectively manage resource consumption – be it battery, internet data or computing power.

You can use this to determine how long users spend on your page, automatically pause streaming video/audio (with some nice fadeout effects for audio especially) or even raise notifications.

Did you enjoy this post? Here are a few more related posts:

How to track errors in JavaScript Web applications


Your wonderful one-of-a-kind web application just had a successful launch and your user base is rapidly growing. To keep your customers satisfied, you have to know what issues they face and address those as fast as possible.

One way to do that could be being reactive and waiting for them to call in – however, most customers won’t do this; they might just stop using your app. On the flip side, you could be proactive and log errors as soon as they occur in the browser to help roll out fixes.

But first, what error kinds exist in the browser?

Errors

There are two kinds of errors in JavaScript: runtime errors which have the window object as their target and then resource errors which have the source element as the target.

Since errors are events, you can catch them by using the addEventListener methods with the appropriate target (window or sourceElement). The WHATWG standard also provides onerror methods for both cases that you can use to grab errors.

Detecting Errors

One of JavaScript’s strengths (and also a source of much trouble too) is its flexibility. In this case, it’s possible to write wrappers around the default onerror handlers or even override them to instrument error logging automation.

Thus, these can serve as entry points for logging to external monitors or even sending messages to other application handlers.

//logger is error logger
var original = window.onerror; //if you still need a handle to this
window.onerror = function(message,source,lineNo,columnNo,errObject){
    logger.log('error', {
        message: message,
        stack: errObject && errObject.stack
    });
    original() //if you want to log the original
    return;
}

var elemOriginal = element.onerror;
element.onerror = function(event) {
    logger.log('error', {
        message: event.message,
        stack: event.error.stack
    });
    elemOriginal();
    return;
}

The Error Object

The interface for this contains the error message and optional values: fileName and lineNumber. However, the most important part of this is the stack which provides information about the stack.

Note: Stack traces vary from browser to browser as there exists no formatting standard.

Browser compatibility woes

Nope, you ain’t getting away from this one.

Not all browsers pass in the errorObject (the 5th parameter) to the window.onerror function. Arguably, this is the most important parameter since it provides the most information.

Currently the only big 5 browser that doesn’t pass in this parameter is the Edge browser – cue the only ‘edge’ case. Safari finally added support in June.

The good news though is there is a workaround! Hurray! Let’s go get our stack again.

window.addEventListener('error', function(errorEvent) {
    logger.log('error', {
        message: event.message,
        stack: event.error.stack
    });
});

And that wraps it up! You now have a way to track errors when they happen in production. Happier customers, happier you.

Note: The eventListener and window.onError approaches might need to be used in tandem to ensure enough coverage across browsers. Also the error events caught in the listener will still propagate to the onError handler so you might want to filter out duplicated events or cancel the default handlers.

Related

Tips for printing from web applications

Liked this article? Please share, subscribe or drop a comment.

Understanding Bit masks


Bit masks enable the simultaneous storage and retrieval of multiple values using one variable. This is done by using flags with special properties (numbers that are the powers of 2). It becomes trivial to symbolize membership by checking if the bit at a position is 1 or 0.

How it works

Masking employs the bitwise OR and AND operations to encode and decode values respectively.

New composite values are created by a bitwise OR of the original composite and the predefined flag. Similarly, the bitwise AND of a composite and a particular flag validates the presence / absence of the flag.

Assuming we start off with decimal values 1,2,4 and 8. The table below shows the corresponding binary values.

Decimal Binary
0 0000
1 0001
2 0010
4 0100
8 1000

The nice thing about this table is that the four bits allow you to represent all numbers in the range 0 – 15 via combinations. For example, 5 which is binary 101, can be derived in two ways.

5     -> 1 + 4

or

101 -> 0001 | 0100

       -> 0101

7 which is 111 can also be derived in the same form.

Since any number in a range can be specified using these few ‘base’ numbers, we can use such a set to model things in the real world. For example, let’s say we want to model user permissions for an application.

Assuming the base permissions are read, write and execute, we can map these values to the base numbers to derive the table below:

Permissions Decimal Binary
None 0 000
Read 1 001
Write 2 010
Execute 4 100

Users of the application will have various permissions assigned to them (think ACL). Thus a potential model for visitor, reader, writer and admin roles with our base permissions is:

Role Permissions Decimal Binary
Visitors None 0 000
Readers Read 1 001
Writers Read + Write 3 011
Admins Read + Write + Execute 7 111

Noticed a pattern yet?

All the binary values can be obtained by ‘OR-ing’ the base binary values. For example, admins who have read, write and execute permissions have the value obtained when you do a bitwise OR of 1, 2 and 4.

The UNIX model uses the same numbering system. E.g. 777 translates into 111 111 111 which grants owners, groups and others read, write and execute permissions.

Checking Access

Now, the next question is how do you check if a composite value contains a particular flag? Going back to the binary data basics, this means checking if a bit at some position is a 1 or 0.

The bitwise AND operator comes in handy here – it guarantees a 1 when both values sharing the same index are 1 and 0 in all other cases. Thus, ‘AND-ing’ a composite value and the desired flag would reveal the desired outcome. If we get a value greater than zero as the result, then the user has the permission, otherwise a zero means there is no permission.

The admin role has a bitmask value of 111. To check if he really ‘has’ the execute permission we do a bitwise AND of 111 and the execute flag 100. The result is 100 which proves the permission.

More tables! The two tables show how to check for 2 users; one with the read + write + execute (111) permissions and another with the read and execute (101) permissions.

Read + Write + Execute (111)

Permissions 111 bitmask Binary Has permission?
Read 111 001 Yes: 111 & 001 → 1
Write 111 010 Yes: 111 & 010 → 1
Execute 111 100 Yes: 111 & 100 → 1

Read + Execute (101)

Permissions 101 bitmask Binary Has permission?
Read 101 001 Yes: 101 & 001 → 1
Write 101 010 No: 101 & 010 → 0
Execute 101 100 Yes: 101 & 100 → 1

See? Such a simple way to check without having to make unnecessary calls to the server.

Usage

This post shows the permission model however bit masks can be applied a wide variety of scenarios. Possible examples include checking membership, verifying characteristics and representing hierarchies.

A possible use in games could be to verify the various power-ups an actor has and to add new ones rapidly. Eliminates the need to iterate, use the bitmask.

Hierarchical models, where higher members encompass lower ones (e.g. the set of numbers) can also be adequately modeled using bitmaps.

Language support

Explicit language support is not needed to use bitmasks, the rules to know are:

  • Use increasing powers of 2 – ensures there is only one flag at the right spot
  • Create basic building blocks that are easy to extend and combine
  • Remember to watch out for overflows and use values that are large enough to hold all possible bit values. For example, C’s uint_8 / unsigned char can only hold 8 different flags, if you need more, you’d have to use a bigger value.

Some languages provide extra support for bit mask operations. For, example, C# provides the enum FlagsAtribute which implies that the enum would be used for bit masking operations.

Teaser

Q: Why not base 10? After all, we could use 10, 100, 1000 etc.

A: The decimal system falls short because you can have ten different numbers in one position. This makes it difficult to represent the binary ON/OFF state (which maps well to 0/1).

 

Safely handling destructive loops


Collections abound everywhere in the real world and loops are very common in programming. A simple loop is shown below:

var arr = [1,2,3,4];

for(var i = 0, len = arr.length; i < len; i++) {
    console.log(arr[i]);
}

//Output
1,2,3,4

Destructive loops

Simple loops can be boring, after all, why not have the collection change during a looping operation for more fun? Won’t happen? Believe me it does, have run into such at least twice.

An example scenario involves collections of listeners (say for example in a pub-sub implementation). Ideally, you want to go through all the listeners and invoke them. However it is possible a listener can either directly or indirectly remove itself while the loop is processing. For example, it might call a destroy function on some object which in turn leads to a unsubscribe call.

When this happens, it’s all chaos. Funny things happen or even worse – bugs.

Suddenly, the loop invariants are all wrong and you get funny results and/or errors (most likely errors). Let’s take an example:

function createListenerArray(arr) {
   for(var i = 0; i < 4; i++) {
       arr.push(function(i) {
           console.log(i);
           if(i === 2) {
               arr.splice(i, 1);
           }
       });
   }

   return arr;
}

The createListener function pushes 4 functions onto the array reference it gets. One of these functions (the third one) will remove itself from the array once invoked. To make tracking things easier, each function will log its index to the console.

var arr = [];
createListenerArray(arr);
for(var i = 0, len = arr.length; i < len; i++) {
    arr[i](i);
}

0
1
2
//TypeError: arr[i] is not a function

Oops! Blows up…

The loop was proceeding smoothly until it got to the function at index 2. Invoking that function changed the array by removing the corresponding entry from the array. Thus the valid length of the array decreased from 4 to 3.

The next step of the loop tried to access the element at index 3; however that index is now an invalid position since the element at index 3 got moved to index 2 when the array shrunk. arr[3] is undefined and invoking undefined as a function leads to the TypeError.

Imagine the ripple effect this can cause in larger arrays

Let’s try forEach.

var arr = [];
createListenerArray(arr);

arr.forEach(function(val, i){
    val(i);
});

0
1
2
undefined

This is not the desired result but on the bright side, at least there were no Exceptions. So what other approaches exist?

1. Clone

One way is to create a clone of the array to provide a validation checker before invocations as shown below.

var arr = [];
createListenerArray(arr);
var clone = arr.slice(0);

for(var i = 0, len = clone.length; i < len; i++) {
    if(arr.indexOf(clone[i]) > -1) {
        clone[i](i);
    }
}
//
0
1
2
3

This guarantees that the functions would always exist; to verify, we can re-run the snippet again to prove that the value at index 2 is now gone.

for(var i = 0, len = clone.length; i < len; i++) {
if(arr.indexOf(clone[i]) > -1) {
        clone[i](i);
    }
}

//Output
0
1
3

2. Count down

Cloning can lead to new issues with memory allocation and garbage collection. There is another approach that is cleaner, doesn’t require cloning and should not leave danglers around.

The fix relies on understanding the true cause of the looping issue. The problem occurs because the removal of a loop element affects unprocessed elements in the loop (by changing the array length).

We can circumvent this by counting down from right to left – if an element removes itself, the unprocessed elements to the left are not affected since their indices are still valid (compare to the left-to-right count-up approach).

Now, even if a function should remove itself, things are still alright, since its index would be removed and not be valid anymore.

let arr = [];
createListenerArray(arr);

for(var i = arr.length - 1; i >= 0; i--) {
    arr[i](i);
}

//Output
3
2
1
0

console.log(arr.length);
//3

Neat! Now, this is another reason to use utils like _.forEachRight.

Liked this trick? Let me know your thoughts.