proj-plbook-plChJavascriptLang

Table of Contents for Programming Languages: a survey

Because it is so well-known, Javascript gets its own chapter.

Tutorials/online books:

Best practices and style guides:

Respected exemplar code:

Retrospectives:

Features

Variadic functions and reified arguments objects

Weak references

(as of this writing, a future feature)

And there is an option to be notified after the garbage-collection of weak references; see https://news.ycombinator.com/item?id=9735973 .

ES6 overview

Opinions

"I tried Javascript and found callbacks to be a crime against humanity, found a better concurrency model in Go, but found rather simple things that it couldn't express and Python could." -- [14]

Criticisms

Equality with implicit type conversion

Javascript is often [26] [27] criticized for its '==' operator, which is equality after implicit type conversion. Javascript also has an '===' operator which is a more typical equality.

Links:

Javascript criticism links

Other lists of criticisms

Gotchas

https://t.co/oK7NETXW5A

" ...All too often, people try to do something like declare a var inside a loop, and spin off a closure that captures that var. The reasonable assumption is that the scope of the variable is the body of the loop, and thus every iteration gets its own new copy, and all closures are independent.

In reality, all closures get the same variable, and if it is the loop counter or derived from it, and closures are executed later, then they will all see the same value - the one that said variable had after the last iteration. It's even worse if closures try to write to it.

This is something that is peculiar to JS. In most other languages, there's no similar issue, because either local variables can't be declared inside loops (or, indeed, at all, treating assignment as implicit declaration), as in Python or Ruby; or if they can, then their scope is what you'd expect it to be, as in C#, Java etc.

Writing async code using closures as continuations is not unique to JS, either. All mainstream languages support this now.

z3t4 65 days ago [-]

What you describe is the moment someone would usually go from PITA to Ninja! From programming sequential to async using functions. The WTF code:

  for(var i=0; i < textures.length; i++) {
    textures[i].onload = function (i) {
      pattern[i] = ctx.createPattern(textures[i], 'repeat');
    }
  }

The enlightenment:

  for(var i=0; i < textures.length; i++) {
    createPattern(i);
  }
  function createPattern(i) {
    textures[i].onload = function() {
      pattern[i] = ctx.createPattern(textures[i], 'repeat');
    }
  }

In JavaScript? you can now however replace var with let and it will be block scoped and the WTF code will work. It's sad though as people learning JavaScript? now will not get the beauty of it and will be stuck in callback hell. Function scope in JavaScript? pushes you in the right direction. It's like instead of teaching people how to fly, we give them roads so they can walk, like they are used to.

int_19h 62 days ago [-]

It's way more than just async callbacks. For example, you may be using a lazy sequence abstraction, with high-order functions like the usual map/filter/reduce, but with a deferred implementation (i.e. they're only applied, and functions passed as arguments are evaluated, when the next item is read from the sequence). If you create such deferred sequences inside a loop, they will again capture the mutated counter.

" [28]

for (k in ['a', 'b']) {
      console.log(k);
    }

returns undefined, and print "0", "1" (eg, the keys of the list-like associative array) to the log.

piva00 38 minutes ago

...JavaScript? has a lot of quirks like the '==' vs '===', empty arrays equalling to false or this kind of stuff: http://stackoverflow.com/a/1995298/398142

...

" There's plenty not to like about JavaScript?, but the biggest mess is this:

js> x = 1 1 js> z = x.y js> ...

In other words: it's not an error to access an attribute of an object which isn't there ...

The fact that sometimes unknown things are 'undefined' and sometimes they're 'null' and sometimes they're '"undefined"' and sometimes they're the empty string and sometimes they're 0 really compounds this problem. Python has None, Ruby has nil, and nobody uses random ad-hoc sentinel values because why would you do that? " -- [29]

vs node:

 "Basic maths assumptions like commutativity are out of scope.
 ...
  [] + {} '[object Object]' > {} + [] 0" [35] [36]

Links:

Open Source Implementations

JIT implementations:

Implementations written in Javascript:

Minimalistic or embedded implementations:

Random notes:

" The people who are working on V8 also created the Self VM (to this day one of the fastest dynamic OO language execution engines ever created), the Animorphic Smalltalk VM (to this day one of the fastest Smalltalk execution engines ever created), the HotSpot? JVM (the fastest JVM ever created, probably the fastest VM period) and OOVM (one of the most efficient Smalltalk VMs ever created). " -- http://stackoverflow.com/questions/5168718/what-blocks-ruby-python-to-get-javascript-v8-speed

Popular libraries

Frameworks:

Language upgrades:

Lists:

Things that compile to Javascript

eslint-config-cleanjs

" ... a subset of JavaScript? which would be as close to an idealised pure functional language as possible. The idea is to see if it's possible to banish all the Bad Parts (well, except for the single numeric type being IEEE 754 floating point) and leave a language without the design flaws which have plagued JS from the start, and which aren't easy to design out of the language without becoming a subset of itself.

