Search

4/12/2010

JavaScript: The Good Parts

JavaScript: The Good Parts


Bad Parts
* Global Variable
* + adds and concatenates
* Semicolon insertion - when compiler gets an error, it backs up, looks around for a line feed, turns it into a semicolon, and then tries again.
* typeof
* with and eval
* phony arrays - In JavaScript, arrays are essentially hash tables, in which the keys are turned into strings and then hashed to locate the buckets. This has a terrible performance penalty. But it has an advantage in that it makes the programming model quite a bit easier. 'cause you don't ever have to dimension an array. Dimensions don't exist in this language.
* == and !=
* false, null, undefined, NaN

for in is troublesome
* Design question: Should for..in do a shallow skim or a deep dredge?
* Decision: deep dredge. The programmer must explicitly filter out the deep members.
* Except: They didn't tell anybody!
* Consequence: Lots of confusion about how to use for..in

Good Parts
* Lambda
* Dynamic Objects - you can take any object and at any time, you can add a new property to it or remove a property from it. You don't have to go to some class and make another derived class in order to have an object.
* Loose Typing
* Object Literals

Prototypal Inheritance
* Class-free
* Objects inherit from objects
* An object contains a link to another object: Delegation. Differential Inheritance.

var newObject = Object.create(oldObject);

newObject
__proto__ => oldObject

Each object contains only what makes it different from the object it inherits from, and that allows for objects to be much smaller. For a long time, the language was ambivalent about its prototypal nature, so never included an operator for actually making new objects which inherit from other objects. We're correcting that oversight in the next edition of the language with object.create, which will make a new object which inherits from an old one.


if (typeof object.create !== 'function') {
object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
}
}


Global

var names = ['zero', 'one', 'two', 'three'];
var digit_name = function (n) {
return names[n];
}
alert(digit_name(3));


Slow

var digit_name = function (n) {
var name = 'zero', 'one', 'two', 'three'];
return names[n];
};
alert(digit_name(3));

The problem with this is that every time this function gets called, we're going to reinitialize the names array. Now in theory, an optimizing compiler could detect this case and factor that out. But today, nobody does that.

Closure

var digit_name = function () {
var name = 'zero', 'one', 'two', 'three'];
return function (n) {
return names[n];
}
}();
alert(digit_name(3));


So here I've got a function which is going to return another function and the outer function gets executed immediately. The inner function has access to the properties of the outer function or to the variables of the outer function. It will continue to enjoy access to them even after the outer function has returned. So when it returns, the function goes into digit_name and that function will have names bound to the original array and will continue to have it for as long as it lives.


Power Constructor
1. Make an object - Object literal, Object.create, call another power constructor

function myPowerConstructor(x) {
var that = otherMaker(x);
}

2. Define some variables and functions - These become private members.

function myPowerConstructor(x) {
var that = otherMaker(x);
var secret = f(x);
}


3. Augment the object with privileged methods.

function myPowerConstructor(x) {
var that = otherMaker(x);
var secret = f(x);
that.priv = function () {
... secret x that ....
};
}


4. Return the object

function myPowerConstructor(x) {
var that = otherMaker(x);
var secret = f(x);
that.priv = function () {
... secret x that ....
};
return that;
}


Closure
* A function object contains
- A function (name, parameters, body)
- A reference to the environment in which it was created (context).

Style Isn't Subjective

return
{
ok: false
};

SILENT ERROR

It turns out that curly brace can mean "start an object literal", or it could mean a block. Now it turns out, in this language, we don't have block scope. So having an empty block is not useful.
Okay, so "ok" doesn't look like a statement. Well, actually it does. It looks like a statement label. Well, "false" doesn't look like any kind of statement. But remember, we have those useless expression statements that we inherited from C. So we'll evaluate "false" and go, "Yep, that's false", and ignore it.

return {
ok: true
}

Woks well in JavaScript

Why does JSON require quotes around the property names?
1. To align it with Python. In Python, the quotes are required.
2. it makes the grammar of the standards much easier to specify and I like simplicity.
3. JavaScript has a stupid reserved word policy. There are certain words that you cannot use in the key position of an object literal.

沒有留言: