extend
1function extend(Child, Parent) {
2    var F = function() { }
3    F.prototype = Parent.prototype
4    Child.prototype = new F()
5    Child.prototype.constructor = Child
6    Child.superclass = Parent.prototype
7}

Использовать ее для наследования можно так:

01// создали базовый класс
02function Animal(..) { ... }
03 
04// создали класс
05// и сделали его потомком базового
06function Rabbit(..)  { ... }
07extend(Rabbit, Animal)
08 
09// добавили в класс Rabbit методы и свойства
10Rabbit.prototype.run = function(..) { ... }
11 
12// все, теперь можно создавать объекты
13// класса-потомка и использовать методы класса-родителя
14rabbit = new Rabbit(..)
15rabbit.animalMethod()



Вызов конструктора родителя с теми же аргументами, что были переданы осуществляется так:

1function Rabbit(..)  {
2    ...
3    Rabbit.superclass.constructor.apply(this, arguments)
4 
5    ...
6}

Для окончательной организации удобного javascript-наследования на классе, пригодится функция копирования свойств из объекта src в другой dst:

01// копирует все свойства из src в dst,
02// включая те, что в цепочке прототипов src до Object
03function mixin(dst, src){
04    // tobj - вспомогательный объект для фильтрации свойств,
05    // которые есть у объекта Object и его прототипа
06    var tobj = {}
07    for(var x in src){
08        // копируем в dst свойства src, кроме тех, которые унаследованы от Object
09        if((typeof tobj[x] == "undefined") || (tobj[x] != src[x])){
10            dst[x] = src[x];
11        }
12    }
13    // В IE пользовательский метод toString отсутствует в for..in
14    if(document.all && !document.isOpera){
15        var p = src.toString;
16        if(typeof p == "function" && p != dst.toString && p != tobj.toString &&
17         p != "\nfunction toString() {\n    [native code]\n}\n"){
18            dst.toString = src.toString;
19        }
20    }
21}

В полном примере мы создадим класс Animal c методом walk и его насленика Bird, который умеет летать: fly. Функции walk и fly принимают время ходьбы/полета и соответственно увеличивают свойство distance - расстояние до животного:

01// ---- родительский класс ----
02 
03function Animal(name, walkSpeed) {
04    this.name = name
05    this.walkSpeed = walkSpeed
06}
07 
08// добавляем методы объекта
09mixin(Animal.prototype, {
10 
11    // пример переменной
12    distance: 0,
13 
14    // пример метода
15    walk: function(time) {
16        this.distance = this.distance + time*this.walkSpeed
17    },
18 
19    toString: function() {
20        return this.name+" на расстоянии "+this.distance
21    }
22})
23 
24// ---- класс наследник ----
25 
26function Bird(name, walkSpeed, flySpeed) {
27    // вызов родительского конструктора
28    Bird.superclass.constructor.call(this, name, walkSpeed)
29 
30    this.flySpeed = flySpeed
31}
32extend(Bird, Animal)
33 
34mixin(Bird.prototype, {
35    fly: function(time) {
36        this.distance = this.distance + time*this.flySpeed
37    }
38})

Пример создания объекта-наследника:

1bird = new Bird("Птыц", 1, 10)
2 
3bird.walk(3)
4 
5alert(bird) // => Птыц на расстоянии 3
6 
7bird.fly(2)
8 
9alert(bird) // => Птыц на расстоянии 23

Конечно же, вызовы extend и mixin можно объединить в одну функцию. В примере это не сделано для наглядности происходящего.

При наследовании можно организовать "настоящие" приватные члены класса. Для этого, однако, придется объявлять все методы не отдельно от конструктора, а внутри него:

01function extend(Child, Parent) {
02    var F = function() { }
03    F.prototype = Parent.prototype
04    Child.prototype = new F()
05    Child.prototype.constructor = Child
06    Child.superclass = Parent.prototype
07}
08 
09// ---- родительский класс ----
10 
11function Animal(name, walkSpeed) {
12 
13    // объявить приватную переменную
14    var speed = walkSpeed
15 
16    // объявить открытую переменную
17    this.distance = 0
18 
19    // добавить метод, использующий private speed
20    this.walk = function(time) {
21        this.distance = this.distance + time*speed
22    }
23 
24    // добавить метод, использующий private name
25    this.toString = function() {
26        return name+" на расстоянии "+this.distance
27    }
28}
29 
30 
31// ---- класс наследник ----
32 
33function Bird(name, walkSpeed, flySpeed) {
34    // вызов родительского конструктора
35    Bird.superclass.constructor.call(this, name, walkSpeed)
36 
37    this.fly = function(time) {
38        this.distance = this.distance + time*flySpeed
39    }
40}
41extend(Bird, Animal)
42 
43 
44bird = new Bird("Птыц", 1, 10)
45 
46bird.walk(3)
47 
48alert(bird) // => Птыц на расстоянии 3
49 
50bird.fly(2)
51 
52alert(bird) // => Птыц на расстоянии 23

Приватными являются все свойства, которые доступны только из внутренних методов объекта через механизм замыкания (см. статью о функциях javascript).

Это свойства, явно объявленные через var, плюс аргументы конструктора.

При таком способе объявления - все свойства и методы записываются не в прототип объекта, а в сам объект.

Поэтому, если объектов создается очень много, то это сопряжено с дополнительными расходами памяти на хранение множества копий методов - свой код функции для каждого объекта, а не один в прототипе на всех. Обычно же эти расходы можно во внимание не принимать.

Если Вы использовали ООП в других языках программирования, то наверняка знаете, что чаще делаются не private свойства, а protected, т.е такие, к которым могут получить доступ наследники. Javascript не предоставляет синтаксиса для создания protected свойств, поэтому их просто помечают подчеркиванием в начале.

Например,

01function Animal(name) {
02 
03    var privateVariable = 0
04 
05    this._protectedName = name
06 
07    this._protectedMethod = function(..) {
08        ... alert(privateVariable)..
09    }
10 
11    this.publicMethod = function() { ... }
12}

Все функции, объявленные внутри конструктора, имеют доступ к приватным свойствам и, конечно же, к защищенным и публичным.

Ограничение доступа к таким "защищенным" свойствам не жесткое и остается на совести программиста.