...

Highlights:

    no this and no classes
    no null and undefined (implying that all functions must return)
    no mutation of any kind
    no variable reassignment
    no statements, only expressions (including no if)
    no CommonJS or AMD, only ES6 modules"

Typescript extension

Tutorials and manuals:

Papers:

Comparisons:

" novaleaf 2 hours ago

I love Typescript, I do all my javascript coding via it.

However, Though I wish it were, Typescript is NOT currently suitable for defining modules for external consumption. The problem comes down to no effective means of publishing the typings of your project and your project's dependencies. For example, if your project uses Promises, you might choose to include a definition of those promises, or (worse) reference a Promise typing you found on DefinitelyTyped?. This will work fine for you, the publisher. But any consumer of your project will be rudely greeted with typing collisions: Things like "The interface 'Promise' already exists in es6.d.ts"

There needs to be a solution to this module publishing problem before people can seriously publish modules (using NPM) using Typescript. Unfortunately, I have been tracking this issue and there is no timeline for resolving it, mostly due to too many different module systems, and handling module publishing being outside the design-scope of Typescript.

reply

lloyd-christmas 1 hour ago

typings[1] does exactly that as long as people start publishing their definitions (which is kind of the point of them). Relying on un-versioned ambient declarations is what breaks things, not having dependencies.

[1] https://github.com/typings/typings/blob/master/docs/registry.md

reply "

" nothrabannosir 3 hours ago

....Compiling TS just removes type annotations...TS does not add any semantic features, it only adds type annotations. Which it checks at compile time, and then removes. That's it. Want to switch away from TS? Compile all your .ts files, save the .js, check that into your repo and continue from there. (As other commenters sort-of pointed out: you will need to keep Babel in your pipeline.)

Eridrus 3 hours ago

Sort of. I don't recall the details from the top of my head and can't easily seem to find details, but I think we're seeing some divergence between Typescript's classes and es6 classes, though I think it's mostly syntactic.

Your code will keep working, but it may diverge a bit from standard JS; however everything will keep working, and I'm sure the expectation would be to move over the es6's syntax unless there were semantic reasons not to.

The Typescript authors are involved in the ECMAScript process, so I'm pretty sure that there won't be any surprising huge rifts at least.

reply

chadaustin 3 hours ago

I don't know why you're being downvoted. You're exactly right - there are a few tiny divergences between ES6 and TypeScript?. In particular, try compiling some classes with Babel's strict compatibility mode and compare the output to TypeScript?'s output. There are several small semantic differences.

Also, there a few constructs in TypeScript? that generate JavaScript? code, like enum and module.

THAT SAID, TypeScript? is basically ES6 + type annotations, and can certainly be used as such.

reply

 rtpg 5 hours ago

I can absolutely understand that coming from coffeescript (optional parentheses resolution... yikes).

But TypeScript? is basically "Javascript + types + ES6". They call it an "erasing compiler" because it's not meant to do much but remove types/make ES6 code work with ES5.

There is one gotcha in name resolution when you're working in modules (if you are in a module a.b, and a.c exists, then c will automatically refer to a.c, even if a global c exists). But that usually gets caught by the type system. Lot less issues than coffeescript IMO

reply

wereHamster 5 hours ago

With `--target=es6` I'm not sure if the TypeScript? compiler does any code transformation other than removing type annotations. So the chance of a 'transpiler error' is basically zero.

reply

bd82 4 hours ago

There are a few small things that still require conversion. But that is because Typescript also includes capabilities from ES7 (ES2016).

For example - currently in Typescript but only planned for ES7: https://github.com/jeffmo/es-class-fields-and-static-propert...

or Support ES7: exponentiation operator https://github.com/Microsoft/TypeScript/issues/4812

Typescript seems to be more like ECMAScript.next + types rather than ES6 + types.

reply

joshuacc 3 hours ago

FYI, those are not ES2016 features. ES2016 only includes two small feature enhancements. They might make it into 2017, but if TC39 decides they're not ready, they'll just keep not including the feature in the annual spec revision.

reply

ascetone 4 hours ago

My favourite thing they brought over from ES7 is async/await support via ES6 generators.

reply

"

Atscript extension

"To sum up, AtScript? is ECMAScript 6 with types, annotations and introspection." -- https://en.wikipedia.org/wiki/AtScript

"

...

Familiar Syntax: We desire to use a syntax which has been tried, is time tested and is most likely to become the next standard. This means using ':' to indicate type annotations (proposed in ES4 and used by TypeScript?), '@' for metadata annotations (used by java, dart and others) and 'name:Type;' for field annotations (used by java, dart, TypeScript? and others). ... Semantics Agnostic: Type system theory is a complex field with many tradeoffs. It is our explicit goal to leave the semantic discussion as well as the assertion system outside of the scope of AtScript?. Instead we want to provide hooks for others to build runtime type assertion libraries and static analyzer tools with their own semantics. In this way we believe that we can spur innovation in the area of type systems by lowering the barrier to entry.

