Объектно-ориентированные вопросы в Javascript

Некоторое время я использую 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, скорее всего, будет более эффективным и будет использовать меньше памяти, поскольку все объекты будут использовать одни и те же функции.

Я очень ценю все отличные ответы - Спасибо!

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
40
0
4 818
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

Каждый раз, когда функция 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");

Думаю, я имею в виду, что вопрос №2 заключается в том, как я могу изменить функцию №3, чтобы я мог сказать что-то вроде var person = new User ();

BrianH 14.01.2009 21:53

Этот комментарий не совсем верен: «Все разные функции getName ведут себя совершенно одинаково». Тип # 2 имеет доступ к частным варам

meouw 14.01.2009 23:12

Тип №1 не имеет доступа к частным варам? Или вы говорите, что функция getName в № 2 имеет доступ к возрасту, но функция getName в № 1 имеет доступ только к имени, а не к возрасту?

BrianH 14.01.2009 23:20

Есть способ использовать лексическую область видимости для подделки частных переменных. Вам, вероятно, пока не стоит об этом беспокоиться, но если вам интересно, см. crockford.com/javascript/private.html

Andru Luvisi 14.01.2009 23:35

Это немного глубоко, но я сохранил его в своем восхитительном аккаунте на потом - спасибо!

BrianH 15.01.2009 05:36

Это великолепно. Я пытался понять, как правильно использовать Javascript, и это многое прояснило.

Timmy O'Mahony 21.06.2011 17:56

2:

Вы можете получить доступ к имени и возрасту, не используя такие функции. В 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);

Когда вы создаете объект с помощью {} (литерал объекта), {} является конструктором (зависит от браузера). Но, по сути, нет, вы не можете использовать конструктор в этом формате.

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

meouw 14.01.2009 23:02

В вашем примере №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 :)

Dan Rosenstark 18.07.2009 01:15

Кажется, у вас есть несколько хороших ответов, но вы, возможно, захотите посмотреть на этот вопрос: лучший подход к переменным-членам в объектно-ориентированном JavaScript. Это был мой ответ, который описывает различия и сходства.

Если вас интересуют разговоры о декларации класса JavaScript в стиле JSON ...

http://mahtonu.wordpress.com/2010/04/13/json-style-javascript-object-declaration/

Другие вопросы по теме