Некоторое время я использую javascript, но никогда не изучал язык, кроме основ. Я читаю книгу Джона Ресига «Pro Javascript Techniques» - у меня возникают некоторые вопросы, но я не нахожу ответов на них в книге, в Google и т. д.
Джон приводит этот пример в своей книге:
Функция # 1
function User( name, age ){
this.name = name;
this.age = age;
}
// Add a new function to the object prototype
User.prototype.getName = function(){
return this.name;
};
User.prototype.getAge = function(){
return this.age;
};
var user = new User( "Bob", 44 );
console.info("User: " + user.getName() + ", Age: " + user.getAge());
Я все еще изучаю свойство опытный образец, поэтому я попытался написать что-то подобное:
Функция # 2
function User (name, age ) {
this.name = name;
this.age = age;
this.getName = function() {
return this.name;
};
this.getAge = function() {
return this.age;
};
}
var user = new User( "Bob", 44 );
console.info("User: " + user.getName() + ", Age: " + user.getAge());
Он не использует свойство опытный образец для создания функций getName и getAge, но вывод такой же, как в примере Джона.
Я сделал еще один шаг и создал это:
Функция # 3
var User = {
name: "",
age: 0,
setName: function(name) {
this.name = name;
},
setAge: function(age) {
this.age = age;
},
getName: function() {
return this.name;
},
getAge: function() {
return this.age;
}
};
User.setName("Bob");
User.setAge(44);
console.info("User: " + User.getName() + ", Age: " + User.getAge());
Опять же - он выглядит иначе, чем пример Джона (и мне пришлось добавить методы установки), но результат тот же.
Вопрос 1 - в чем разница между 3 функциями? В чем преимущество свойства prototype и что функция № 2 что-то делает неправильно, потому что кажется более простым код № 2 вместо № 1 (хотя я уверен, что № 1 делает это лучше, видя, как это создал Джон) .
Вопрос 2 - Как я мог изменить функцию № 3, чтобы не использовать методы setName и setAge, но при этом сохранить сокращенное обозначение {...}? Может ли сокращение {...} иметь конструкторы?
Заранее благодарим за помощь в обучении!
РЕДАКТИРОВАТЬ Я думаю, что мой второй вопрос немного сбил с толку. Я имел в виду, как я могу использовать сокращение {...} для создания объекта User, но затем после того, как я создам объект, скажите что-то вроде:
var user = new User("Bob", 44);
Так же, как в функции №1 - или это невозможно?
РЕДАКТИРОВАТЬ # 2 Ух ты! Спасибо всем за отличные ответы. Это действительно проясняет мне ситуацию. Так что, если я правильно понимаю, разница между №1 и №2 не так уж велика. Если я когда-либо создам только один объект «Пользователь» - они, вероятно, вообще не будут отличаться. Но если моя программа создает много объектов User, №1, скорее всего, будет более эффективным и будет использовать меньше памяти, поскольку все объекты будут использовать одни и те же функции.
Я очень ценю все отличные ответы - Спасибо!



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Каждый раз, когда функция function () {} оценивается, она создает новый объект функции. Следовательно, в № 1 все объекты User используют одни и те же функции getName и getAge, но в № 2 и № 3 каждый объект имеет свою собственную копию getName и getAge. Все разные функции getName ведут себя одинаково, поэтому вы не увидите никакой разницы в выводе.
Сокращение {...} является a конструктор. При оценке он создает новый «объект» с заданными свойствами. Когда вы запускаете «новый пользователь (...)», он создает нового «пользователя». Вы случайно создали объект с таким же поведением, что и пользователь, но они бывают разных типов.
Ответ на комментарий:
Вы не можете напрямую. Вы можете создать функцию, которая создает новый объект согласно №3. Например:
function make_user(name, age) {
return {
name: name,
age: age,
getName: function() { return name; },
getAge: function() { return age; },
};
}
var user = make_user("Joe", "18");
Этот комментарий не совсем верен: «Все разные функции getName ведут себя совершенно одинаково». Тип # 2 имеет доступ к частным варам
Тип №1 не имеет доступа к частным варам? Или вы говорите, что функция getName в № 2 имеет доступ к возрасту, но функция getName в № 1 имеет доступ только к имени, а не к возрасту?
Есть способ использовать лексическую область видимости для подделки частных переменных. Вам, вероятно, пока не стоит об этом беспокоиться, но если вам интересно, см. crockford.com/javascript/private.html
Это немного глубоко, но я сохранил его в своем восхитительном аккаунте на потом - спасибо!
Это великолепно. Я пытался понять, как правильно использовать Javascript, и это многое прояснило.
Вы можете получить доступ к имени и возрасту, не используя такие функции. В javascript вы должны использовать разные хаки, чтобы сохранить что-то приватным или защищенным.
Этот
User.name = "BoB";
User.age = 44;
выдаст тот же результат, что и ваш пример.
В других языках конструкторов нет. Самый простой способ - просто определить функцию init () и вызвать ее сразу после создания экземпляра объекта.
Но мой самый большой совет - загляните в http://www.prototypejs.org/. Это библиотека javascript с множеством интересных функций, которая пытается сделать javascript «более OO *».
Используя библиотеку прототипов, вы можете сделать классы более похожими на настоящие классы ООП. Также есть конструкторы.
Редактировать: Что касается того, что вы спросили в своем комментарии:
person = new User();
person.name = "Bob";
person.age = 44;
Вопрос 1
prototype имеет преимущество исправление обезьяны. Как показывает первый пример, функции добавляются постфактум. Вы можете продолжить это, добавляя или заменяя любые нужные вам методы (правда, с честным предупреждением).
Определение таких объектов, как №2, больше похоже на классическое ООП. Но, опять же, исправление обезьян разрешено не на всех языках ООП.
Вопрос 2
В вашей третьей функции вам даже не нужны функции get и set - name и age являются общедоступными свойствами (потенциальный недостаток {}).
var User = {
name: "",
age: 0
};
User.name = 'Bob';
User.age = 44;
console.info("User: " + User.name + ", Age: " + User.age);
Когда вы создаете объект с помощью {} (литерал объекта), {} является конструктором (зависит от браузера). Но, по сути, нет, вы не можете использовать конструктор в этом формате.
Добавление свойства или метода к определенному пользователем объекту не квалифицируется как исправление обезьяны. Патч обезьяны - это добавление методов или свойств к встроенным объектам, то есть изменение поведения самого языка.
В вашем примере №1 показано использование свойства prototype. Это свойство доступно для всех создаваемых вами объектов javascript и позволяет добавлять свойства или функции к объявлению объекта, поэтому у вас был объект с двумя свойствами, а позже вы добавили 4 функции (геттеры и сеттеры).
Вы должны рассматривать свойство prototype как способ изменить спецификацию объекта во время выполнения, скажем, у вас есть объект с именем name:
var Name = {
First: "",
Last: ""
};
Вы можете использовать прототип для добавления функции getFullName () позже, просто:
Name.prototype.getFullName = function() { return this.First + " " + this.Last; }
В примере 2 вы встраиваете объявление этих геттеров и сеттеров в объявление объекта, поэтому в конечном итоге они совпадают. Наконец, в третьем примере вы используете нотацию объекта JavaScript, вы должны увидеть JSON.
Что касается вашего вопроса 2, вы можете просто объявить свой объект как:
var User = {
name: "",
age: 0
};
это даст вам тот же объект без геттеров и сеттеров.
Если вы хотите использовать ООП в JavaScript, я настоятельно рекомендую поискать замыкания. Я начал свое изучение предмета с этих трех веб-страниц:
http://www.dustindiaz.com/javascript-private-public-privileged/
http://www.dustindiaz.com/namespace-your-javascript/
http://blog.morrisjohns.com/javascript_closures_for_dummies
Различия между 1, 2 и 3 заключаются в следующем: 1) Это пример добавления новых методов к существующему объекту. 2) То же, что и №1, за исключением того, что некоторые методы включены в объект в функции User. 3) Это пример определения объекта с помощью JSON. Недостатком является то, что вы не можете использовать new (по крайней мере, в этом примере) для определения новых экземпляров этого объекта. Однако вы получаете преимущество удобного стиля кодирования JSON.
Вам обязательно стоит почитать о JSON, если вы еще этого не знаете. Когда вы поймете JSON, JavaScript станет более понятным.
редактировать Если вы хотите использовать новое в функции № 3, вы можете написать его как
function User() {
return {
name: "",
age: 0,
setName: function(name) {
this.name = name;
},
setAge: function(age) {
this.age = age;
},
getName: function() {
return this.name;
},
getAge: function() {
return this.age;
}
};
}
Конечно, тогда все эти функции и свойства станут общедоступными. Чтобы сделать их закрытыми, вам нужно использовать закрытие. Например, с помощью этого синтаксиса вы можете сделать возраст и имя закрытыми.
function User() {
var age=0;
var name = "";
return {
setName: function(name_) {
name = name_;
},
setAge: function(age_) {
age = age_;
},
getName: function() {
return name;
},
getAge: function() {
return age;
}
};
}
Спасибо за это ... надеюсь, вы все еще здесь и отвечаете на вопросы на SO :)
Кажется, у вас есть несколько хороших ответов, но вы, возможно, захотите посмотреть на этот вопрос: лучший подход к переменным-членам в объектно-ориентированном JavaScript. Это был мой ответ, который описывает различия и сходства.
Если вас интересуют разговоры о декларации класса JavaScript в стиле JSON ...
http://mahtonu.wordpress.com/2010/04/13/json-style-javascript-object-declaration/
Думаю, я имею в виду, что вопрос №2 заключается в том, как я могу изменить функцию №3, чтобы я мог сказать что-то вроде var person = new User ();