Next JavaScript Harmony and JS 1.7 – A brief Introduction and Examples

Introduction


ECMAScript  http://www.ecmascript.org ) of which  JavaScript is one of several popular implementations, is globally the most distributed and most widely used programming language which is bundled with a fully integrated IDE (e.g. www.chromium.org/devtools/google-chrome-developer-tools-tutorial ) .
Arguably it is also the most misunderstood language. Given the tremendous shift in programming style  JavaScript has seen over the past ten years, the aspect of JavaScript being (initially) misunderstood has definite merit.
It is no surprise that JavaScript's significance can hardly be underestimated, and various influential factions (e.g. Google, Microsoft, Mozilla,..) have disparate ideas regarding its syntactic future direction.
However, for the near term future, many parties agreed to at least harmonize in the creation of a JavaScript testbed called JavaScript Harmony (interim codename). Widely new and enticing features have already been proposed years ago (see the ES4 proposal [pdf]) along with proof of concept implementations.


At the 24th December of 2011, the Dev Google Chrome team  released a Canary build (i.e. experimental) that is up to snuff with the JS Harmony features Mozilla users have had access to for a considerable while.
These features can be enabled by typing in about:flags into the Chrome address bar, and clicking on “Enable Experimental JavaScript” at the bottom of the feature list.

Note: Not all features listed herein will necessarily work in the various Browser-platforms

Features

Herein the most important features compiled over the last couple of months are presented. It does not aim at completeness, but rather at providing an overview of some of the most significant new features.

Let’s get started with detecting JS Harmony.

typeof null == 'null' && typeof null === 'null'
//>true
typeof null == 'object' && typeof null == 'object'
//>false


The most important aspects which have to a certain degree found their way into Google's Dart ECMAScript-like-language implementation,  are:

OOP

Class based inheritance in addition to prototypal linking (loading) of objects. Inheritance properties resemble those of C++, C# and Java.
Notably the keyword class was reserved for over 10 years since JS 1.0
Sticking to OOP rather than prototypal trees might put an end to 
0..constructor.constructor('alert("Never. Over my dead eval!")')()
Owing to the fine granularity of class inheritance and security.

Strong Typing

Strong typing allows fast JIT compilation/optimization,  unit testing within static code analysis, and can effectively put an end to a lot of weird behavior that almost all web-developers encountered at some point. At the immediate level, adhering to strong typing means more effective code-size and code-care, - a nuisance if you just want to tinker around on the interactive interpreter command line.
The syntax resembles ActionScript 3.0. Type inference is usually one of the main speed tradeoffs of dynamically typed programming languages. A new method for fast type inference for Javascript was recently proposed ( Fast and Precise Hybrid Type Inference for JavaScript, Author NA; The Impact of OptionalType Information on JIT Compilation of Dynamically TypedLanguages, University of California, Adobe and Mozilla; and Static Type Inference for Ruby  ; See this blog post on the Mozilla website ) 
Let me know what you think about enforcing types at the language level of ECMAScript.


Strict mode - Compile Time Type Checking
A  “strict” mode performs basic unit and security checks prior to code execution. Verifications encompasses static type checking, illegal constant assignment, equality-assertions and lookup of variable references.

Namespaces

Namespacing was rather limited to (global) objects, manifested in the use of the with statement and indeed much hated thus far. The with statement allows resolving or rather importing variables from a given object.
e.g. with( {x: window.console, y: window.document} ){...}
JavaScript 2.0 (of which JS Harmonay is an intermediate but very close step) proposes a dedicated pre-declared global object for holding namespace objects. This results in speed improvements (i.e. easier to separate global from namespace variables) and less chance of overwriting valuable data.


Constants