...

Nominal types were originally proposed for JavaScript? in the ECMAScript 4 specification. Though this was never implemented in JavaScript?, it was adopted and widely used via Adobe's ActionScript?3 and inspired others. e.g. TypeScript? adopted the syntax, but uses a structural type system semantic.

...

One way to take advantage of the types is to have the transpiler, e.g. traceur, generate type assertion statements as shown below. Notice that the transpiler is unaware of the semantics of the types, and it leaves all of that information to a third party rtts library. Leaving the assertions to a pluggable library will allow others to experiment with different type system semantics.

AtScript?: class MyClass? { methodA(name:string):int { var length:int = name.length; return length; } }

ES6: import * as rtts from 'rtts';

class MyClass? { methodA(name) { rtts.types(name, rtts.string); var length = rtts.type(name.length, rtts.int); return rtts.returnType(length, rtts.int); } }

Why use a runtime type system?

It allows free mixing of existing libraries which do not have type annotations with new code which can take advantage of types. The incomplete type information would prevent useful static analysis of code but runtime type checks do not suffer from such limitations. The semantics of types can be left to the implementor of the rtts library. This means that different libraries can choose different strategies of identifying types. e.g. nominal vs structural. Our hope is that developers will be able to experiment with new ways of using types. Runtime type verification can be used to verify that the JSON returned from the server is of a valid structure, something which cannot be done statically. Since the type errors should be caught and resolved before pushing the code to production, all of the assertions can be stripped from production builds, completely removing the cost of these assertions. Prior Art This runtime type system is modeled after Dart’s runtime type assertion. Dart users working on large scale applications point out that optional types and runtime type assertions work well in practice.

Generics ... methodA(names:List<string>):List<int> { ... methodA(names) { rtts.types(names, Array.of(rtts.string)); ...

Field Annotations

As mentioned earlier, explicit field declarations are needed to fully describe the type’s structure. This syntax has been proposed in TypeScript?, and should be familiar to most developers.

AtScript?: class Point { x:int; y:int; }

ES6: class MyClass? { constructor() { this.x = null; auto-generated this.y = null; auto-generated } }

By specifying the fields in this way, the transpiler can generate the constructor which then pre-creates the fields. By creating the fields in the same order it will allow most virtual machines to optimize their hidden class system, thereby enhancing performance. Forgetting to declare a field will still produce working code, but the static analyzer could generate a warning to notify the developer of the potential mistake.

" -- https://docs.google.com/document/d/11YUzC-1d0V1-Q3V0fQ7KSit97HnZoKVygDxpWzEYW0U/edit#

todo continue reading and taking notes starting with section 'Metadata Annotations' in the previous document

Links:

Flow typechecker (made by Facebook)

http://flowtype.org/

Comparisons:

" TypeScript?

Flow

" Pros for TS:

Pros for Flow:

rtype type annotations

https://github.com/ericelliott/rtype

PureScript (typed) extension

http://www.purescript.org/

Coffeescript extension

Preemption by ES6?

Many are of the opinion that ES6, which came after Coffeescript, learned from it and incorporated many of its best parts into Javascript. [39] [40]

ES6

An update to Javascript including:

Links:

ES7

An update to Javascript including:

Links:

Internals

Source maps

Not actually part of Javascript, but often used for other languages that compile to Javascript.

A source map file is a JSON containing (much of this is optional):

The mapping data consists of one 'group' for each line in the object file. Each group consists of 'segments'. Each segment has:

All items in the segment are optional except for the first one (the starting column in the object file); however, if the second item (the source code file or text) is present, then the third and fourth are too (the source code line and column).

All indices (columns, lines, etc) are zero-based.

Many of the indices are encoded relative to the previous occurence of the given field. For example, line numbers are encoded as deltas from the last mentioned line number.

An encoding called "base 64 VLQ" is used. The spec constrains all numbers to fit within 32 bits.

Source maps can be gzipped.

Variants/subsets/alternate implementations

gpu.js

Compiles a subset of JavaScript? to GPU code.

" gpu.js relies on the assumption that the kernel function is using only a subset of legal JavaScript? syntax:

    1D, 2D, 3D array of numbers or just numbers as kernel input
    1D, 2D, 3D array of numbers as kernel output
    Number variables
    Arithematic operations (+, -, *, /, %)
    Javascript Math operations (Math.floor() and etc.)
    for loops (of fixed sizes only!)
    if and else statements
    No variables captured by a closure" -- http://gpu.rocks/

Links:

Implementation-specific internals

Links: