Front-end-Job-Interview-Questions
Ответы на вопросы на должность Frontend разработчика.
Project maintained by FedorovAlexander Hosted on GitHub Pages — Theme by mattgraham
В чём разница между «атрибутом» (attribute) и «свойством« (property)?
Атрибуты определены в разметке HTML, а свойства определены в DOM. Большинство стандартных HTML-атрибутов становятся свойствами соответствующих объектов. Но они не идентичны.
Атрибуты
- Всегда являются строками.
- Их имя нечувствительно к регистру.
- Видны в innerHTML.
Свойства
- Могут иметь любое значение.
- Названия свойств чувствительны к регистру.
- Работают за счёт того, что DOM-узлы являются объектами JS.
Атрибут и свойство в чем разница
По умолчанию атрибуты в классах являются общедоступными, а это значит, что из любого места программы мы можем получить атрибут объекта и изменить его. Например:
class Person: def __init__(self, name, age): self.name = name # устанавливаем имя self.age = age # устанавливаем возраст def print_person(self): print(f"Имя: \tВозраст: ") tom = Person("Tom", 39) tom.name = "Человек-паук" # изменяем атрибут name tom.age = -129 # изменяем атрибут age tom.print_person() # Имя: Человек-паук Возраст: -129
Но в данном случае мы можем, к примеру, присвоить возрасту или имени человека некорректное значение, например, указать отрицательный возраст. Подобное поведение нежелательно, поэтому встает вопрос о контроле за доступом к атрибутам объекта.
С данной проблемой тесно связано понятие инкапсуляции. Инкапсуляция является фундаментальной концепцией объектно-ориентированного программирования, которая предполагает скрытие функционала и предотвращение прямого доступа извне к нему.
Язык программирования Python позволяет определить приватные или закрытые атрибуты. Для этого имя атрибута должно начинаться с двойного подчеркивания — __name . Например, перепишем предыдущую программу, сделав оба атрибута — name и age приватными:
class Person: def __init__(self, name, age): self.__name = name # устанавливаем имя self.__age = age # устанавливаем возраст def print_person(self): print(f"Имя: \tВозраст: ") tom = Person("Tom", 39) tom.__name = "Человек-паук" # пытаемся изменить атрибут __name tom.__age = -129 # пытаемся изменить атрибут __ tom.print_person() # Имя: Tom Возраст: 39
В принципе мы также можем попытаться установить для атрибутов __name и __age новые значения:
tom.__name = "Человек-паук" # пытаемся изменить атрибут __name tom.__age = -129 # пытаемся изменить атрибут __
Но вывод метода print_person покажет, что атрибуты объекта не изменили свои значения:
tom.print_person() # Имя: Tom Возраст: 39
Как это работает? При объявлении атрибута, имя которого начинается с двух прочерков, например, __attribute , Python в реальности определяет атрибута, который называется по шаблону _ClassName__atribute . То есть в случае выше будут создаваться атрибуты _Person__name и _Person__age . Поэтому к такому атрибуту мы сможем обратиться только из того же класса. Но не сможем обратиться вне этого класса. Например, присвоение значения этому атрибуту ничего не даст:
tom.__age = 43
Потому что в данном случае просто определяется динамически новый атрибут __age, но это он не имеет ничего общего с атрибутом self.__age или точнее self._Person__age .
А попытка получить его значение приведет к ошибке выполнения (если ранее не была определена переменная __age):
print(tom.__age)
Тем не менее приватность атрибутов тут довольно относительна. Например, мы можем использовать полное имя атрибута:
class Person: def __init__(self, name, age): self.__name = name # устанавливаем имя self.__age = age # устанавливаем возраст def print_person(self): print(f"Имя: \tВозраст: ") tom = Person("Tom", 39) tom._Person__name = "Человек-паук" # изменяем атрибут __name tom.print_person() # Имя: Человек-паук Возраст: 39
Тем нее менее автор внешнего кода еще должен угадать, как называются атрибуты.
Методы доступа. Геттеры и сеттеры
Может возникнуть вопрос, как обращаться к подобным приватным атрибутам. Для этого обычно применяются специальные методы доступа. Геттер позволяет получить значение атрибута, а сеттер установить его. Так, изменим выше определенный класс, определив в нем методы доступа:
class Person: def __init__(self, name, age): self.__name = name # устанавливаем имя self.__age = age # устанавливаем возраст # сеттер для установки возраста def set_age(self, age): if 0 < age < 110: self.__age = age else: print("Недопустимый возраст") # геттер для получения возраста def get_age(self): return self.__age # геттер для получения имени def get_name(self): return self.__name def print_person(self): print(f"Имя: \tВозраст: ") tom = Person("Tom", 39) tom.print_person() # Имя: Tom Возраст: 39 tom.set_age(-3486) # Недопустимый возраст tom.set_age(25) tom.print_person() # Имя: Tom Возраст: 25
Для получения значения возраста применяется метод get_age:
def get_age(self): return self.__age
Для изменения возраста определен метод set_age:
def set_age(self, age): if 0 < age < 110: self.__age = age else: print("Недопустимый возраст")
Причем опосредование доступа к атрибутам через методы позволяет задать дополнительную логику. Так, в зависимости от переданного возраста мы можем решить, надо ли переустанавливать возраст, так как переданное значение может быть некорректным.
Также еобязательно создавать для каждого приватного атрибута подобную пару методов. Так, в примере выше имя человека мы можем установить только из конструктора. А для получение определен метод get_name.
Аннотации свойств
Выше мы рассмотрели, как создавать методы доступа. Но Python имеет также еще один - более элегантный способ - свойства . Этот способ предполагает использование аннотаций, которые предваряются символом @.
Для создания свойства-геттера над свойством ставится аннотация @property .
Для создания свойства-сеттера над свойством устанавливается аннотация имя_свойства_геттера.setter .
Перепишем класс Person с использованием аннотаций:
class Person: def __init__(self, name, age): self.__name = name # устанавливаем имя self.__age = age # устанавливаем возраст # свойство-геттер @property def age(self): return self.__age # свойство-сеттер @age.setter def age(self, age): if 0 < age < 110: self.__age = age else: print("Недопустимый возраст") @property def name(self): return self.__name def print_person(self): print(f"Имя: \tВозраст: ") tom = Person("Tom", 39) tom.print_person() # Имя: Tom Возраст: 39 tom.age = -3486 # Недопустимый возраст (Обращение к сеттеру) print(tom.age) # 39 (Обращение к геттеру) tom.age = 25 # (Обращение к сеттеру) tom.print_person() # Имя: Tom Возраст: 25
Во-первых, стоит обратить внимание, что свойство-сеттер определяется после свойства-геттера.
Во-вторых, и сеттер, и геттер называются одинаково - age. И поскольку геттер называется age, то над сеттером устанавливается аннотация @age.setter .
После этого, что к геттеру, что к сеттеру, мы обращаемся через выражение tom.age .
При этом можно определить только геттер, как в случае с свойством name - его нельзя изменить, а можно лишь получить значение.
JavaScript. Атрибуты и свойста элементов.
Пишу данную статью специально для тех, кто программирует на javascript. Хочу рассказать вам об одной простенькой ошибке, которая может здорово вынести мозг.
Как известно, все элементы DOM – объекты, и у них есть свойства. В тоже время всё, что есть на странице, – это элементы html, у которых есть атрибуты. Как же две эти сущности между собой соотносятся.
Допустим, у нас на странице есть div с определённым классом:
Очевидно, что здесь мы установили его атрибуту class значение bold.
Посмотрим, появится ли это в свойствах данного объекта. Действительно, у него есть свойство className со значением bold. Убедиться в этом можно, написав следующий код:
var elems = document.getElementsByClassName('bold'); var div = elems[0]; alert(div.className); // выведет bold
Интересно, а если мы изменим данное свойство, изменится ли атрибут? Проверим:
var elems = document.getElementsByClassName('bold'); var div = elems[0]; div.className = "small"; alert(div.className); // выведет small alert(div.getAttribute('class')); // выведет small
Как видим, атрибут и свойство изменились одновременно. Из-за этого сейчас мы может сделать вывод, что атрибуты и свойства – это одно и тоже, и изменяются они синхронно. Но на самом деле это не так. Синхронизация происходит только для стандартных атрибутов. Попробуем добавиться какой-либо свой атрибут и проверим, появится ли он в свойствах объекта:
var elems = document.getElementsByClassName('bold'); var div = elems[0]; div.setAttribute('myAttr', 100); alert(div.getAttribute('myAttr')); // выведет 100 alert(div.myAttr); // выведет undefined
Т.е. если мы устанавливаем какой-то собственный атрибут, то объекту такого свойства не добавляется. Теперь сделаем наоборот – установим свойство и проверим, появится ли атрибут:
var elems = document.getElementsByClassName('bold'); var div = elems[0]; div.myAttr = 100; alert(div.getAttribute('myAttr')); // выведет 100 alert(div.myAttr); // выведет 100
В этот раз всё нормально – установлены и свойство и атрибут. Вроде бы всё достаточно просто, где же мы рискуем сделать ошибку?
При написании кода на чистом javascript-е это очень маловероятно. Вряд ли кому-то из вас больше нравится писать div.setAttribute(‘myAttr’, 100); чем div.myAttr = 100; потому что вторая запись короче и понятнее. Но ведь все мы уже давно подсели на великолепную библиотеку jQuery, в котором есть очень удобная функция attr. Давайте ею воспользуемся:
$('.bold').attr('myAttr', '100');
А теперь поищем свойство myAttr у данного объекта:
var elems = document.getElementsByClassName('bold'); var div = elems[0]; alert(div.myAttr); // выведет undefined
Вот так! Функция attr установила лишь значение атрибута, не изменив при этом реальных свойств данного объекта. Над подобной ошибкой один из учеников провёл немалое количество времени, прежде чем выяснилось, что атрибуты и свойства – это не одно и тоже.
На самом деле многие не задумываются о различии свойств и атрибутов. Происходит это потому, что программист, начав изучать javascript, один раз разбирается с тем, как html парсится браузером в DOM, видит, что все стандартные атрибуты переходят в свойства, и решает, что эти две сущности ничем не отличаются. Но на деле оказывается, что это не так.
В идеале мы не должны придумывать для элементов собственные атрибуты, мы должны задавать свойства. Однако, кто же из нас теперь откажется от простой и удобной функции attr!? Да никто! Поэтому просто необходимо понимать эту разницу между свойства и атрибутами, чтобы задав элементу какой-нибудь атрибут, не искать данное значение в свойствах.
Понравился материал? Поделись с друзьями!
Различия между свойствами и атрибутами в HTML
Атрибуты — это предустановленные значения, указанные непосредственно в HTML-коде. К примеру, в type и value являются атрибутами. Свойства — это изменчивые поля DOM-объектов HTML-элементов, такие как input.value . Атрибуты определяют стартовые параметры, а свойства – текущее состояние. Поначалу свойства могут не совпадать с атрибутами, поскольку изменения свойства не отражаются на его HTML-атрибуте.
Скопировать код
Зеркальное отражение: свойства, которые отражают и не отражают атрибуты
В одной стороне похожи и такие свойства как атрибуты, но их применение различно. Например, вводимые данные пользователя изменяют свойство value текстового поля, при этом getAttribute('value') будет возвращать начальное значение до тех пор, пока его прямо не обновят.
Бывает и так, что свойства и атрибуты вообще не схожи между собой. Атрибуту class соответствует свойство className , так как class в JavaScript — зарезервированное слово. Это нюанс стоит запомнить при работе с HTML-элементами через JavaScript.
Влияние jQuery на отношения атрибутов и свойств
Библиотеки такие как jQuery, размывают грань между атрибутами и свойствами. Введение метода .prop() в jQuery, начиная с версии 1.6.1, в дополнение к .attr() , облегчило реализацию изменений, связанных с текущим состоянием элемента, например, с отмеченным checkbox'ом.
Отсылки из прошлого: defaultValue и defaultChecked
Свойства defaultValue и defaultChecked становятся настоящим спасением, когда нужно учесть начальное состояние. Вне зависимости от изменения свойств value или checked , эти свойства сохраняются. Они словно маяки среди блуждающего в мире изменений JavaScript.
Строгие стандарты или когда свойства препятствуют изменению атрибутов
Когда-нибудь пробовали изменить атрибут type у текстового поля? Это может удивить! DOM следит за соблюдением стандартов HTML и мониторит любые попытки изменений. Если изменения неправильные, они будут заблокированы, так как DOM в этом контексте выступает как непреклонный страж порядка.
Дальше базовых знаний: глубже в свойствах
Свойства могут получить больше информации, чем атрибуты. К примеру, атрибут style , задает стилевое оформление, однако свойство style предоставляет объект, который хранит информацию о динамичных инлайновых стилях элемента.
Помощник разработчика: HTML спецификация
Если приходится разбираться со всеми этими загадочными особенностями, имеется в распоряжении надёжный помощник – спецификация HTML. Знание принципов преобразования атрибутов в свойства сделает жизнь разработчика более комфортной и поможет избежать сюрпризов.