We rarely dive into current programming languages, touting the next new framework or the new features that will be out next year. This is about JavaScript the language as it exists today, what I picked up in going from C# to JS, and what C# picked up from JS along the way as well. It is based on Douglas Crockford's seminal book "JavaScript: The Good Parts".
JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying And Love JS
1. JavaScript: The Good Parts
Or: How a C# developer learned to stop worrying and love JS
Doug Jones
duggj@yahoo.com
2. So…what’s this about?
What C# learned from JS
JS versions
The language of JavaScript…the Good and the Bad
ES5
Tools
History
3. What this is NOT about
Transpilers
TypeScript
CoffeeScript
Dart
Traceur
etc…
Another JS framework or library
Angular
Ember
Lo-Dash
Underscore
etc…
ES6 or ES7 features
4. Creator of JSON (JavaScript Object Notation)
Wrote JSON2 parser and JSLint
Self proclaimed “world's foremost living authority on JavaScript”
6. What C# learned from JS
“JavaScript is the only language that I’m aware of that
people feel they don’t need to learn before they start
using it.” – Douglas Crockford
7. What C# learned from JS cont’d
.NET 2.0
Anonymous methods (with closures) //inline assign delegate to click event
Null Coalescing operator (??)
int? i = x ?? y;
button1.Click += delegate(System.Object o, System.EventArgs ea)
{ System.Windows.Forms.MessageBox.Show("Click!"); };
8. .NET 3.5
LINQ functionality has significant ties to js language
Action<T> and Func<T> types
Lambda expressions, like in LINQ .Where (anonymous functions like js, with closures)
Extension Methods (tacking function onto .prototype in prototypal inheritance)
Implicitly typed local variables (var in C#)
Object and Collection initializers
Anonymous types (hybrid between static typing and true dynamics)
var anonTypeObj = new { x = 7, y = “testing”};
What C# learned from JS cont’d
9. .NET 4.0
Dynamic //every variable in js is dynamic, like the C# type
Including associative array
dynamicObj[“myProp”] = 7;
Including ExpandoObject
Dynamic dynamicObj = new ExpandoObject();
dynamicObj.newProp = false;
What C# learned from JS cont’d
10. What C# learned from JS cont’d
.NET 4.5
async/await is promise/future construct similar to js frameworks
TaskCompletionSource / Task in C#
Used in Angular via $q and jQuery via $.promise
$q.defer() / $q.defer().promise
All ajax calls return promises (via $http or $.ajax(…).done(function() {…
11. JS Versions
(or ECMAScript)
Book written using ES3, but current
browsers support ECMAScript 5 (as of IE 9*)
*except strict mode
http://kangax.github.io/compat-table/es5/
12. JS Versions cont’d
ECMAScript 6 currently in draft
Iterators and generators (yield keyword)
Modules
Replacement for RequireJS and CommonJS
ECMAScript 7
async/await in spec
Chrome 39 and Firefox 34 appear to support about half ES6
http://kangax.github.io/compat-table/es6/
13. JavaScript the language
There’s a lot to JavaScript…just not to The Good Parts
The Good Parts are about JavaScript the language, no references to the DOM
14. Data types
Six data types that are primitives:
Boolean var isTrue = false;
Null
Undefined
Number var myNum = 7.29302; //64 bit floating point number, like “double” in C#
0.1 + 0.2 !== 0.3 //0.30000000000000004
String var text = “hello”; // or ‘hello’
and Object
Arrays
Functions
Regular Expressions
Dates
Everything else…
15. Functions
Functions are objects!
They can be properties too (then called methods)
JS
var obj = {};
obj.helloFn = function(){
alert("hello");
};
obj.helloFn.testProp = 7; //functions can have properties
16. Functions cont’d
Functions have 2 name placements
Variable name (function expression)
Function name (function statement or function declaration)
var helloFn = function(){
alert(“hello”);
}
function helloFn(){
alert(“hello”);
}
//or both, useful for recursion
var quickSort = function quickSortInternal(items,left,right){
…
if (index < right) {
quickSortInternal(items, index, right);
}
}
17. Truthy and Falsy
Truthy and Falsy
Here are the falsy values:
false
null
undefined
empty string -> ‘’ or “”
number 0
NaN (Not a Number)
Everything else…Truthy
Only mildly contrived example
If(myVar && myVar.book && myVar.book.chapter && myVar.book.chapter.page && …)
18. Triple equals – better than double equals
Using the == operator (Equality)
true == 1; //true, because 'true' is converted to 1 and then compared
"2" == 2; //true, because "2" is converted to 2 and then compared
Using the === operator (Identity)
true === 1; //false
"2" === 2; //false
This is because the equality operator == does type coercion, meaning that the
interpreter implicitly tries to convert the values before comparing.
On the other hand, the identity operator === does not do type coercion, and thus does
not convert the values when comparing.
http://stackoverflow.com/a/359547/186483
Very odd coercion
' trn ' == 0 // true
19. Truthy and Falsy cont’d
Given that you want to check whether the variable myVar has been assigned a
valid value
http://stackoverflow.com/questions/3390396/how-to-check-for-undefined-in-javascript
if(myVar == undefined) no, null value would be coerced to true statement
If(myVar === undefined) yes, but…undefined could be overwritten before ES5
if(typeof myVar === "undefined") correct, but…
if(myVar) can be used in most cases, much easier to work with
20. Null Coalescing Operator
C#
int? val = firstVal ?? 0;
SQL
SELECT Name, COALESCE(Business_Phone, Cell_Phone,
Home_Phone) Contact_Phone
FROM Contact_Info
JS
Falsy OR coalescing, returns first truthy value
var employeeName = employee.Name || "Unknown";
AND coalescing – if ALL truthy, returns LAST value
return (stockQuoteArray && stockQuoteArray[ticker] &&
stockQuoteArray[ticker][date]);
21. Scope
function level scope, not block level scope
NOT like C# block level scope:
C#
if (true)
{
var j = 3;
}
MessageBox.Show(j.ToString());
//compile time error
JS
function fn() {
"use strict";
if (true) {
var j = 3;
}
alert(j);
}
fn();
//successfully shows alert
22. Closures
Closures are functions that refer to independent (free) variables.
In other words, the function defined in the closure 'remembers' the environment
in which it was created.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures
var x = 100;
var fn = function () {
alert(x);
};
fn(); //alerts 100
var x = 100;
var fn = function () {
window.setTimeout(function () {
alert("inner: " + x);
}, 1000);
};
fn();
alert("outer: " + x);
x += 1;
//alerts “outer: 100”
//alerts “inner: 101”
23. Closures in C#
public class LinqExample
{
private int[] _ints = new int[] {1, 7, 2, 9, 3, 4, 2};
public IEnumerable<int> FilterInts(int filterNum)
{
var result = _ints.Where(x => x == filterNum);
return result;
}
}
//get list of all ints of certain value…for some reason
24. public IEnumerable<int> FilterInts(int filterNum)
{
LinqExample.u003Cu003Ec__DisplayClass1 cDisplayClass1
= new LinqExample.u003Cu003Ec__DisplayClass1();
cDisplayClass1.filterNum = filterNum;
// ISSUE: method pointer
return Enumerable.Where<int>((IEnumerable<int>)
this._ints, new Func<int, bool>((object) cDisplayClass1,
__methodptr(u003CFilterIntsu003Eb__0)));
}
Closures in C#
what they’re actually doing
[CompilerGenerated]
private sealed class u003Cu003Ec__DisplayClass1
{
public int filterNum;
public bool u003CFilterIntsu003Eb__0(int x)
{
return x == this.filterNum;
}
}
25. The IIFE!
Immediately Invoked Function Expression
var x = 100;
(function () {
alert(x);
x++;
}()); // *
alert(x);
*you have to wrap the function in parens in order to make it parse as an expression
26. Module Pattern (Crockford)
var stockService = (function () {
var stockQuoteArray = {
"AMZN": {
"10/31/2014": 305.46
// …
}
};
return {
getQuote: function (ticker, date) {
if (stockQuoteArray[ticker] && stockQuoteArray[ticker][date]) {
return stockQuoteArray[ticker][date];
}
return null;
}
};
})();
var quote = stockService.getQuote("AMZN", "10/31/2014");
alert(quote);
27. Revealing Module Pattern (John Papa)
var stockService = (function () {
var stockQuoteArray = {
"AMZN": {
"10/31/2014": 305.46
// …
}
};
return {
getQuote: getQuote //per Crockford, using a function before it’s defined is SLOPPY
};
function getQuote(ticker, date) {
if (stockQuoteArray[ticker] && stockQuoteArray[ticker][date]) {
return stockQuoteArray[ticker][date];
}
return null;
}
})();
28. Context
“this” is the context, just like C#
BUT… “this” can change
In the global execution context (outside of any function), this refers to the global
object, whether in strict mode or not.
When a function is called as a method of an object, its this is set to the object the
method is called on.
When a function is used as a constructor (with the new keyword), its this is bound
to new object being constructed.
When a function is used as an event handler, its this is set to the element the
event fired from
Change “this” context yourself in call or apply method
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
29. Context cont’d
var dgName = "Bob";
function callName() {
alert(this.dgName);
}
callName();
callName.apply({ dgName:
"Tim" }, []);
//calls “Bob” then “Tim”
var dgName = "Bob";
function callName() {
(function () {
alert(this.dgName);
}());
}
callName();
callName.apply({ dgName: "Tim" }, []);
//calls “Bob” twice
//due to subfunction using global context
30. Context cont’d
var dgName = "Bob";
function callName() {
var self = this;
(function () {
alert(self.dgName);
}());
}
callName();
callName.apply({ dgName: "Tim" }, []);
//alerts “Bob” then “Tim”
Douglas Crockford uses “that” instead of self.
John Papa uses “self”, which I prefer
31. The new keyword
Module patterns shown for what amounts to essentially singletons
What if I need multiple instances with different state in each?
var Animal = function (helloText) {
if (!(this instanceof Animal)) {
return new Animal(helloText);
}
var self = this;
self.helloText = helloText;
self.speak = function () {
alert(helloText);
};
//returns “this” automatically when called with “new”
};
var human = new Animal("Hello");
var tiger = Animal("Growl"); //whoops, forgot new…no problem
//should allay Crockford’s fears
human.speak();
tiger.speak();
http://stackoverflow.com/a/383503/186483
32. Instances without “new” keyword
You can use the module patterns
WITHOUT the IIFE to allow for
multiple instances
Only do this if you need multiple
instances
The state saved in the objects must
be different for different instances
var animal = function () {
var helloText = "";
var setText = function (text)
{
helloText = text;
};
var speak = function () {
alert(helloText);
};
return {
speak: speak,
setText: setText
};
};
var human = animal();
var tiger = animal();
human.setText("Hello");
tiger.setText("Growl");
human.speak();
tiger.speak();
33. Hoisting
Variable declarations hoisted to top of function (top of scope)
Function statements also hoisted
(function () {
myOtherFunc();
var myFunc = function () {
alert("my func");
}
var x = 7;
function myOtherFunc() {
alert("my other func");
}
}());
(function () {
var x;
var myFunc;
function myOtherFunc() {
alert("my other func");
}
myOtherFunc();
myFunc = function () {
alert("my func");
};
x = 7;
}());
34. Prototypal Inheritance
(or Prototypical)
All javascript objects have a “template” base object, or prototype.
Javascript functions have the “prototype” object, whereas all objects have
the “__proto__” object.
Don’t Do This!
Function.prototype.bar = function() {
alert("bar");
};
Object.prototype.methodName = function(){
return dowhateverto(this)
};
35. Prototypal Inheritance (cont’d)
The old way
var Animal = function (speakText) {
this.helloText = speakText;
this.speak = function () {
alert(this.helloText);
};
};
var Human = function () {
this.helloText = "Hello";
};
var mammal = new Animal("Growl");
Human.prototype = mammal;
var bob = new Human();
bob.speak(); //Hello
mammal.speak(); //Growl
36. Prototypal Inheritance (cont’d)
var individualStockService = function (tickerSymbol) {
var s = Object.create(stockService);
s.ticker = tickerSymbol || "SPY"; //default to common ticker
s.getThisQuote = function (date) {
return this.getQuote(this.ticker, date);
};
return s;
};
var amznStockService = individualStockService("AMZN");
var amznQuote = amznStockService.getThisQuote("10/31/2014");
var uaStockService = individualStockService("UA");
var uaQuote = uaStockService.getThisQuote("12/05/2014");
var quote = individualStockService().getThisQuote("12/05/2014");
alert(amznQuote); //305.46
alert(uaQuote); //69.43
alert(quote); //208
37. Use strict mode
var stockService = (function () {
‘use strict’;
var stockQuoteArray = {
…
Converts mistakes into errors (as syntax errors or at runtime),
mistypedVaraible = 17;
var a = Animal(); // “this” undefined within function constructor without “new”
undefined = 7; //assigning to read-only variable
Octal syntax forbidden // 015 === 13, but now errors
eval
creates variables only for the code being evaluated
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
38. JavaScript: The Bad Parts
“If you want to learn more about the bad parts and how to use them badly,
consult any other JavaScript book.” - Douglas Crockford
39. The Awful Parts
Global Variables //implicit global variables wherever “var” forgotten
And in functions within methods as shown on last Context slide
Scope – function level, not block level
Semicolon insertion //can insert in bad places, like after “return”
Unicode //only 16 bits, ('u0041‘, but not 'u1F4A9‘, need to use 'uD83DuDCA9‘
instead)
Have to run surrogate pair algorithm to get the hex pairs above
https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
ES6 problem is fixed, example: 'u{1F4A9}'
40. Awful Parts cont’d
typeof //typeof null === ‘object’
parseInt //always use radix 10, “16 tons” produces 16 “08” produces 0
+ //adds or concatenates, like C#
NaN // NaN !== NaN, typeof NaN === ‘number’
Floating Point - (0.1 + 0.2) !== 0.3
Phony Arrays //arguments array not an array, but object with length property
Falsy Values //falsy not interchangeable, language idiosyncrasy
hasOwnProperty //can be replaced
41. The Bad Parts
== //double equal, coercive equality test
with statement
eval //compromises security and performance
continue //not really sure why he dislikes, short circuit lowers code
complexity
switch fall through // “attractive nuisance” that leads to bugs
Block-less statements //same as in C#, 1 liner without curly braces
If(id === 13) soundAlarm();
42. Bad Parts cont’d
++ and -- // “too tricky, too cryptic”
Bitwise operators //bad performance, most likely mistyped, not wanted
9 << 2 yields 36
Function statement vs function expression
Typed wrappers //new Boolean(false), has .valueOf
like nullable types in C#, but confusing and no reason for it in JS
New //if you forget new keyword, “this” inside function is global context
Could tack properties and methods onto global scope
void // void func(){…} always returns undefined
43. EcmaScript 5 changes
Strict Mode //see slide
Objects
Object.create() //see prototypal inheritance slide
Object.getPrototypeOf()
Object.freeze()
All properties read only and no properties can be added
Object.seal()
No properties can be added and writable state remains on properties
Arrays
Some Underscore/LoDash functions added in
.every, .filter, .forEach, .indexOf, .map, .reduce, .some
46. JSLint
http://www.jslint.com/
Javascript compiler that builds js and checks code quality, just as C# compiler
does.
It is incredibly opinionated and somewhat brutal with excessive errors
For example:
Expected exactly one space between 'function' and '('.
Expected '}' at column 17, not column 9.
Expected '10/31/2014' at column 21, not column 13.
Function used before it was defined
prevents John Papa’s version of Revealing Module Pattern
47. JSHint
A better option
http://www.jshint.com/
http://www.jshint.com/docs/
Forked from JSLint, but by default it is less strict
Comes with Web Essentials (chances are, you already have it)
http://vswebessentials.com/
You can edit JSHint config file to set up for only errors you’re
concerned with (roughly 50 or so options), such as:
Require triple equals (===) for comparison
Requires all functions run in ES5 Strict Mode
Require all non-global variables to be declared (prevents global leaks)
Prohibit use of `++` & `--` //set to false by default, which I’m happy with
Some errors cannot be configured, such as the semi-colon required at
the end of every line.
Bottom line, it forces me to write better code. I recommend it to
everyone.
48. (function () {
'use strict';
var serviceId = 'carService';
// TODO: replace app with your module name
angular.module('app').factory(serviceId, ['$http',
carService]);
function carService($http) {
// Define the functions and properties to reveal.
var service = {
getData: getData
};
return service;
function getData() {
}
//#region Internal Methods
//#endregion
}
})();
49. History of JavaScript
Mocha created in May 1995 by Brendan Eich at Netscape
Officially called LiveScript in beta Netscape Navigator 2.0 releases
Renamed JavaScript in 2.0B3
Pressure from ally Sun (ally against Microsoft) to remove LiveScript since they had
a language that would work in every browser, Java
With the name change to JavaScript, Sun was appeased.
Microsoft implements JavaScript in IE 3.0
Completely reverse engineered JS without consent of Netscape
This included all bugs, great copy job!
Later MSFT renames to JScript to avoid trademark issues
50. History of JavaScript cont’d
Netscape submits JavaScript to ECMA International to become a standard
ECMAScript
EcmaScript v1 spec is published in June 1997
EcmaScript v2 spec is published in June 1998
EcmaScript v3 spec published December 1999
EcmaScript v4 NEVER published
EcmaScript v5 published December 2009
10 years later!
5.1 released June 2011
EcmaScript v6 coming soon, NOT officially published
51. Conclusion
JavaScript is a real programming language!
Avoid the Bad parts, embrace the Good
If you haven’t read the book, please do!