this , self и Me — ключевые слова, используемые в некоторых языках программирования для ссылки на объект, класс или другую сущность, частью которой является текущий выполняемый код. Таким образом, сущность, на которую ссылаются, зависит от контекста выполнения (например, какой объект имеет вызываемый метод). Разные языки программирования используют эти ключевые слова немного по-разному. В языках, где ключевое слово типа «this» является обязательным, оно является единственным способом доступа к данным и методам, хранящимся в текущем объекте. Если оно необязательно, эти ключевые слова могут устранить неоднозначность переменных и функций с одинаковыми именами.
Во многих объектно-ориентированных языках программирования , this
(также называемый self
или Me
) — это переменная, которая используется в методах экземпляра для ссылки на объект, с которым они работают. Первый объектно-ориентированный язык, SIMULA 67 , использовался this
для явной ссылки на локальный объект. [1] : 4.3.2.3 C++ и языки, которые являются его производными по стилю (такие как Java , C# , D , и PHP ) также обычно используют this
. Smalltalk и другие, такие как Object Pascal , Perl , Python , Ruby , Rust , Objective-C , DataFlex и Swift , используют . Visual Basicself
от Microsoft использует .Me
Концепция похожа во всех языках: this
обычно это неизменяемая ссылка или указатель , который ссылается на текущий объект; текущий объект часто является кодом, который действует как «родитель» или «вызывающий» для свойства , метода , подпрограммы или функции, содержащей this
ключевое слово. После того, как объект правильно сконструирован или создан, this
всегда является допустимой ссылкой. Некоторые языки требуют этого явно; другие используют лексическую область видимости , чтобы использовать ее неявно, чтобы сделать символы внутри своего класса видимыми. Или, в качестве альтернативы, текущий объект, на который ссылается, this
может быть независимым объектом кода, который вызвал функцию или метод, содержащий ключевое слово this
. Такое происходит, например, когда обработчик событий JavaScript, прикрепленный к тегу HTML на веб-странице, вызывает функцию, содержащую ключевое слово, this
хранящееся в глобальном пространстве за пределами объекта документа; в этом контексте this
будет ссылаться на элемент страницы внутри объекта документа, а не на окружающий объект окна. [2]
В некоторых языках, например, C++, Java и Raku this
или self
является ключевым словом , и переменная автоматически существует в методах экземпляра. В других, например, Python, Rust и Perl 5, первый параметр метода экземпляра является такой ссылкой. Он должен быть указан явно. В Python и Perl параметр не обязательно должен быть назван this
или self
; он может быть назван свободно программистом, как и любой другой параметр. Однако по неформальному соглашению первый параметр метода экземпляра в Perl или Python называется self
. Rust требует, чтобы объект self вызывался &self
или self
, в зависимости от того, заимствует ли вызванная функция инвокант или перемещает его, соответственно.
Статические методы в C++ или Java связаны не с экземплярами, а с классами, и поэтому не могут использовать this
, поскольку объекта нет. В других языках, таких как Ruby, Smalltalk, Objective-C или Swift, метод связан с объектом класса , который передается как this
, и они называются методами класса . Для методов класса Python использует cls
для доступа к объекту класса .
Когда лексическая область видимости используется для вывода this
, использование this
в коде, хотя и не является незаконным, может вызвать тревогу у программиста по обслуживанию, хотя this
в этом случае все еще существуют допустимые варианты использования , такие как ссылка на переменные экземпляра, скрытые локальными переменными с тем же именем, или если метод хочет вернуть ссылку на текущий объект, т. е this
. на себя.
В некоторых компиляторах (например, GCC ) указатели на методы экземпляра C++ могут быть напрямую преобразованы в указатель другого типа с явным this
параметром указателя. [3]
Семантика диспетчеризации this
, а именно то, что вызовы методов this
динамически диспетчеризуются, известна как открытая рекурсия и означает, что эти методы могут быть переопределены производными классами или объектами. Напротив, прямая именованная рекурсия или анонимная рекурсия функции использует закрытую рекурсию со статической диспетчеризацией. Например, в следующем коде Perl для факториала токен __SUB__
является ссылкой на текущую функцию:
использовать функцию ":5.16" ; sub { my $x = shift ; $x == 0 ? 1 : $x * __SUB__ -> ( $x - 1 ); }
Напротив, в C++ (используя явное указание this
для ясности, хотя это и не обязательно) this
привязка выполняется к самому объекту, но если метод класса был объявлен «виртуальным», т. е. полиморфным в базе, он разрешается посредством динамической диспетчеризации, так что производные классы могут переопределить его.
беззнаковый факториал целого числа ( беззнаковый факториал n ) { если ( n == 0 ) вернуть 1 ; иначе вернуть n * это -> факториал ( n - 1 ); }
Этот пример искусственный, поскольку это прямая рекурсия, поэтому переопределение factorial
метода переопределит эту функцию; более естественными примерами являются случаи, когда метод в производном классе вызывает тот же метод в базовом классе или в случаях взаимной рекурсии. [4] [5]
Проблема хрупкого базового класса была возложена на открытую рекурсию, с предположением, что вызов методов по this
умолчанию в закрытой рекурсии (статическая диспетчеризация) вместо открытой рекурсии (динамическая диспетчеризация), используя открытую рекурсию только тогда, когда это специально запрошено; внешние вызовы (не использующие this
) будут динамически диспетчеризироваться как обычно. [6] [7] Способ, которым это решается на практике в JDK, заключается в определенной дисциплине программирования; эта дисциплина была формализована C. Ruby и GT Leavens; она состоит из следующих правил: [8]
public
методы в this
.protected
или private
; если его необходимо также предоставить непосредственно пользователям, то public
метод-обертка вызывает внутренний метод.Ранние версии C++ позволяли this
изменять указатель; делая это, программист мог изменить объект, над которым работал метод. Эта возможность была в конечном итоге удалена, и теперь this
в C++ это r-value . [9]
Ранние версии C++ не включали ссылок, и было высказано предположение, что если бы они были в C++ с самого начала, this
то это была бы ссылка, а не указатель. [10]
C++ позволяет объектам уничтожать себя с помощью оператора исходного кода: delete this
.
Ключевое слово this
в C# работает так же, как и в Java, для ссылочных типов. Однако в типах значений C# имеет совершенно иную семантику , this
будучи похожим на обычную ссылку на изменяемую переменную, и может даже встречаться в левой части присваивания.
Одно из применений this
в C# — разрешить ссылку на переменную внешнего поля в методе, содержащем локальную переменную с тем же именем. В такой ситуации, например, оператор var n = localAndFieldname;
в методе назначит тип и значение локальной переменной localAndFieldname
, n
тогда как оператор var n = this.localAndFieldname;
назначит тип и значение переменной внешнего поля n
. [11]
В D this
в методе класса, структуры или объединения ссылается на неизменяемую ссылку экземпляра охватывающего агрегата. Классы являются ссылочными типами, а структуры и объединения являются типами значений. В первой версии D ключевое слово this
используется как указатель на экземпляр объекта, к которому привязан метод, тогда как в D2 оно имеет характер неявного refаргумента функции.
В языке программирования Dylan , который является объектно-ориентированным языком, поддерживающим мультиметоды и не имеющим концепции this
, отправка сообщения объекту все еще сохраняется в синтаксисе. Две формы ниже работают одинаково; различия — это просто синтаксический сахар .
объект.метод(параметр1, параметр2)
и
метод (объект, параметр1, параметр2)
В тексте класса текущий тип — это тип, полученный из текущего класса . В функциях (процедурах, командах и запросах) класса можно использовать ключевое слово Current
для ссылки на текущий класс и его функции. Использование ключевого слова Current
необязательно, так как ключевое слово Current
подразумевается при простом открытом обращении к имени функции текущего класса. Например: Можно иметь функцию `foo' в классе MY_CLASS и ссылаться на нее следующим образом:
сорт МОЙ_КЛАСС особенность -- Доступ foo : ЦЕЛОЕ ЧИСЛО my_function : ЦЕЛОЕ ЧИСЛО делать Результат := foo конец конец
[12]
В строке № 10 (выше) подразумевается ссылка на Current
вызов простого `foo'.
В строке № 10 (ниже) имеется явная ссылка на Current
вызов `Current.foo'.
сорт МОЙ_КЛАСС особенность -- Доступ foo : ЦЕЛОЕ ЧИСЛО my_function : ЦЕЛОЕ ЧИСЛО делать Результат := Текущий . foo конец конец
Оба подхода приемлемы для компилятора, но подразумеваемая версия (например, x := foo
) предпочтительнее, поскольку она менее многословна.
Как и в других языках, бывают случаи, когда использование ключевого слова Current
обязательно, например:
сорт МОЙ_КЛАСС особенность -- Доступ моя_команда -- Создать MY_OTHER_CLASS с `Current' местный х : МОЙ_ДРУГОЙ_КЛАСС делать создать x . make_with_something ( Текущий ) конец конец
В случае приведенного выше кода вызов make_with_something в строке № 11 передает текущий класс путем явной передачи ключевого слова Current
.
Ключевое слово this
— это ключевое слово языка Java , представляющее текущий экземпляр класса, в котором оно появляется. Оно используется для доступа к переменным и методам класса.
Поскольку все методы экземпляра в Java являются виртуальными, this
они никогда не могут быть равны null. [13]
В JavaScript, языке программирования или скриптов, широко используемом в веб-браузерах, this
— это важное ключевое слово, хотя его значение зависит от того, где оно используется.
this
относится к охватывающему объекту, которым в данном случае является охватывающее окно браузера, window
объект.this
на что ссылается ключевое слово, зависит от того, как вызывается функция. Когда такая функция вызывается напрямую (например, f(x)
), this
будет ссылаться на глобальное пространство, в котором определена функция, и в котором могут существовать другие глобальные функции и переменные (или в строгом режиме, это undefined
). Однако, если глобальная функция, содержащая this
, вызывается как часть обработчика событий элемента в объекте документа, this
будет ссылаться на вызывающий элемент HTML.new
ключевого слова (например, var c = new Thing()
), то внутри Thing this
ссылается на сам объект Thing.obj.f(x)
), this
будет ссылаться на объект, в котором содержится функция. [14] [15] Можно даже вручную указать this
при вызове функции, используя методы .call()
или .apply()
объекта функции. [16] Например, вызов метода obj.f(x)
также может быть записан как obj.f.call(obj, x)
.Чтобы обойти различное значение this
во вложенных функциях, таких как обработчики событий DOM, в JavaScript распространена идиома сохранения ссылки this
на вызывающий объект в переменной (обычно называемой that
или self
), а затем использования этой переменной для ссылки на вызывающий объект во вложенных функциях.
Например:
// В этом примере $ — это ссылка на библиотеку jQuery $ ( ".element" ) .hover ( function () { // Здесь и this, и that указывают на элемент под курсором мыши. var that = this ; $ ( this ) .find ( '.elements' ) .each ( function () { // Здесь this указывает на перебираемый элемент DOM. // Однако that по-прежнему указывает на элемент под курсором мыши. $ ( this ) .addClass ( "highlight" ); }); });
Примечательно, что JavaScript использует оба этих слова this
и связанное с ними ключевое слово self
[17] (в отличие от большинства других языков, которые, как правило, используют одно из них), self
ограничиваясь только веб-работниками. [18]
Наконец, в качестве надежного способа конкретной ссылки на глобальный объект (окно или эквивалент) в JavaScript используется globalThis
ключевое слово. [19]
В Lua self
создается как синтаксический сахар , когда функции определяются с помощью :
оператора. [20] При вызове метода с помощью :
индексируемый объект будет неявно указан в качестве первого аргумента вызываемой функции.
Например, следующие две функции эквивалентны:
локальный объект = {}function obj . foo ( arg1 , arg2 ) print ( arg1 , arg2 ) -- здесь нельзя использовать "self" endfunction obj : bar ( arg ) print ( self , arg ) -- "self" является неявным первым аргументом перед arg end-- Все функции можно вызывать двумя способами: с помощью "." или с помощью ":"obj : foo ( "Foo" ) -- эквивалентно obj.foo(obj, "Foo") obj . bar ( obj , "Bar" ) -- эквивалентно obj:bar("Bar")
Сам по себе Lua не является объектно-ориентированным, но в сочетании с другой функцией, называемой метатаблицами, использование self
позволяет программистам определять функции способом, напоминающим объектно-ориентированное программирование.
В PowerShell специальная автоматическая переменная $_
содержит текущий объект в объекте конвейера. Эту переменную можно использовать в командах, которые выполняют действие над каждым объектом или над выбранными объектами в конвейере. [21]
"один" , "два" , "три" | % { write $_ }
Также, начиная с PowerShell 5.0, который добавляет формальный синтаксис для определения классов и других пользовательских типов, [22] $this
переменная описывает текущий экземпляр объекта.
В Python нет ключевого слова для this
. Когда функция-член вызывается для объекта, она вызывает функцию-член с тем же именем для объекта класса объекта, при этом объект автоматически привязывается к первому аргументу функции. Таким образом, обязательный первый параметр методов экземпляра служит this
; этот параметр традиционно называется self
, но может быть назван как угодно.
В методах класса (созданных с помощью classmethod
декоратора) первый аргумент ссылается на сам объект класса и обычно называется cls
; они в основном используются для наследуемых конструкторов, [23] где использование класса в качестве параметра позволяет создавать подклассы конструктора. В статических методах (созданных с помощью staticmethod
декоратора) специального первого аргумента не существует.
В Rust типы объявляются отдельно от функций, связанных с ними. Функции, разработанные как аналоги методов экземпляров в более традиционных объектно-ориентированных языках, должны явно принимать self
в качестве своего первого параметра. Затем эти функции можно вызывать с помощью instance.method()
синтаксического сахара. Например:
структура Foo { bar : i32 , } impl Foo { fn new () -> Foo { Foo { bar : 0 , } } fn refer ( & self ) { println! ( " { } " , self.bar ) ; } fn mutate ( & mut self , baz : i32 ) { self.bar = baz ; } fn consumer ( self ) { self.refer ( ) ; } }
Это определяет тип, Foo
, который имеет четыре ассоциированные функции. Первая, Foo::new()
, не является функцией экземпляра и должна быть указана с префиксом типа. Остальные три принимают self
параметр различными способами и могут быть вызваны для Foo
экземпляра с использованием синтаксиса точечной нотации sugar, что эквивалентно вызову имени функции с квалифицированным типом с явным self
первым параметром.
let mut foo = Foo :: new (); // должна вызываться как функция с указанным типом foo . refer (); // выводит "0". Foo::refer() имеет доступ только для чтения к экземпляру foo foo . mutate ( 5 ) ; // изменяет foo на месте, разрешено спецификацией &mut, необходимо объявить foo mut foo . consumer (); // выводит "5" и уничтожает foo, так как Foo::consume() полностью владеет self // эквивалентно foo.refer() Foo :: refer ( foo ); // ошибка компиляции: foo находится вне области видимости
Язык Self получил свое название из-за использования слова «self».
Self
строго используется внутри методов класса. Другой способ ссылаться на Self
— использовать ::
.