Интересно, как лучше всего создать объект JavaScript, который имеет свойства и методы.
Я видел примеры, когда человек использовал, var self = this
а затем использовал self.
во всех функциях, чтобы убедиться, что область действия всегда правильная.
Затем я видел примеры использования .prototype
для добавления свойств, в то время как другие делают это встроенными.
Может кто-нибудь дать мне хороший пример объекта JavaScript с некоторыми свойствами и методами?
javascript
Майкл Стум
источник
источник
self
зарезервированное слово? Если нет, то должно быть; посколькуself
предопределенная переменная ссылается на текущее окно.self === window
window
объектной модели браузера, такие какdocument
orframes
; Вы, безусловно, можете повторно использовать идентификатор в качестве имени переменной. Хотя, да, стилистически я предпочитаюvar that= this
избегать любой возможной путаницы. Несмотря на то, чтоwindow.self
в конечном итоге это бессмысленно, редко есть какая-либо причина, чтобы прикоснуться к нему.this
локальной переменной (напримерself
) уменьшает размер файла.Ответы:
Существует две модели для реализации классов и экземпляров в JavaScript: способ прототипирования и способ замыкания. Оба имеют свои преимущества и недостатки, и существует множество расширенных вариантов. Многие программисты и библиотеки используют разные подходы и функции утилит для обработки классов, чтобы наметить некоторые уродливые части языка.
В результате в смешанной компании вы получите смесь метаклассов, которые ведут себя немного по-разному. Что еще хуже, большинство учебных материалов по JavaScript ужасны и служат неким промежуточным компромиссом, охватывающим все основы, оставляя вас в замешательстве. (Возможно, автор также запутался. Объектная модель JavaScript сильно отличается от большинства языков программирования, и во многих местах она плохо спроектирована.)
Давайте начнем с прототипа . Это самый естественный JavaScript-код, который вы можете получить: минимальный объем служебного кода и instanceof будет работать с экземплярами такого типа объектов.
Мы можем добавить методы к созданному экземпляру
new Shape
, написав их вprototype
поиске этой функции конструктора:Теперь, чтобы создать его подкласс, настолько, насколько вы можете назвать то, что JavaScript делает подклассами. Мы делаем это, полностью заменяя это странное магическое
prototype
свойство:перед добавлением методов к нему:
Этот пример будет работать, и вы увидите код, подобный этому, во многих руководствах. Но,
new Shape()
черт возьми , это ужасно: мы создаем экземпляр базового класса, хотя фактическая форма не должна быть создана. Случается работать в этом простом случае , поскольку JavaScript настолько неаккуратен: она позволяет нулевые аргументы, которые передаются в, в каком случаеx
иy
статьundefined
и назначены на прототипthis.x
иthis.y
. Если бы функция конструктора делала что-то более сложное, она бы не получалась.Поэтому нам нужно найти способ создать объект-прототип, который содержит методы и другие члены, которые нам нужны на уровне класса, без вызова функции конструктора базового класса. Для этого нам нужно начать писать вспомогательный код. Это самый простой из известных мне подходов:
Это передает членов базового класса в его прототипе новой функции конструктора, которая ничего не делает, а затем использует этот конструктор. Теперь мы можем написать просто:
вместо
new Shape()
неправильности. Теперь у нас есть приемлемый набор примитивов для построенных классов.Есть несколько уточнений и расширений, которые мы можем рассмотреть в рамках этой модели. Например, вот синтаксически-сахарная версия:
У любой версии есть недостаток, заключающийся в том, что функция конструктора не может быть унаследована, как во многих языках. Таким образом, даже если ваш подкласс ничего не добавляет к процессу конструирования, он должен не забывать вызывать конструктор базы с любыми аргументами, которые требуется базе. Это может быть немного автоматизировано с помощью
apply
, но все же вы должны написать:Таким образом, общее расширение состоит в том, чтобы разбить материал инициализации на его собственную функцию, а не на сам конструктор. Эта функция может потом наследовать от базы просто отлично:
Теперь у нас есть один и тот же шаблон функций конструктора для каждого класса. Может быть, мы можем переместить это в свою собственную вспомогательную функцию, чтобы нам не приходилось постоянно печатать ее, например, вместо того
Function.prototype.subclass
, чтобы переворачивать ее и позволить функции базового класса выплевывать подклассы:... который начинает больше походить на другие языки, хотя и с немного неуклюжим синтаксисом. Вы можете добавить несколько дополнительных функций, если хотите. Может быть, вы хотите
makeSubclass
взять и запомнить имя класса и указать его по умолчаниюtoString
. Может быть, вы хотите, чтобы конструктор определял, когда он был случайно вызван безnew
оператора (что в противном случае часто приводило бы к очень раздражающей отладке):Может быть, вы хотите передать всех новых участников и
makeSubclass
добавить их в прототип, чтобы избавить вас от необходимости писатьClass.prototype...
так много. Многие системы классов делают это, например:Существует множество потенциальных возможностей, которые вы можете посчитать желательными в объектной системе, и никто не может согласиться с одной конкретной формулой.
Путь закрытия , тогда. Это позволяет избежать проблем наследования на основе прототипов JavaScript, поскольку вообще не использует наследование. Вместо:
Теперь каждый экземпляр
Shape
будет иметь свою собственную копиюtoString
метода (и любые другие методы или другие члены класса, которые мы добавим).Плохая вещь в каждом экземпляре, имеющем собственную копию каждого члена класса, состоит в том, что он менее эффективен. Если вы имеете дело с большим количеством подклассовых экземпляров, прототипное наследование может помочь вам лучше. Кроме того, вызов метода базового класса немного раздражает, как вы можете видеть: мы должны помнить, каким был метод, до того, как конструктор подкласса перезаписал его, или он потеряется.
[Кроме того, поскольку здесь нет наследования,
instanceof
оператор не будет работать; Вы должны будете предоставить свой собственный механизм для прослушивания классов, если вам это нужно. Хотя вы можете возиться с объектами-прототипами так же, как и с наследованием прототипов, это немного сложно и не стоит того, чтобы простоinstanceof
работать.]Хорошая вещь о каждом экземпляре, имеющем свой собственный метод, - то, что метод может тогда быть привязан к определенному экземпляру, которому он принадлежит. Это полезно из-за странного способа привязки JavaScript
this
в вызовах методов, который приводит к тому, что если вы отсоедините метод от его владельца:тогда
this
внутри метода не будет ожидаемого экземпляра Circle (на самом деле это будет глобальныйwindow
объект, вызывающий горе отладки). В действительности это обычно происходит , когда метод принимается и присваиваетсяsetTimeout
,onclick
илиEventListener
в целом.При использовании прототипа вы должны включать закрытие для каждого такого назначения:
или в будущем (или сейчас, если вы взломали Function.prototype), вы также можете сделать это с помощью
function.bind()
:если ваши экземпляры выполняются способом закрытия, привязка выполняется бесплатно закрытием по переменной экземпляра (обычно вызываемой
that
илиself
, хотя лично я бы посоветовал против последней, поскольку онаself
уже имеет другое, другое значение в JavaScript). Вы не получаете аргументы1, 1
в приведенном выше фрагменте бесплатно, поэтому вам все равно понадобится другое закрытие или a,bind()
если вам нужно это сделать.Есть много вариантов метода закрытия. Вы можете предпочесть
this
полностью опустить , создавая новыйthat
и возвращая его вместо использованияnew
оператора:Какой путь «правильный»? Обе. Что является «лучшим»? Это зависит от вашей ситуации. FWIW Я склонен к созданию прототипов для реального наследования JavaScript, когда я сильно занимаюсь OO, и замыканий для простых одноразовых эффектов страницы.
Но оба способа довольно противоречивы для большинства программистов. У обоих есть много потенциальных беспорядочных изменений. Вы встретите обе (а также многие промежуточные и вообще неработающие схемы), если будете использовать код / библиотеки других людей. Нет единого общепринятого ответа. Добро пожаловать в удивительный мир объектов JavaScript.
[Это было частью 94 Почему JavaScript не мой любимый язык программирования.]
источник
new
.Я использую этот шаблон довольно часто - я обнаружил, что он дает мне довольно большую гибкость, когда мне это нужно. В использовании он довольно похож на классы в стиле Java.
При этом используется анонимная функция, которая вызывается при создании, возвращая новую функцию конструктора. Поскольку анонимная функция вызывается только один раз, вы можете создать в ней частные статические переменные (они находятся внутри замыкания, видимого для других членов класса). Функция конструктора в основном является стандартным объектом Javascript - вы определяете закрытые атрибуты внутри нее, а публичные атрибуты присоединяются к
this
переменной.По сути, этот подход сочетает в себе крокфордский подход со стандартными объектами Javascript для создания более мощного класса.
Вы можете использовать его так же, как и любой другой объект Javascript:
источник
this
, нужно ли создавать его экземплярnew
?this
действительно привыкают вconstructor
функции, которая становитсяFoo
в примере.constructor.prototype.myMethod = function () { ... }
.Дуглас Крокфорд широко обсуждает эту тему в «Хороших частях» . Он рекомендует избегать нового оператора для создания новых объектов. Вместо этого он предлагает создавать индивидуальные конструкторы. Например:
В Javascript функция является объектом и может использоваться для создания объектов вместе с оператором new . По соглашению, функции, предназначенные для использования в качестве конструкторов, начинаются с заглавной буквы. Вы часто видите такие вещи, как:
В случае , если вы забыли использовать новый оператор , а инстанцирование нового объекта, то , что вы получаете обычный вызов функции, и это связанно с глобальным объектом , а не на новый объект.
источник
new
вvar that = {};
любом случае есть скрытое .Чтобы продолжить от ответа Бобинса
В es6 теперь вы можете создать
class
Итак, теперь вы можете сделать:
Таким образом, расширить круг (как в другом ответе) вы можете сделать:
Заканчивается немного чище в es6 и немного легче для чтения.
Вот хороший пример этого в действии:
Показать фрагмент кода
источник
Вы также можете сделать это таким образом, используя структуры:
Затем :
источник
Другим способом было бы http://jsfiddle.net/nnUY4/ (я не знаю, следует ли этому виду обработки функций создания и раскрытия объекта какой-либо конкретной модели)
источник
Когда кто-то использует трюк закрытия «this» во время вызова конструктора, он предназначен для того, чтобы написать функцию, которая может использоваться в качестве обратного вызова каким-либо другим объектом, который не хочет вызывать метод объекта. Это не связано с тем, чтобы сделать прицел правильным.
Вот ванильный объект JavaScript:
Вы можете многое узнать о том, что Дуглас Крокфорд говорит о JavaScript. Джон Резиг также великолепен. Удачи!
источник
this
имеет отношение к тому, чтобы "сделать прицел правильным".self=this
хотя не заставляетthis
упорствовать, легко позволяет «исправить» область видимости через замыкание.Closure
универсален. bobince хорошо суммировал подходы прототипа и замыкания при создании объектов. Однако вы можете имитировать некоторые аспектыOOP
использования замыкания в функциональном программировании. Помните, что функции - это объекты в JavaScript ; так что используйте функцию как объект по-другому.Вот пример закрытия:
Некоторое время назад я наткнулся на статью Mozilla о закрытии. Вот что бросается в глаза: «Закрытие позволяет связать некоторые данные (среду) с функцией, которая работает с этими данными. Это имеет очевидные параллели с объектно-ориентированным программированием, где объекты позволяют нам связывать некоторые данные (свойства объекта). ) одним или несколькими методами ". Это был первый раз, когда я прочитал параллелизм между замыканием и классическим ООП без ссылки на прототип.
Как?
Предположим, вы хотите рассчитать НДС для некоторых товаров. НДС, вероятно, останется стабильным в течение срока действия заявки. Один из способов сделать это в ООП (псевдокод):
По сути, вы передаете значение НДС в свой конструктор, и ваш метод расчета может работать с ним через замыкание . Теперь вместо использования класса / конструктора передайте свой НДС в качестве аргумента в функцию. Поскольку единственное, что вас интересует, - это сами вычисления, возвращает новую функцию, которая является методом вычисления:
В вашем проекте определите значения верхнего уровня, которые являются хорошим кандидатом для расчета НДС. Как правило, всякий раз, когда вы передаете одни и те же аргументы, есть способ улучшить его с помощью замыкания. Не нужно создавать традиционные объекты.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures
источник
Создание объекта
Самый простой способ создать объект в JavaScript - это использовать следующий синтаксис:
Это прекрасно работает для хранения данных в структурированном виде.
Однако для более сложных вариантов использования часто лучше создавать экземпляры функций:
Это позволяет вам создавать несколько объектов, которые разделяют один и тот же «план», подобно тому, как вы используете классы, например, в. Ява.
Однако это можно сделать более эффективно, используя прототип.
Когда разные экземпляры функции совместно используют одни и те же методы или свойства, вы можете переместить их в прототип этого объекта. Таким образом, каждый экземпляр функции имеет доступ к этому методу или свойству, но его не нужно дублировать для каждого экземпляра.
В нашем случае имеет смысл перенести метод
f
на прототип:наследование
Простой, но эффективный способ сделать наследование в JavaScript, это использовать следующий двухслойный:
Это похоже на это:
Основное различие между ними заключается в том, что при использовании конструктор
A
не запускаетсяObject.create
, что более интуитивно понятно и более похоже на наследование на основе классов.Вы всегда можете выбрать, при необходимости, запустить конструктор
A
при создании нового экземпляраB
, добавив его в конструкторB
:Если вы хотите передать все аргументы
B
вA
, вы также можете использоватьFunction.prototype.apply()
:Если вы хотите смешать другой объект в цепочке конструктора
B
, вы можете комбинироватьObject.create
сObject.assign
:демонстрация
Запись
Object.create
может безопасно использоваться в любом современном браузере, включая IE9 +.Object.assign
не работает ни в одной версии IE, ни в некоторых мобильных браузерах. Рекомендуется заполнитьObject.create
и / илиObject.assign
использовать их и поддерживать браузеры, которые их не реализуют.Вы можете найти полифилл
Object.create
здесь и одинObject.assign
здесь .источник
источник
В дополнение к принятому ответу от 2009 года. Если вы можете ориентироваться на современные браузеры, можно использовать Object.defineProperty .
Чтобы увидеть список совместимости с настольными компьютерами и мобильными устройствами, см . Список совместимости браузера Mozilla . Да, IE9 + поддерживает его так же, как Safari mobile.
источник
Вы также можете попробовать это
источник
Во- первых, вы можете изменить свое предпочтение при добавлении методов к примеру , вместо конструктора
prototype
объекта . Я почти всегда объявляю методы внутри конструктора, потому что я часто использую Constructor Hijacking для целей наследования и декораторов.Вот как я решаю, куда пишутся декларации:
this
)var
объявления имеют приоритет надfunction
объявлениями{}
и[]
)public
объявления имеют приоритет надprivate
объявлениямиFunction.prototype.bind
болееthus
,self
,vm
,etc
this
из Лексической Области Пространства Закрытия.Вот почему они помогают:
Конструктор угон Модельный дизайн Шаблоны проектированияКак видите, я действительно не нуждаюсь в этом,
thus
так как предпочитаюFunction.prototype.bind
(или.call
или.apply
) болееthus
. В нашемSingleton
классе мы даже не называем его,thus
потому чтоINSTANCE
передает больше информации. ИбоModel
мы возвращаемся,this
чтобы мы могли вызвать конструктор, используя.call
для возврата экземпляр, который мы передали в него. Избыточно, мы присвоили его переменнойupdated
, хотя это полезно в других сценариях.Кроме того, я предпочитаю создавать объектные литералы, используя
Preferred Не предпочитаемыйnew
ключевое слово над {скобками}:Как видите, последний не имеет возможности переопределить свойство override своего суперкласса.
Если я добавляю методы к
Preferred Не предпочитаемыйprototype
объекту класса , я предпочитаю литерал объекта - с использованием или без использованияnew
ключевого слова:источник
Я хотел бы отметить, что мы можем использовать либо заголовок, либо строку для объявления объекта.
Есть разные способы вызова каждого типа из них. См. ниже:
источник
По сути, в JS нет понятия класса, поэтому мы используем функцию в качестве конструктора класса, которая соответствует существующим шаблонам проектирования.
До сих пор JS не имеет ни малейшего представления о том, что вы хотите создать объект, поэтому здесь появляется новое ключевое слово.
Ссылка: Профессиональный JS для веб-разработчиков - Nik Z
источник
class
, которое вы упомянули в заголовке, используяfunction
ключевое слово. Это не шаблон проектирования, а преднамеренная особенность языка. Я не отрицал вас по этому поводу, но похоже, что кто-то другой сделал это из-за краткости и почти неуместного вопроса. Надеюсь, что этот отзыв поможет.