diff options
Diffstat (limited to 'tools/addon-sdk-1.5/packages/api-utils/docs/base.md')
-rw-r--r-- | tools/addon-sdk-1.5/packages/api-utils/docs/base.md | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/tools/addon-sdk-1.5/packages/api-utils/docs/base.md b/tools/addon-sdk-1.5/packages/api-utils/docs/base.md new file mode 100644 index 0000000..7a694f2 --- /dev/null +++ b/tools/addon-sdk-1.5/packages/api-utils/docs/base.md @@ -0,0 +1,207 @@ +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +### Inheritance ### + +Doing [inheritance in JavaScript](https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript) +is both verbose and painful. Reading or writing such code requires requires +sharp eye and lot's of discipline, mainly due to code fragmentation and lots of +machinery exposed: + + // Defining a simple Class + function Dog(name) { + // Classes are for creating instances, calling them without `new` changes + // behavior, which in majority cases you need to handle, so you end up + // with additional boilerplate. + if (!(this instanceof Dog)) return new Dog(name); + + this.name = name; + }; + // To define methods you need to make a dance with a special 'prototype' + // property of the constructor function. This is too much machinery exposed. + Dog.prototype.type = 'dog'; + Dog.prototype.bark = function bark() { + return 'Ruff! Ruff!' + }; + + // Subclassing a `Dog` + function Pet(name, breed) { + // Once again we do our little dance + if (!(this instanceof Pet)) return new Pet(name, breed); + + Dog.call(this, name); + this.breed = breed; + } + // To subclass, you need to make another special dance with special + // 'prototype' properties. + Pet.prototype = Object.create(Dog.prototype); + // If you want correct instanceof behavior you need to make a dance with + // another special `constructor` property of the `prototype` object. + Object.defineProperty(Pet.prototype, 'contsructor', { value: Pet }); + // Finally you can define some properties. + Pet.prototype.call = function(name) { + return this.name === name ? this.bark() : ''; + }; + +An "exemplar" is a factory for instances. Usually exemplars are defined as +(constructor) functions as in examples above. But that does not necessary has +to be the case. Prototype (object) can form far more simpler exemplars. After +all what could be more object oriented than objects that inherit from objects. + + var Dog = { + new: function(name) { + var instance = Object.create(this); + this.initialize.apply(instance, arguments); + return instance; + }, + initialize: function initialize(name) { + this.name = name; + }, + type: 'dog', + bark: function bark() { + return 'Ruff! Ruff!' + } + }; + var fluffy = Dog.new('fluffy'); + + + var Pet = Object.create(Dog); + Pet.initialize = function initialize(name, breed) { + Dog.initialize.call(this, name); + this.breed = breed; + }; + Pet.call = function call(name) { + return this.name === name ? this.bark() : ''; + }; + +While this small trick solves some readability issues, there are still more. To +address them this module exports `Base` exemplar with few methods predefined: + + var Dog = Base.extend({ + initialize: function initialize(name) { + this.name = name; + }, + type: 'dog', + bark: function bark() { + return 'Ruff! Ruff!' + } + }); + + var Pet = Dog.extend({ + initialize: function initialize(name, breed) { + Dog.initialize.call(this, name); + this.breed = breed; + }, + function call(name) { + return this.name === name ? this.bark() : ''; + } + }); + + var fluffy = Dog.new('fluffy'); + dog.bark(); // 'Ruff! Ruff!' + Dog.isPrototypeOf(fluffy); // true + Pet.isPrototypeOf(fluffy); // true + +### Composition ### + +Even though (single) inheritance is very powerful it's not always enough. +Sometimes it's more useful suitable to define reusable pieces of functionality +and then compose bigger pieces out of them: + + var HEX = Base.extend({ + hex: function hex() { + return '#' + this.color + } + }) + + var RGB = Base.extend({ + red: function red() { + return parseInt(this.color.substr(0, 2), 16) + }, + green: function green() { + return parseInt(this.color.substr(2, 2), 16) + }, + blue: function blue() { + return parseInt(this.color.substr(4, 2), 16) + } + }) + + var CMYK = Base.extend(RGB, { + black: function black() { + var color = Math.max(Math.max(this.red(), this.green()), this.blue()) + return (1 - color / 255).toFixed(4) + }, + magenta: function magenta() { + var K = this.black(); + return (((1 - this.green() / 255).toFixed(4) - K) / (1 - K)).toFixed(4) + }, + yellow: function yellow() { + var K = this.black(); + return (((1 - this.blue() / 255).toFixed(4) - K) / (1 - K)).toFixed(4) + }, + cyan: function cyan() { + var K = this.black(); + return (((1 - this.red() / 255).toFixed(4) - K) / (1 - K)).toFixed(4) + } + }) + + // Composing `Color` prototype out of reusable components: + var Color = Base.extend(HEX, RGB, CMYK, { + initialize: function initialize(color) { + this.color = color + } + }) + + var pink = Color.new('FFC0CB') + // RGB + pink.red() // 255 + pink.green() // 192 + pink.blue() // 203 + + // CMYK + pink.magenta() // 0.2471 + pink.yellow() // 0.2039 + pink.cyan() // 0.0000 + +### Combining composition & inheritance ### + +Also it's easy to mix composition with inheritance: + + var Pixel = Color.extend({ + initialize: function initialize(x, y, color) { + Color.initialize.call(this, color) + this.x = x + this.y = y + }, + toString: function toString() { + return this.x + ':' + this.y + '@' + this.hex() + } + }); + + var pixel = Pixel.new(11, 23, 'CC3399'); + pixel.toString() // 11:23@#CC3399 + Pixel.isPrototypeOf(pixel) // true + + // Pixel instances inhertis from `Color` + Color.isPrototypeOf(pixel); // true + + // In fact `Pixel` itself inherits from `Color`, remember just simple and + // pure prototypal inheritance where object inherit from objects. + Color.isPrototypeOf(Pixel); // true + +### Classes ### + +Module exports `Class` function. `Class` takes argument of exemplar object +extending `Base` and returns `constructor` function that can be used for +simulating classes defined by given exemplar. + + var CPixel = Class(Pixel); + var pixel = CPixel(11, 12, '000000'); + pixel instanceof CPixel // true + Pixel.prototypeOf(pixel); // true + + // Use of `new` is optional, but possible. + var p2 = CPixel(17, 2, 'cccccc'); + p2 instanceof CPixel // true + p2.prototypeOf(pixel); // true |