Prior to JS Harmony, constants in JS did at best only exist as programming conventions, dictated as UPPERCASING notation, such as in Google’s JavaScript Code Conventions (Note the document's corresponding XSL ) which is loosely based on Crockfords prior suggestions ; See also here  for more JS Style Guides )
/**
 * The number of seconds in a minute.
 * @type {number}
 */

goog.example.SECONDS_IN_A_MINUTE = 60;

With JS Harmony a “const” keyword is  introduced to store and lock constants. Notably since everything in JavaScript is an Object a workaround for protecting objects against overwriting was to extend native Objects or if the Object is user-defined, by applying the defineProperty method.

e.g.
const var SECONDS_IN_A_MINUTE = 60;

//const has block scope, like let

//Naturally the native Object string is ‘protected’ against overwriting and changes throwing a definePropertyError in the process of trying to change any attributes.

 Object.defineProperty(String, "length", {
        value: 101,
        writable: true,
        enumerable: true,
        configurable: true
    });

Program Units

Modules allow to decrease resource and bandwidth usage by storing initially unused code-parts in separate units, in a similar fashion to ActionScript 3 library methodology. But there is a lot more to modules as shown in here.

The specifications for the modular system are formally defined here [pdf] 
Modules too are Objects, as virtually everything in JS (with two exceptions), and have the following features

  • Static scoping
  • Orthogonality from existing features
  • Smooth refactoring from global code to modular code
  • Fast compilation
  • Simplicity and usability
  • Standardized protocol for sharing libraries
  • Compatibility with browser and non-browser environments
  • Easy external loading
Modules differ from traditional Object usage, in that the keyword export has to be used before a variable e.g. export var s = ‘…’; to enable access of this variable from an outside scope.

    module Sequence {
                var s1 =’’;
                var sm_hamming = function(s1,s2){                    var i,cnt=0; for(in s1,s2) { x[i]==y[i] ||cnt++; }; 
                    return cnt; };
                //nested Modules
                module StringMetrics(){
                  ...
                }
        export sm_hamming;
        export var s2 = ’gattaca’;
    }

The variables within the scope can then be accessed like any other Object:
console.log(Sequence .sm_hamming(test, Sequence.s2) , Sequence.s2 );
//importing will resolve the Object’s scope similar to Python’s Module keywords from mod import a,b ; //from mod2 import *  http://docs.python.org/tutorial/modules.html
import Sequence.{ sm_hamming, s2};
console.log(sm_hamming(test, s2) , s2 );
//it likely didn’t elude the readers attention that the purpose and syntax is very similar to the with statement :)
//Indeed!
import BioTools.{PProc: SequencePreProcessor, Conv: SequenceDumpBed }, Sequence.StringMetrics;
 
Lastly files can be loaded as follows. See also RequireJS  http://requirejs.org/docs/commonjs.html as part of CommonJS.
//this process differs somewhat from Python's logic of adding the modules path first
//import sys
//sys.path.append('/ufs/guido/lib/python')
//import …mymodule with each folder-nesting being resolved by ‘.’

module JSON = require('http://json.org/modules/json2.js');
module fileIO = require('io/DFS');
   
//direct import of modules
import require("bioTools.js").Sequence;


//Modules allow reflection
module M0 = Sequence; // primary instance
var M1 = Sequence; // dynamic reference to M0 module instance
console.log(Object.keys( M0. s2 + M1.s2 ) )


let-statement resolves the past issues of with

The let statement works out the kinks of with. The with statement adds another object to the global JS object scope chain. The prototype chain can sometimes be very long and costly to traverse.
For an example on the impact of speed, compare the following Code examples. In the first instance the iteration variable is linked to the global JS scope in the latter  loop-example the variable is within the local scope of a closure, and executes much faster

{for(var i=10000000;i--;i){}}
//The following code executes between 10-30x faster
(function(){for(var i=10000000;i--;i){}})()

 Let denotes variables within the current execution scope, so that the interpreter only has to generally search only one additional object.

//new: blocked scopes with the let statement
var a = 10;
let (        a = a * 10
                ,b = a + 1) {
    console.log("a is" + a + ", b is " + b);
}

//before, blocked scopes with the with statement
var a = 10;
with(     {a: a * 10
                ,b : a + 1} ){
    console.log("a is" + a + ", b is " + b);
}
//x is 100, b is 11

//Showing the blocked scope
var a = 3,b = 5;
console.log( “local scope / before let statement:  a is" + a + "; b is" + b);
             
let (a=7, b=11) {
                console.log( “blocked scope / in the let statement:  a is"
 + a + "; b is" + b);
}

console.log( “local scope / after let statement:  a is" + a + "; b is" + b);

Variable extraction / destructuring assignment
var a=3, b=5, c = 7;
[a, b, c] = (function(){return [1,,2]; })();
console.log(‘a, b, c is:’ + [a,b,c])
//> a, b, c is:1,,2
//swapping
[a,b] = [b,a]
//CC direction reversal
[a,b,c] = [c,b,a]
//decomposed comparison is not implemented
[a,b] === [a,b] || [a,b] == [a,b]
//>false
 //use
''+[a,b] === ''+[a,b]
//>true


Generators
//these are just as in Python & Co

function xrange(start,stop,step) {
                for (let i=start; i<stop; i+=step) {
                               yield i;
                }
}

var x = xrange ()
,_list  = [];
for (var i=0; i<100; i++) {
                _list.push( x.next() );
}


Iterators

var _iList  = {
                name : "Some vertex",
                begin : "0",
                end: "1",
                label : “Vertex from 0 to 1
};

var iterObj = Iterator( _iList )
                ,values  = []
                ,nextItem;
try{
                for (;;) {
                               nextItem = iterObj.next();
                               values.push( nextItem[0] + " = >" + nextItem[1] );
                }
}
//variable error handlers, since JS 1.5
catch (err if err instanceof StopIteration) { 
                resultValues.push("End of the List");
}
catch (err) { 
                resultValues.push("NA  ERROR");
}

//with let destructured assignment
for (let [key, value] in Iterator(_iList )) {
                console.log( key, value);
}

for each ( let { name: n, family: { father: f } } in obj )
    print("Name: " + n + ", Father: " + f);

//functions with destructuring
function f( { "key": val } )
{...
}

Array comprehensions
//..as in python

function xrange(start,stop,step) {
                for (let i=start; i<stop; i+=step) {
                               yield i;
                }
}
var modValue = [for each (in xrange(0, 100, 2)) if (0 ===i % 4)];

[ i*for (i of [1,2,3,4,5,6,7,8,9,10]) ]

//3D Matrix
[ [i,j,k] for (i of rows) for (j of columns)  for(k of slices)]

Classes

//Example taken from the ECMAScript proposal project, based on the WebGL library Three.JS

class SkinnedMesh extends THREE.Mesh {
  constructor(geometry, materials) {
    super(geometry, materials);

    public identityMatrix = new THREE.Matrix4();
    public bones = [];
    public boneMatrices = [];
    ...
  }

  update(camera) {
    ...
    super.update();
  }
}

Weakmaps
Weakmaps as introduced in one of my first blog posts, will be discussed in a separate blog post in connection to Spectra-Data.
Basically an array of keys would keep references to the key objects thus preventing them from being garbage collected. WeakMaps holds references exclusively "weakly", meaning garbage collection is not impeded in case no other references to the key'ed object is found.

In contrast to a Map , a WeakMap is not enumerable.In Google's V8 Maps have not been iterable either thus far and thus have been the same performance-wise.
var _map = new Map();
var _obj = {a: "element1", b: “element2” };
_map.set(obj, "element1");
_map.get(obj);
 

Proxy - Get hooked!


A Proxy allows the creation of objects with dynamically computed properties during run-time. One use is to hook into other object instances and report, log and reflect upon these. Useful for meta-programming, and already known to many web-programmers as a set of Magic functions as for instance in PHP

var proxyMagic = Proxy.create({
  get: function(obj, propertyName) {
    return 'Proxy -  '+ propertyName;
  }
});
 
console.log(proxyMagic.runTimeProperty);
//> Proxy - runTimeProperty 

Set

These are weakly linked, compact lists as part of the Collections package, defined as follows (ES wiki)

  class Set {
constructor() {
private map = Map();
}
has(key) { return private(this).map.has(key); }
add(key) { private(this).map.set(key, true); }
delete(key) { return private(this).delete(key); }
// todo: iteration
}


Example:
var _set = new Set();
_set.add(3);
_set.has(5); //false
_set.had(7); //false


Overview of the Harmony proposals:


A lot of new, exciting things that are proposed with most of these likely to be put to use in JavaScript 2.0

Have phun and a great year ahead!
LihatTutupKomentar