by sandersn
27. August 2008 09:02
I wrote this when re-learning Javascript. It is quite dense but I have added illustrations. I learned part of it from
Doug Crockford's useful but rather prescriptive site (specifically, he prescribes semicolons, which I hate). The description is probably only as useful as your grasp of lexical scope, because that's what is at the core of Javascript.
Credo:
- There is no built-in object-oriented scope. Only lexical scope and hash lookup, called object scope below.
- Lexical scope never uses the dot operator.
- Object scope always uses the dot operator.
- Using these two scopes, you can create private and public fields, and private, public and privileged methods.
- Private fields are created using lexical scope. As such, they are only accessible inside the prototype function, to private and privileged functions. They are not inherited. They do not use 'this.' prefixes.
- Public fields are created using object scope. As such, they are accessible to any code. They are inherited. They always use 'this.' prefixes.
- Private methods are created using lexical scope: the var keyword. As such, they are only accessible inside the prototype function, are not inherited, and do not require 'this.' prefixes. They can access private variables.
- Privileged methods are created using object scope: assignment to 'this'. As such, they are accessible anywhere and require 'this.' prefixes. However, because they are attached to individual objects during construction, they are not inherited either. They can access private variables because of lexical scope, and because they are unique to each object.
- Public methods are created using object scope: assign to the prototype. As such, they are accessible anywhere and require 'this.' prefixes. They can access only public variables because, even if they are created inside the lexical scope of a particular object, those private variables are the variables of only one object, the latest one constructed. (this must lead to a way to make public static variables, if you want them)
- Public methods require the most boilerplate, because they can only access public variables, which must be explicitly created from constructor arguments, and because they must be assigned to the prototype, not 'this', and because all accesses of methods and variables must be prefixed with 'this'. They are also the least secure; anyone can add a public method anywhere. However, they are also the most efficient, since they are not copied to each instance.
- Use of only public methods and public variables gives you the same object system as Python. This is probably why it's the recommended style. Simple, explicit, and dynamic.
Illustrations:
- Lexical scope:
var x = 1
function f() {
var x = 2
function g() {
print(x)
}
g()
}
f()
// prints 2
- Object scope:
var o = {x : 1, y : 2}
function f() {
print o.x
}
f()
// prints 1
- How nice!
- Private fields:
function Example(x) {
var y = 2
}
var e = new Example(1)
// e.x and e.y are both undefined from the outside
//private static:
var Example = (function() {
var privateStatic = 1
return function(x) {
var y = 1
this.f = function() { print(privateStatic++) }
}
})();
var e = new Example(1)
var f = new Example(1001)
e.f(); f.f(); e.f() // prints 1 2 3
- Public fields:
function Example(x) {
this.y = 2
}
var e = new Example(1)
e.y // is now available from the outside
- Private methods:
function Example(x) {
var y = 2
var f = function() { print(y++) }
}
var e = new Example(1)
e.f() // throws TypeError: e.f is not a function
- Privileged methods:
function Example(x) {
var y = 2
this.f = function() { print(y++) }
}
var e = new Example(1)
e.f(); e.f() // prints 2 3
- Public methods:
function Example(x) {
this.y = 2 // y must also be public
this.x = x // copy constructor argument to public field
}
Example.prototype.f = function() { print(this.x + this.y++) }
var e = new Example(1)
e.f(); e.f() // prints 3 4
Note: I wanted to link to a concise tutorial on lexical scope, but I don't know one. If you have time,
SICP will certainly teach you lexical scope, along with a million other wild and wonderful things. If you don't like Scheme syntax (an acquired taste), follow along with
translations to other languages.
f4f61628-a0ba-4d07-b237-a760b7440b53|0|.0
Tags:
General