Ответ 1
В JavaScript нет классов, как говорили другие. Наследование разрешается посредством прототипирования, которое по существу не более чем создает неистинные ссылки на свойства вновь созданного объекта. JavaScript также имеет альтернативы простым объектам данных, а именно объектным литералам.
Изменение "класса" в JavaScript должно быть определено как таковое:
// I use function statements over variable declaration
// when a constructor is involved.
function Person(name) {
this.name = name;
}
// All instances of Person create reference methods to it prototype.
// These references are not deletable (but they can be overwritten).
Person.prototype = {
speak: function(){
alert(this.name + ' says: "Hello world!"');
}
};
var Mary = new Person('Mary');
Mary.speak(); // alerts 'Mary says: "Hello world!"'
Ссылка this
всегда указывает на владельца function
. Если вы вызываете Person
без оператора new
, то владельцем будет глобальная область (окно). Если вы не используете эту ссылку для назначения свойств вашему экземпляру, то свойства будут просто объявлены как переменные. Если вы не используете оператор var
, то эти объявления будут создавать глобальные переменные, которые являются плохими!
подробнее об этом
Использование ссылки this
в функции конструктора чрезвычайно важно, если вы хотите добавить свойства к текущему экземпляру. Без использования this
вы создаете только переменную (которая не совпадает с свойством) и, как уже упоминалось, если вы также не используете оператор var, вы создаете глобальные переменные.
function Person(){
name = 'Mary'
}
var p = new Person();
alert(p.name); // undefined, did not use 'this' to assign it to the instance.
alert(name); // 'Mary', boo, it created a global variable!
Используйте это!
function Person(){
this.name = 'Mary'
}
var p = new Person();
alert(p.name); // 'Mary', yay!
alert(name); // undefined, yay!
Примечание. Все, что присваивается экземпляру через конструктор функции, НЕ МОЖЕТ БЫТЬ ВЕРНО, если вы не назначаете его прототипу и не перезаписываете его снова в конструкторе функций, чтобы сделать его собственностью.
Когда вы создаете новый экземпляр функции с удвоением функции в качестве конструктора, на самом деле происходит следующее.
pseudo code:
copy Person.prototype as person
invoke Person function on person
return person
Собственно, это то, что происходит на каждом классическом языке, когда вы создаете экземпляр класса. Но основное отличие JavaScript заключается в том, что он не инкапсулирован в классный оператор класса. Первоначально JavaScript даже не имел конструкторов функций, но был добавлен позже, потому что SUN потребовал, чтобы они хотели, чтобы JavaScript был больше похож на Java.
Литералы объектов
Альтернатива для конструкторов функций для объектов, которые содержат только внутренние данные, а методы не являются объектными литералами.
var Mary = {
firstName: 'Mary',
lastName: 'Littlelamb'
};
Каков предпочтительный способ объявления внутренних объектов, а не:
// do not ever do this!
var Mary = new Object();
Mary.firstName = 'Mary';
Mary.lastName = 'Littlelamb';
С объектными литералами в вашем наборе навыков вы можете создать шаблон factory для внутренних объектов данных с помощью шаблона модуля (который обычно для однолетних).
var createPerson = function(firstName, lastName){
return {
firstName: firstName,
lastName: lastName
}
}
var Mary = createPerson('Mary', 'Littlelamb');
Это обеспечивает удобную инкапсуляцию, но может использоваться только для встроенных объектов данных.
Еще одна вещь, которую вы можете сделать с объектными литералами и JavaScript - это делегирование, которое должно быть предпочтительным.
var personMethods = {
speak: function(){
alert(this.firstName + ' says: "Hello world!"');
}
};
var Mary = {
firstName: "Mary",
lastName: "Littlelamb"
};
var Peter = {
firstName: "Peter",
lastName: "Crieswolf"
};
personMethods.speak.apply(Mary); // alerts 'Mary says: "Hello world!"'
personMethods.speak.apply(Peter); // alerts 'Peter says: "Hello world!"'
Почему это должно быть предпочтительным? Поскольку он сохраняет ваши объекты в минутах и читабельны, даже прототипные ссылки занимают память, а при использовании наследования и "подклассификации" вы получаете дочерние экземпляры, у которых есть много неиспользуемых ссылок на методы. Делегирование всегда лучше.