Разница между конструктором и объектом
Я определенно нуждаюсь в этом.
Какая разница между:
var MY_APP = function(){
this.firstMethod = function(){
//something
};
this.secondMethod = function(){
//something
};
};
а также
var MY_APP = {
firstKey: function(){
//something
},
secondKey: function(){
//something
}
};
Помимо очевидного факта, что один является Функцией, а другой - Объектом, каковы различия в потоке кода, прототипах, шаблонах... что угодно, и когда мы должны использовать первое или второе?
Я так разнесен в этой области, что я не уверен, правильно ли я объясняю сомнение, но если вы спросите, можно дать дополнительную информацию.
4 ответа
Основное различие между ними заключается в том, как они предназначены для использования. Конструктор, как следует из его названия, предназначен для создания и настройки нескольких экземпляров объекта. С другой стороны, литерал объекта является одноразовым, как строковые и числовые литералы, и чаще используется в качестве объектов конфигурации или глобальных синглетонов (например, для пространств имен).
Есть несколько тонкостей первого примера, на которые следует обратить внимание:
- Когда код выполняется, анонимная функция создается и присваивается MY_APP, но больше ничего не происходит.
firstMethod
а такжеsecondMethod
не существует, пока MY_APP не будет явно вызван. - В зависимости от того, как вызывается MY_APP, методы
firstMethod
а такжеsecondMethod
окажутся в разных местах:MY_APP()
: Поскольку контекст не указан,this
по умолчаниюwindow
и методы станут глобальными.var app1 = new MY_APP()
: Из-заnew
ключевое слово, новый объект создается и становится контекстом по умолчанию.this
ссылается на новый объект, и методы будут назначены новому объекту, который впоследствии будет назначенapp1
, Тем не мение,MY_APP.firstMethod
остается неопределенным.MY_APP.call(YOUR_APP)
: Это вызывает мой MY_APP, но устанавливает контекст для другого объекта,YOUR_APP
, Методы будут назначеныYOUR_APP
переопределяя любые свойстваYOUR_APP
с такими же именами. Это действительно гибкий метод, который позволяет множественное наследование или миксины в Javascript.
Конструкторы также допускают другой уровень гибкости, поскольку функции обеспечивают замыкания, а литералы объектов - нет. Если например firstMethod
а также secondMethod
полагаться на общую переменную password
который является приватным для объекта (недоступен вне конструктора), это можно сделать очень просто, выполнив:
var MY_APP = function(){
var password = "GFHSFG";
this.firstMethod = function(){
// Do something with password
alert(password); // Woops!
};
this.secondMethod = function(){
// Do something else with password
};
};
MY_APP();
alert(password); // undefined
alert(MY_APP.password); // undefined
Конструктор может быть повторно использован как есть, литерал объекта должен быть повторен или включен в функцию для повторного использования.
Пример переноса литерала объекта в функцию:
function MY_APP() {
return {
firstKey: function(){
//something
},
secondKey: function(){
//something
}
};
}
Объект, созданный с использованием конструктора, будет иметь свойство конструктора, установленное для функции конструктора. Однако, поскольку вы использовали анонимную функцию, назначенную переменной вместо именованной функции, конструктор все равно останется безымянным.
Кроме этого, нет никаких различий. Оба создают анонимные функции, которые назначаются свойствам объекта, поэтому результирующие объекты одинаковы. Это можно сравнить с назначением именованных функций свойствам или использованием функций-прототипов, причем обе имеют различие в том, что каждая функция существует только один раз, а не создается снова и снова для каждого объекта.
Первый - это функция, второй - объектный литерал. Поскольку функции в JS являются объектами первого класса, функция может иметь свойства, как и любой другой объект.
Как правило, если вы хотите создать "класс", с которым вы, возможно, знакомы по классическим языкам наследования, вы должны сделать что-то вроде
function MyClass() {...}
как описано здесь http://www.crockford.com/javascript/inheritance.html
Чтобы ответить на вопрос, заданный в ваших изменениях, вы должны использовать их в разных ситуациях. Объектные литералы используются для передачи конфигураций. Типичный шаблон использования - это метод, который принимает объектный литерал, например
something.init({
length: 10,
height: 10,
text: 'some text'
});
и так далее.
Вы можете использовать что-то похожее на ваш первый пример при создании пространства имен. Javascript имеет некоторые интересные языковые особенности, в которых вы можете иметь так называемые "самопризывающие функции", которые имеют вид:
var myApp = (function(){
var firstMethod = function() {...}
...
})();
Мотивы, стоящие за этим, подробно описаны здесь.
http://sparecycles.wordpress.com/2008/06/29/advanced-javascript/
Вы также можете исследовать различия через вашу любимую консоль отладки JavaScript. В Firebug и Chrome я сделал следующее:
var ol = {}; ol.prototype;
var fn = function () {}; fn.prototype;
первая строка печатает undefined, вторая возвращает прототип с конструктором 'function'
В JavaScript есть некоторая путаница относительно различий между функцией и объектом.
В первом случае
var MY_APP = function() { this.v = 7; ... }
или же
function MY_APP(x) { this.v = x; ... }
объявлена функция, а не объект. В MY_APP, this
относится к глобальному объекту.
Это означает, что вызов функции MY_APP(7) v
глобально до значения 7. (и в вашем случае функция firstMethod
будет объявлено глобально).
MY_APP(3); // The global variable v is set to 3
MY_APP(4); // The global variable v is overwritten and set to 4
Чтобы использовать MY_APP в качестве объекта, его необходимо создать, например,
var obj1 = new MY_APP(3);
var obj2 = new MY_APP(4);
буду иметь obj1.v
быть 3, и obj2.v
быть 4.
Обратите внимание, что вы также можете добавить методы, используя prototype
ключевое слово (вместо this.firstMethod...)
MY_APP.prototype.firstMethod = function () { ... }
Во втором случае
var MY_APP = { ... };
объект, один объект, создан, и его имя MY_APP. this
ключевые слова ссылаются на этот объект, MY_APP.