Skip to content

Commit

Permalink
syntax highlighting
Browse files Browse the repository at this point in the history
  • Loading branch information
raganwald committed Feb 4, 2013
1 parent 808e73e commit 7a6f5e5
Showing 1 changed file with 76 additions and 66 deletions.
142 changes: 76 additions & 66 deletions 2013/02/prototypes.md
Expand Up @@ -12,16 +12,18 @@ That sounds tautological, until we look at JavaScript.

JavaScript objects don't have a class. There's a constructor and there's a prototype. The constructor of an object is a function that was invoked with the `new` operator. In JavaScript, any function can be a constructor, even if it doesn't look like one:

function square (n) { return n * n; }
//=> undefined
square(2)
//=> 4
square(2).constructor
//=> [Function: Number]
new square(2)
//=> {}
new square(2).constructor
//=> [Function: square]
```javascript
function square (n) { return n * n; }
//=> undefined
square(2)
//=> 4
square(2).constructor
//=> [Function: Number]
new square(2)
//=> {}
new square(2).constructor
//=> [Function: square]
```

As you can see, the `square` function will act as a constructor if you call it with `new`. *There is no special kind of thing that constructs new objects, every function is (potentially) a constructor*.

Expand All @@ -31,73 +33,81 @@ That's different from a true classical language, where the class is a special ki

What about prototypes? Well, again JavaScript differs from a "classical" system like Ruby. In Ruby, classes are objects, but they're special objects. For example, here are some of the methods associated with the Ruby class `String`:

String.methods
#=> [:try_convert, :allocate, :new, :superclass, :freeze, :===, :==,
:<=>, :<, :<=, :>, :>=, :to_s, :included_modules, :include?, :name,
:ancestors, :instance_methods, :public_instance_methods,
:protected_instance_methods, :private_instance_methods, :constants,
:const_get, :const_set, :const_defined?, :const_missing,
:class_variables, :remove_class_variable, :class_variable_get,
:class_variable_set, :class_variable_defined?, :public_constant,
:private_constant, :module_exec, :class_exec, :module_eval, :class_eval,
:method_defined?, :public_method_defined?, :private_method_defined?,
:protected_method_defined?, :public_class_method, :private_class_method,
# ...
:!=, :instance_eval, :instance_exec, :__send__, :__id__]
```ruby
String.methods
#=> [:try_convert, :allocate, :new, :superclass, :freeze, :===, :==,
:<=>, :<, :<=, :>, :>=, :to_s, :included_modules, :include?, :name,
:ancestors, :instance_methods, :public_instance_methods,
:protected_instance_methods, :private_instance_methods, :constants,
:const_get, :const_set, :const_defined?, :const_missing,
:class_variables, :remove_class_variable, :class_variable_get,
:class_variable_set, :class_variable_defined?, :public_constant,
:private_constant, :module_exec, :class_exec, :module_eval, :class_eval,
:method_defined?, :public_method_defined?, :private_method_defined?,
:protected_method_defined?, :public_class_method, :private_class_method,
# ...
:!=, :instance_eval, :instance_exec, :__send__, :__id__]
```

And here are some of the methods associated with an instance of a string:

String.new.methods
#=> [:<=>, :==, :===, :eql?, :hash, :casecmp, :+, :*, :%, :[],
:[]=, :insert, :length, :size, :bytesize, :empty?, :=~,
:match, :succ, :succ!, :next, :next!, :upto, :index, :rindex,
:replace, :clear, :chr, :getbyte, :setbyte, :byteslice,
:to_i, :to_f, :to_s, :to_str, :inspect, :dump, :upcase,
:downcase, :capitalize, :swapcase, :upcase!, :downcase!,
:capitalize!, :swapcase!, :hex, :oct, :split, :lines, :bytes,
:chars, :codepoints, :reverse, :reverse!, :concat, :<<,
:prepend, :crypt, :intern, :to_sym, :ord, :include?,
:start_with?, :end_with?, :scan, :ljust, :rjust, :center,
# ...
:instance_eval, :instance_exec, :__send__, :__id__]
```ruby
String.new.methods
#=> [:<=>, :==, :===, :eql?, :hash, :casecmp, :+, :*, :%, :[],
:[]=, :insert, :length, :size, :bytesize, :empty?, :=~,
:match, :succ, :succ!, :next, :next!, :upto, :index, :rindex,
:replace, :clear, :chr, :getbyte, :setbyte, :byteslice,
:to_i, :to_f, :to_s, :to_str, :inspect, :dump, :upcase,
:downcase, :capitalize, :swapcase, :upcase!, :downcase!,
:capitalize!, :swapcase!, :hex, :oct, :split, :lines, :bytes,
:chars, :codepoints, :reverse, :reverse!, :concat, :<<,
:prepend, :crypt, :intern, :to_sym, :ord, :include?,
:start_with?, :end_with?, :scan, :ljust, :rjust, :center,
# ...
:instance_eval, :instance_exec, :__send__, :__id__]
```

As you can see, a "class" in Ruby is very different from an "instance of that class." And the methods of a class are very different from the methods of an instance of that class.

In JavaScript, prototypes are also objects, but unlike a classical system, there are no special methods or properties associated with a prototype. Any object can be a prototype, even an empty object. In fact, that's exactly what is associated with a constructor by default:

function Nullo () {};
Nullo.prototype
//=> {}
```javascript
function Nullo () {};
Nullo.prototype
//=> {}
```
There's absolutely nothing special about a prototype object. No special class methods, no special constructor of its own, nothing. Let's look at a simple Queue in JavaScript:

var Queue = function () {
this.array = [];
this.head = 0;
this.tail = -1;
};
Queue.prototype.pushTail = function (value) {
return this.array[this.tail += 1] = value;
};
Queue.prototype.pullHead = function () {
var value;
if (!this.isEmpty()) {
value = this.array[this.head];
this.array[this.head] = void 0;
this.head += 1;
return value;
}
};
Queue.prototype.isEmpty = function () {
return this.tail < this.head;
};

Queue.prototype
//=> { pushTail: [Function],
pullHead: [Function],
isEmpty: [Function] }
```javascript
var Queue = function () {
this.array = [];
this.head = 0;
this.tail = -1;
};

Queue.prototype.pushTail = function (value) {
return this.array[this.tail += 1] = value;
};
Queue.prototype.pullHead = function () {
var value;

if (!this.isEmpty()) {
value = this.array[this.head];
this.array[this.head] = void 0;
this.head += 1;
return value;
}
};
Queue.prototype.isEmpty = function () {
return this.tail < this.head;
};

Queue.prototype
//=> { pushTail: [Function],
pullHead: [Function],
isEmpty: [Function] }
```

The first way a prototype in JavaScript is different from a class in Ruby is that the prototype is an ordinary object with exactly the same properties that we expect to find in an instance: Methods `pushTail`, `pullHead`, and `isEmpty`.

Expand Down

0 comments on commit 7a6f5e5

Please sign in to comment.