какая разница между
var A = function () {
this.x = function () {
//do something
};
};
а также
var A = function () { };
A.prototype.x = function () {
//do something
};
javascript
prototype
this
sw234
источник
источник
a1.x !== a2.x
:; по прототипу:a1.x === a2.x
Ответы:
Примеры имеют очень разные результаты.
Прежде чем смотреть на различия, следует отметить следующее:
[[Prototype]]
свойство экземпляра .myObj.method()
), то это внутри метода ссылается на объект. Если это не установлено вызовом или использованием bind , по умолчанию используется глобальный объект (окно в браузере) или в строгом режиме, он остается неопределенным.Итак, вот такие фрагменты:
В этом случае переменной
A
присваивается значение, которое является ссылкой на функцию. Когда эта функция вызывается с использованиемA()
, функция this не устанавливается вызовом, поэтому по умолчанию используется глобальный объект, и выражениеthis.x
действуетwindow.x
. В результате ссылка на выражение функции в правой части назначаетсяwindow.x
.На случай, если:
происходит что-то совсем другое. В первой строке переменной
A
присваивается ссылка на функцию. В JavaScript все объекты функций по умолчанию имеют свойство prototype , поэтому нет отдельного кода для создания объекта A.prototype .Во второй строке A.prototype.x назначается ссылка на функцию. Это создаст свойство x, если оно не существует, или назначит новое значение, если оно существует. Таким образом, разница с первым примером, в котором свойство x объекта участвует в выражении.
Другой пример ниже. Это похоже на первый (и, возможно, о чем вы хотели спросить):
В этом примере
new
оператор был добавлен перед выражением функции, поэтому функция вызывается как конструктор. При вызове сnew
помощью функции this устанавливается ссылка на новый объект, частное[[Prototype]]
свойство которого установлено для ссылки на открытый прототип конструктора . Таким образом, в операторе присваиванияx
будет создано свойство для этого нового объекта. При вызове в качестве конструктора функция возвращает свой объект this по умолчанию, поэтому нет необходимости в отдельномreturn this;
операторе.Чтобы проверить, что A имеет свойство x :
Это необычное использование new, поскольку единственный способ ссылаться на конструктор - через A.constructor . Было бы гораздо более распространенным сделать:
Другим способом достижения аналогичного результата является использование выражения, вызываемого немедленно:
В этом случае
A
присваивается возвращаемое значение вызова функции с правой стороны. Здесь снова, так как это не установлено в вызове, оно будет ссылаться на глобальный объект иthis.x
будет эффективнымwindow.x
. Так как функция ничего не возвращает,A
будет иметь значениеundefined
.Эти различия между этими двумя подходами также проявляются, если вы сериализуете и десериализуете свои объекты Javascript в / из JSON. Методы, определенные в прототипе объекта, не сериализуются при сериализации объекта, что может быть удобно, когда, например, вы хотите сериализовать только части данных объекта, но не его методы:
Смежные вопросы :
Примечание: между этими двумя подходами не может быть значительной экономии памяти, однако использование прототипа для совместного использования методов и свойств, вероятно, будет использовать меньше памяти, чем каждый экземпляр, имеющий свою собственную копию.
JavaScript не является языком низкого уровня. Возможно, не очень полезно думать о прототипировании или других шаблонах наследования как о способе явного изменения способа выделения памяти.
источник
null
), но это очень отличается отprototype
свойства, которое относится к функциям и для которого устанавливается прототип всех экземпляров, когда они создаютсяnew
. Не могу поверить, что это действительно получило 87 голосов :-("The language is functional"
Вы уверены, что это то, что означает функционал?A
функцию, а другая половина о неясных и неортодоксальных способах выполнения. что-то простое.Как говорили другие версии первой версии, использование «this» приводит к тому, что каждый экземпляр класса A имеет свою собственную независимую копию метода функции «x». Принимая во внимание, что использование «прототипа» будет означать, что каждый экземпляр класса А будет использовать одну и ту же копию метода «х».
Вот некоторый код, чтобы показать эту тонкую разницу:
Как уже упоминали другие, есть разные причины, чтобы выбрать тот или иной метод. Мой образец просто предназначен для того, чтобы четко продемонстрировать разницу.
источник
this
объекта, который является владельцем метода. т.е. метод не имеет объекта, который является его владельцем. В этом случае естьthis
объект, как показано в классе A в примере.Возьмите эти 2 примера:
против
Большинство людей здесь (особенно ответы с самым высоким рейтингом) пытались объяснить, чем они отличаются, не объясняя ПОЧЕМУ. Я думаю, что это неправильно, и если вы сначала поймете основы, разница станет очевидной. Давайте сначала попробуем объяснить основы ...
а) Функция - это объект в JavaScript. КАЖДЫЙ объект в JavaScript получает внутреннее свойство (то есть, вы не можете получить к нему доступ, как и к другим свойствам, за исключением, может быть, в браузерах, таких как Chrome), которое часто называют
__proto__
(вы можете ввестиanyObject.__proto__
Chrome, чтобы увидеть, на что он ссылается. Это просто так. , свойство, ничего более. Свойство в JavaScript = переменная внутри объекта, ничего более. Что делают переменные? Они указывают на вещи.Так на что же
__proto__
указывает это свойство? Ну, обычно другой объект (мы объясним, почему позже). Единственный способ заставить JavaScript для__proto__
свойства НЕ указывать на другой объект - это использоватьvar newObj = Object.create(null)
. Даже если вы сделаете это,__proto__
свойство STILL существует как свойство объекта, просто оно не указывает на другой объект, оно указывает наnull
.Вот где большинство людей запутываются:
Когда вы создаете новую функцию в JavaScript (которая также является объектом, помните?), В момент ее определения JavaScript автоматически создает новое свойство для этой функции, которое вызывается
prototype
. Попробуй это:A.prototype
ПОЛНОСТЬЮ ОТЛИЧАЕТСЯ от__proto__
собственности. В нашем примере «A» теперь имеет ДВА свойства, называемые «prototype» и__proto__
. Это большая путаница для людей.prototype
и__proto__
свойства никак не связаны, это разные вещи, указывающие на отдельные значения.Вы можете задаться вопросом: почему JavaScript имеет
__proto__
свойство, созданное для каждого отдельного объекта? Ну, одним словом: делегирование . Когда вы вызываете свойство объекта, а у объекта его нет, JavaScript ищет объект, на который ссылается объект,__proto__
чтобы узнать, есть ли у него его. Если у него его нет, то он смотрит на__proto__
свойство этого объекта и так далее ... пока цепочка не закончится. Так называется прототип цепочки . Конечно, если JavaScript__proto__
не указывает на объект и вместо этого указывает наnull
неудачу, JavaScript это понимает и вернет вамundefined
свойство.Вы также можете задаться вопросом, почему JavaScript создает свойство, вызываемое
prototype
для функции, когда вы определяете функцию? Потому что он пытается обмануть вас, да обмануть вас, что он работает как языки на основе классов.Давайте продолжим с нашим примером и создадим «объект» из
A
:Что-то происходит на заднем плане, когда это случилось.
a1
обычная переменная, которой был присвоен новый пустой объект.Тот факт, что вы использовали оператор
new
перед вызовом функции,A()
сделал что-то ДОПОЛНИТЕЛЬНОЕ в фоновом режиме.new
Ключевое слово создается новый объект , который в настоящее время ссылкиa1
и этот объект пуст. Вот что происходит дополнительно:Мы говорили, что в каждом определении функции есть новое созданное свойство с именем
prototype
(к которому вы можете получить доступ, в отличие от__proto__
свойства)? Ну, это свойство сейчас используется.Итак, мы находимся в точке, где у нас есть свежеиспеченный пустой
a1
объект. Мы говорили, что все объекты в JavaScript имеют внутреннее__proto__
свойство, которое указывает на что-то (a1
также имеет), является ли оно нулевым или другим объектом. То , чтоnew
оператор делает то , что он устанавливает , что__proto__
свойство точки к функции вprototype
собственность. Прочитайте это снова. Это в основном это:Мы сказали, что
A.prototype
это не что иное, как пустой объект (если мы не изменим его на что-то еще до определенияa1
). Так что теперь, в основном,a1.__proto__
указывает на то же самое, на чтоA.prototype
указывает этот пустой объект. Они оба указывают на один и тот же объект, который был создан, когда произошла эта строка:Теперь, когда
var a1 = new A()
оператор обрабатывается , происходит еще одна вещь . В основномA()
выполняется, и если A что-то вроде этого:Все эти вещи внутри
function() { }
будут выполнены. Когда вы достигаетеthis.hey..
линии,this
меняется наa1
и вы получаете это:Я не буду освещать, почему
this
изменения,a1
но это отличный ответ, чтобы узнать больше.Итак, подведем итог: когда вы делаете,
var a1 = new A()
на заднем плане происходят 3 вещи:a1
.a1 = {}
a1.__proto__
свойство назначается так, чтобы оно указывало на то же, что и указательA.prototype
(другой пустой объект {})Функция
A()
выполняется сthis
установленным новым пустым объектом, созданным на шаге 1 (прочитайте ответ, на который я ссылался выше, чтобы узнать, почему онthis
меняетсяa1
)Теперь давайте попробуем создать еще один объект:
Шаги 1,2,3 повторится. Вы что-то замечаете? Ключевое слово - повторить. Шаг 1:
a2
будет новым пустым объектом, шаг 2: его__proto__
свойство будет указывать на то же, на чтоA.prototype
указывает и, самое главное, шаг 3: функцияA()
выполняется снова, а это значит, чтоa2
она получитhey
свойство, содержащее функцию.a1
иa2
имеют два названных свойства SEPARATE,hey
которые указывают на 2 отдельные функции! Теперь у нас есть дубликаты функций в одних и тех же двух разных объектах, которые делают одно и то же, упс ... Вы можете представить, как это повлияет на память, если у нас будет создано 1000 объектовnew A
, после того как все объявления функций занимают больше памяти, чем что-то вроде числа 2. Итак, как мы можем предотвратить это?Помните, почему
__proto__
свойство существует на каждом объекте? Таким образом, если вы извлекаетеyoMan
свойствоa1
(которое не существует), к его__proto__
свойству обращаются, и если оно является объектом (и в большинстве случаев так оно и есть), оно проверит, содержит ли оноyoMan
, а если нет, он будет обращаться к этому объекту и__proto__
т. д. Если это произойдет, он примет значение этого свойства и отобразит его вам.Поэтому кто-то решил использовать этот факт + тот факт, что при создании
a1
его__proto__
свойство указывает на тот же (пустой) объект, на которыйA.prototype
указывает и делает это:Круто! Теперь, когда вы создаете
a1
, он снова проходит все 3 шага, описанных выше, и на шаге 3 он ничего не делает, такfunction A()
как не имеет ничего для выполнения. И если мы сделаем:Он увидит, что
a1
он не содержит,hey
и проверит свой__proto__
объект свойства, чтобы увидеть, есть ли он, что имеет место.При таком подходе мы исключаем часть из шага 3, где функции дублируются при каждом создании нового объекта. Вместо того , чтобы
a1
иa2
наличие отдельногоhey
имущества, в настоящее время никто из них не имеет его. Который, я полагаю, ты уже сам понял. Это хорошо ... если вы понимаете,__proto__
иFunction.prototype
такие вопросы будут довольно очевидными.ПРИМЕЧАНИЕ. Некоторые люди склонны не вызывать внутреннее свойство Prototype, поскольку
__proto__
я использовал это имя в публикации, чтобы четко отличить его отFunctional.prototype
свойства как две разные вещи.источник
__proto__
и.prototype
это совершенно разные вещи.В большинстве случаев они по сути одинаковы, но вторая версия экономит память, поскольку для каждого объекта существует только один экземпляр функции вместо отдельной функции.
Причиной использования первой формы является доступ к "частным пользователям". Например:
Из-за правил области видимости javascript private_var доступен для функции, назначенной this.x, но не за пределами объекта.
источник
Первый пример изменяет интерфейс только для этого объекта. Второй пример изменяет интерфейс для всех объектов этого класса.
источник
x
доступной для всех объектов, прототипу которых назначен новый экземпляр A:function B () {}; B.prototype = new A(); var b = new B(); b.x() // Will call A.x if A is defined by first example;
Основная проблема с использованием
this
вместо этогоprototype
заключается в том, что при переопределении метода конструктор базового класса будет по-прежнему ссылаться на переопределенный метод. Учти это:против:
Если вы думаете, что это не проблема, то это зависит от того, можете ли вы жить без личных переменных, и достаточно ли у вас опыта, чтобы узнать утечку при ее появлении. Также неудобно помещать логику конструктора после определения метода.
против:
источник
Каждый объект связан с объектом-прототипом. При попытке получить доступ к несуществующему свойству JavaScript будет искать в этом объекте-прототипе это свойство и возвращать его, если оно существует.
prototype
Свойство функции конструктора относится к объекту прототипа всех экземпляров , созданных с этой функцией при использованииnew
.В первом примере вы добавляете свойство
x
к каждому экземпляру, созданному с помощьюA
функции.Во втором примере вы добавляете свойство к объекту-прототипу, на которое
A
указывают все экземпляры, созданные с помощью .В заключение, в первом примере копия функции присваивается каждому экземпляру . Во втором примере одна копия функции является общей для всех экземпляров .
источник
Какая разница? => Много.
Я думаю, что
this
версия используется для включения инкапсуляции, то есть сокрытия данных. Это помогает манипулировать закрытыми переменными.Давайте посмотрим на следующий пример:
Теперь
prototype
структура может быть применена следующим образом:Разные взрослые имеют разный возраст, но все взрослые получают одинаковые права.
Итак, мы добавляем его, используя прототип, а не этот.
Давайте посмотрим на реализацию сейчас.
Надеюсь это поможет.
источник
Прототип - это шаблон класса; что относится ко всем будущим экземплярам этого. В то время как это конкретный экземпляр объекта.
источник
Я знаю, что на это ответили до смерти, но я хотел бы показать реальный пример различий в скорости.
Здесь мы создаем 2 000 000 новых объектов с помощью
print
метода в Chrome. Мы храним каждый объект в массиве. Установкаprint
прототипа занимает около 1/2 времени.источник
Позвольте мне дать вам более полный ответ, который я узнал во время курса обучения JavaScript.
В большинстве ответов уже упоминалось о разнице, то есть при создании прототипа функция используется всеми (будущими) экземплярами. Принимая во внимание, что объявление функции в классе создаст копию для каждого экземпляра.
В общем, нет правильного или неправильного, это скорее вопрос вкуса или дизайнерского решения в зависимости от ваших требований. Прототип, однако, является техникой, которая используется для разработки объектно-ориентированного подхода, как я надеюсь, вы увидите в конце этого ответа.
Вы показали две закономерности в своем вопросе. Я попытаюсь объяснить еще два и попытаюсь объяснить различия, если это уместно. Не стесняйтесь редактировать / расширять. Во всех примерах речь идет об объекте автомобиля, который имеет местоположение и может двигаться.
Шаблон декоратора объектов
Не уверен, что эта модель все еще актуальна в наше время, но она существует. И это полезно знать об этом. Вы просто передаете объект и свойство в функцию декоратора. Декоратор возвращает объект со свойством и методом.
Функциональные классы
Функция в JavaScript является специализированным объектом. Помимо вызова, функция может хранить свойства, как и любой другой объект.
В этом случае
Car
это функция ( также думать объект ), которая может быть вызвана, как вы привыкли делать. У него есть свойствоmethods
(которое является объектом сmove
функцией). КогдаCar
вызывается, вызываетсяextend
функция, которая совершает какое-то волшебство и расширяетCar
функцию (думаю объект) с помощью методов, определенных внутриmethods
.Этот пример, хотя и отличается, ближе всего подходит к первому примеру в вопросе.
Занятия по прототипам
Первые два шаблона позволяют обсудить использование методов для определения общих методов или использование методов, которые встроены в теле конструктора. В обоих случаях каждый экземпляр имеет свою
move
функцию.Шаблон-прототип не подходит для такого же исследования, потому что разделение функций через делегирование прототипа является самой целью шаблона-прототипа. Как отмечали другие, ожидается, что у него будет больше памяти.
Однако есть один интересный момент: у каждого
prototype
объекта есть удобное свойствоconstructor
, которое указывает на функцию (думайте объект), к которой он присоединен.Относительно последних трех строк:
В этом примере
Car
ссылки наprototype
объект, который связывает черезconstructor
кCar
себе, то естьCar.prototype.constructor
этоCar
само по себе. Это позволяет выяснить, какая функция конструктора построила определенный объект.amy.constructor
поиск завершается неудачно и, таким образом, делегируетсяCar.prototype
, у которого есть свойство конструктор. И вотamy.constructor
этоCar
.Кроме того,
amy
являетсяinstanceof
Car
.instanceof
Оператор работает, видя , если объект - прототип правого операнда (Car
) можно найти в любом месте в прототипе левого операнда (amy
) цепи.Некоторые разработчики могут быть смущены в начале. Смотрите ниже пример:
В
instanceof
оператор возвращаетсяfalse
, потому чтоDog
«прототип сек не может быть найден где - нибудь вfido
» S цепи прототипов.fido
это простой объект, который создается с литералом объекта, то есть он просто делегируетObject.prototype
.Псевдоклассические паттерны
На самом деле это просто еще одна форма шаблона-прототипа в упрощенной форме, и она более привычна для тех, кто программирует на Java, например, так как она использует
new
конструктор.Он делает то же самое, что и в паттерне-прототипе, это просто синтаксический сахар поверх макета-прототипа.
Однако основное отличие состоит в том, что в механизмах JavaScript реализованы оптимизации, которые применяются только при использовании псевдоклассического шаблона. Подумайте о псевдоклассическом паттерне, возможно, о более быстрой версии прототипного паттерна; объектные отношения в обоих примерах одинаковы.
Наконец, не должно быть слишком сложно понять, как можно сделать объектно-ориентированное программирование. Есть два раздела.
Один раздел, который определяет общие свойства / методы в прототипе (цепочке).
И еще один раздел, где вы помещаете определения, которые отличают объекты друг от друга (
loc
переменные в примерах).Это то, что позволяет нам применять такие понятия, как суперкласс или подкласс в JavaScript.
Не стесняйтесь добавлять или редактировать. Как только я закончу, я могу сделать это вики-сообществом.
источник
Я считаю, что @Matthew Crumley прав. Они функционально , если не структурно, эквивалентны. Если вы используете Firebug для просмотра объектов, созданных с использованием
new
, вы увидите, что они одинаковы. Тем не менее, мое предпочтение будет следующим. Я предполагаю, что это больше похоже на то, к чему я привык в C # / Java. То есть, определить класс, определить поля, конструктор и методы.РЕДАКТИРОВАТЬ Не имелось в виду, что область действия переменной была закрытой, я просто пытался проиллюстрировать, как я определяю свои классы в javascript. Имя переменной было изменено, чтобы отразить это.
источник
initialize
иx methods do not refer to the
_instance_var` дляA
экземпляра, но для глобального. Используйте,this._instance_var
если вы намеревались использовать_instance_var
свойствоA
экземпляра.Как обсуждалось в других ответах, это действительно соображение производительности, потому что функция в прототипе совместно используется со всеми экземплярами, а не с функцией, создаваемой для каждого экземпляра.
Я собрал jsperf, чтобы показать это. Существует существенное различие во времени, которое требуется для создания экземпляра класса, хотя на самом деле это актуально, только если вы создаете много экземпляров.
http://jsperf.com/functions-in-constructor-vs-prototype
источник
Подумайте о статически типизированном языке, вещи
prototype
статичны, а вещиthis
связаны с экземплярами.источник