this
this
(иначе говоря, «контекст») - это специальное ключевое слово внутри каждой функции, и его значение зависит только от , как была вызвана функция, а не как / когда / где она была определена. Лексические области не затрагиваются, как и другие переменные. Вот несколько примеров:
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
Чтобы узнать больше о this
, просмотрите документацию MDN .
this
this
Фактически вы не хотите иметь доступ к this
в частности, но объект, на который он ссылается на . Вот почему простое решение - просто создать новую переменную, которая также относится к этому объекту. Переменная может иметь любое имя, но общие - self
и that
.
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
Поскольку self
является нормальной переменной, она подчиняется лексическим правилам области и доступна внутри обратного вызова. Это также имеет то преимущество, что вы можете получить доступ к значению this
самого обратного вызова.
this
обратного вызова - часть 1 Возможно, у вас есть не контролируйте значение this
, потому что его значение устанавливается автоматически, но на самом деле это не так.
Каждая функция имеет метод .bind
[docs] , который возвращает новую функцию с this
, привязанную к значению. Функция имеет то же поведение, что и тот, который вы назвали .bind
, только то, что this
было установлено вами. Независимо от того, как и когда эта функция вызывается, this
всегда будет ссылаться на переданное значение.
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
В этом случае мы привязываем обратный вызов this
к значению MyConstructor
's this
.
Примечание. При связывании контекста для jQuery вместо этого используйте jQuery.proxy
[docs] . Причина этого заключается в том, что вам не нужно сохранять ссылку на функцию при отмене обратного вызова события. jQuery обрабатывает это внутренне.
В ECMAScript 6 представлены функции стрелок , которые можно рассматривать как лямбда-функции. У них нет собственной привязки this
. Вместо этого this
просматривается в области видимости как обычная переменная. Это означает, что вам не нужно называть .bind
. Это не единственное особое поведение, которое у них есть. Дополнительную информацию см. В документации MDN.
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
this
обратного вызова - часть 2 Некоторые функции / методы, которые принимают обратные вызовы, также принимают значение, к которому должен обращаться обратный вызов this
. Это в основном то же самое, что и привязывать его самостоятельно, но функция / метод делает это за вас. Array#map
[docs] - такой метод. Его подпись такова:
array.map(callback[, thisArg])
Первый аргумент - это обратный вызов, а второй аргумент - значение this
. Вот надуманный пример:
var arr = [1, 2, 3];
var obj = {multiplier: 42};
var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
Примечание. Можно ли передать значение для this
, как правило, упоминается в документации этой функции / метода. Например, метод $.ajax
jQuery [docs] описывает параметр, называемый context
:
Этот объект станет контекстом всех обратных вызовов, связанных с Ajax.
blockquote>Общая проблема: использование объектных методов в качестве обработчиков обратных вызовов / событий
Еще одно распространенное проявление этой проблемы - когда объектный метод используется как обработчик обратного вызова / события , Функции являются первоклассными гражданами в JavaScript, а термин «метод» - просто разговорный термин для функции, которая является значением свойства объекта. Но эта функция не имеет конкретной ссылки на ее «содержащий» объект.
Рассмотрим следующий пример:
function Foo() { this.data = 42, document.body.onclick = this.method; } Foo.prototype.method = function() { console.log(this.data); };
Функция
this.method
назначается как обработчик события click , но если щелкнутьdocument.body
, зарегистрированное значение будетundefined
, потому что внутри обработчика событияthis
ссылается наdocument.body
, а не на экземплярFoo
. Как уже упоминалось в начале, то, что относится к [49], зависит от того, как называется функция, а не от того, как она определена. Если код выглядит следующим образом, может быть более очевидно, что функция не имеет неявной ссылки на объект:function method() { console.log(this.data); } function Foo() { this.data = 42, document.body.onclick = this.method; } Foo.prototype.method = method;
Решение такое же, как указано выше: если доступно, используйте
.bind
явно привязатьthis
к определенному значениюdocument.body.onclick = this.method.bind(this);
или явно вызвать функцию как «метод» объекта, используя анонимную функцию в качестве обработчика обратного вызова / события и назначить object (
this
) к другой переменной:var self = this; document.body.onclick = function() { self.method(); };
или использовать функцию стрелки:
document.body.onclick = () => this.method();
Вы должны использовать шаблон ShouldSerialize*
:
public class Book
{
[XmlAttribute] public string Title {get;set;}
public bool ShouldSerializeTitle() {
return !string.IsNullOrEmpty(Title);
}
[XmlAttribute] public string Description {get;set;}
public bool ShouldSerializeDescription() {
return !string.IsNullOrEmpty(Description );
}
[XmlAttribute] public string Author {get;set;}
public bool ShouldSerializeAuthor() {
return !string.IsNullOrEmpty(Author);
}
[XmlAttribute] public string Publisher {get;set;}
public bool ShouldSerializePublisher() {
return !string.IsNullOrEmpty(Publisher);
}
}
public class Books
{
[XmlElement("Book")]
public List<Book> BookList;
}
public class Book
{
[XmlAttribute]
public string Title;
[XmlAttribute]
public string Description;
[XmlAttribute]
public string Author;
[XmlAttribute]
public string Publisher;
}
class Program
{
static void Main()
{
var books = new Books
{
BookList = new List<Book>(new[]
{
new Book
{
Title = "t1",
Description = "d1"
},
new Book
{
Author = "a2",
Description = "d2"
},
new Book
{
Author = "a3",
Title = "t3",
Publisher = "p3"
},
})
};
var serializer = new XmlSerializer(books.GetType());
serializer.Serialize(Console.Out, books);
}
}
И если вы хотите удалить пространство имен из корневого узла:
var namespaces = new XmlSerializerNamespaces();
namespaces.Add(string.Empty, string.Empty);
serializer.Serialize(Console.Out, books, namespaces);
Также я бы рекомендовал вам использовать свойства вместо полей / g1] в ваших классах моделей для лучшего инкапсуляции:
public class Books
{
[XmlElement("Book")]
public List<Book> BookList { get; set; }
}
null
по умолчанию для ссылочных типов и значением по умолчанию для типов значений.
– Darin Dimitrov
4 November 2010 в 13:27
Альтернатива:
DefaultValueAttribute
ContentPropertyAttribute
attribute В итоге вы получите что-то вроде этого:
[ContentProperty("Books")]
public class Library {
private readonly List<Book> m_books = new List<Book>();
public List<Book> Books { get { return m_books; } }
}
public class Book
{
[DefaultValue(string.Empty)]
public string Title { get; set; }
[DefaultValue(string.Empty)]
public string Description { get; set; }
[DefaultValue(string.Empty)]
public string Author { get; set; }
}