Ответ 1
Все объекты в JavaScript
В отличие от других, предположительно, чистых языков ООП. Функции также являются объектами, но они могут быть также конструктором объектов.
var ObjectCreator = function () {
};
Вышеупомянутая функция, которая, если вызвана соответствующим образом, создает объект. Вызывается соответствующим образом, что вы должны использовать оператор new
:
var obj = new ObjectCreator;
Таким образом, хотя JavaScript не имеет классов как таковых, имеет смысл подражать этому поведению. Например:
class Foo {
public void bar() {}
}
Foo foo = new Foo();
эквивалентен следующему JS-коду:
var Foo = function () {
// constructor
};
Foo.prototype.bar = function () {}
var foo = new Foo;
Наследование отличается
Реальная разница возникает, когда вы хотите использовать наследование, которое является другим типом наследования (прототипным). Итак, учитывая два псевдокласса Foo и Bar, если мы хотим, чтобы Bar простирался от Foo, нам пришлось бы написать:
var Foo = function () {};
var Bar = function () {};
Bar.prototype = new Foo; // this is the inheritance phase
var bar = new Bar;
alert(bar instanceof Foo);
Литералы объектов
В то время как функции-конструкторы полезны, бывают случаи, когда нам нужен только только один экземпляр этого объекта. Написание функции-конструктора, а затем заполнение его прототипа свойствами и методами, как-то утомительно. Таким образом, JavaScript имеет объектные литералы, которые являются своего рода хеш-таблицами, только потому, что они застенчивы. Я сознаю, что они знают о ключевом слове this
. Объектные литералы - отличный способ реализовать шаблон Singleton.
var john = {
age : 24,
isAdult : function () {
return this.age > 17;
}
};
Вышеприведенное, используя функцию конструктора, будет эквивалентно следующему:
var Person = function (age) {
this.age = age;
};
Person.prototype.isAdult = function () {
return this.age > 17;
};
var john = new Person(24);
Как насчет этого prototype
thingy
Как многие говорили, объекты JavaScript наследуются от объектов. У этой вещи есть полезные аспекты, один из которых можно назвать паразитическим наследованием (если я правильно помню контекст, в котором Дуглас Крокфорд упомянул об этом). Во всяком случае, эта концепция прототипа связана с концепцией цепи прототипов, которая похожа на родительскую → дочернюю цепочку в классических языках OO. Итак, материал для наследования. Если метод bar
вызывается в объекте foo
, но этот объект не имеет метода bar
, запускается фаза поиска элемента:
var Baz = function () {};
Baz.prototype.bar = function () {
alert(1);
};
var Foo = function () {};
Foo.prototype = new Baz;
var foo = new Foo;
/*
* Does foo.bar exist?
* - yes. Then execute it
* - no
* Does the prototype object of the constructor function have a bar
* property?
* - yes. Then execute it
* - no
* Is there a constructor function for the prototype object of
* the initial construct function? (in our case this is Baz)
* - yes. Then it must have a prototype. Lookup a bar
* member in that prototype object.
* - no. OK, we're giving up. Throw an error.
*/
foo.bar();
Держись, ты сказал что-то о паразитарном наследовании
Существует ключевое различие между классическим наследованием OO и наследованием на основе прототипов. Когда объекты наследуются от объектов, они также наследуют состояние. Возьмите этот пример:
var Person = function (smart) {
this.smart = smart;
};
var Adult = function (age) {
this.age = age;
};
Adult.prototype = new Person(true);
var john = new Adult(24);
alert(john.smart);
Можно сказать, что john
является паразитом анонимного Человека, потому что он беспощадно сосет человеческий интеллект. Кроме того, учитывая вышеизложенное определение, все будущие взрослые будут умными, что, к сожалению, не всегда верно. Но это не значит, что наследование объектов - это плохо. Это всего лишь инструмент, как и все остальное. Мы должны использовать его по своему усмотрению.
В классическом наследовании OO мы не можем сделать выше. Мы могли бы эмулировать его, используя статические поля. Но это сделает все экземпляры этого класса одинаковыми для этого поля.