Объекты
Содержание:
- Вызов родительских методов
- Сравнение с null и undefined
- Методы toString/valueOf
- Ошибки доступа к свойствам
- Резервирование слов
- Продвинутые методы
- Array.isArray
- Примеры методов
- Object.create()
- Внутренняя реализация: Ссылочный тип
- Целочисленные свойства
- Object.prototype
- Сериализация объектов
- Координаты мыши: clientX(Y)/pageX(Y)
- Немного о «length»
- Javascript прототипы (Prototype) встроенных объектов
- Квадратные скобки
- Взаимосвязанные объекты
Вызов родительских методов
В механизме наследования, разобранном выше, есть одно белое пятно. Это — конструктор.
Хотелось бы, чтобы конструкторы всех родителей вызывались по порядку до конструктора самого объекта.
С наследованием через — это очень просто.
Вызов конструктора родителя с теми же аргументами, что были переданы осуществляется так:
function Rabbit(..) { ... Rabbit.superclass.constructor.apply(this, arguments) ... }
Конечно же, аргументы можно поменять, благо apply дает возможность вызвать функцию с любыми параметрами вместо в примере.
Аналогично можно вызвать и любой другой метод родительского класса:
Rabbit.superclass.run.apply(this, ...)
В этих примерах везде в явном виде указано имя класса хотя можно бы попробовать указать , который должен указывать на , т.к объект принадлежит этому классу.
Если так поступить, то будет ошибка при цепочке наследования классов из 3 элементов типа -> -> .
Проиллюстрируем ее на примере:
function foo() {} foo.prototype.identify = function() { return "I'm a foo"; } function bar() {} extend(bar, foo) bar.prototype.identify = function() { return "I'm a bar and " + this.constructor.superclass.identify.apply(this, arguments); } function zot() {} extend(zot, bar) zot.prototype.identify = function() { return "I'm a zot and " + this.constructor.superclass.identify.apply(this, arguments); } f = new foo(); alert(f.identify()); // "I'm a foo" b = new bar(); alert(b.identify()); // "I'm a bar and I'm a foo" z = new zot(); alert(z.identify()); // stack overflow
Последний вызов приведет к ошибке «too much recursion» из-за того, что , к которому идет обращение в функции обращается к дочернему классу . В результате вызывает сама себя в бесконечной рекурсии.
Правильный способ заключается в явном обозначении класса, т.е …
Оператор instanceOf проверяет принадлежность объекта классу, проходя по цепочке его прототипов, и используя для сравнения свойство prototype.
Логику его работы можно описать так:
function instanceOf(object, constructor) { var o=object while (o.__proto__ != null) { if (o.__proto__ === constructor.prototype) return true o = o.__proto__ } return false }
Поэтому при правильной структуре прототипов он всегда корректно работает.
У этого оператора есть неприятная особенность при использовании нескольких окон: в разных окнах объекты классов (окружение) разное, поэтому массив из одного окна(фрейма) не будет опознан как Array в другом фрейме.
Впрочем, такая ситуация возникает довольно редко.
Сравнение с null и undefined
Поведение и при сравнении с другими значениями — особое:
- При строгом равенстве
-
Эти значения различны, так как различны их типы.
- При нестрогом равенстве
-
Эти значения равны друг другу и не равны никаким другим значениям. Это специальное правило языка.
- При использовании математических операторов и других операторов сравнения
-
Значения преобразуются к числам: становится , а – .
Посмотрим, какие забавные вещи случаются, когда мы применяем эти правила
И, что более важно, как избежать ошибок при их использовании
Сравним с нулём:
С точки зрения математики это странно. Результат последнего сравнения говорит о том, что » больше или равно нулю», тогда результат одного из сравнений выше должен быть , но они оба ложны.
Причина в том, что нестрогое равенство и сравнения работают по-разному. Сравнения преобразуют в число, рассматривая его как . Поэтому выражение (3) истинно, а ложно.
С другой стороны, для нестрогого равенства значений и действует особое правило: эти значения ни к чему не приводятся, они равны друг другу и не равны ничему другому. Поэтому (2) ложно.
Значение несравнимо с другими значениями:
Почему же сравнение с нулём всегда ложно?
На это есть следующие причины:
- Сравнения и возвращают , потому что преобразуется в , а – это специальное числовое значение, которое возвращает при любых сравнениях.
- Нестрогое равенство возвращает , потому что равно только , и ничему больше.
Зачем мы рассмотрели все эти примеры? Должны ли мы постоянно помнить обо всех этих особенностях? Не обязательно. Со временем все они станут вам знакомы, но можно избежать проблем, если следовать надёжным правилам:
Относитесь очень осторожно к любому сравнению с , кроме случаев строгого равенства .
Не используйте сравнения с переменными, которые могут принимать значения , разве что вы полностью уверены в том, что делаете. Если переменная может принимать эти значения, то добавьте для них отдельные проверки.
Методы toString/valueOf
Методы и берут своё начало с древних времён. Они не символы, так как в то время символов ещё не существовало, а просто обычные методы объектов со строковыми именами. Они предоставляют «устаревший» способ реализации преобразований объектов.
Если нет метода , движок JavaScript пытается найти эти методы и вызвать их следующим образом:
- для хинта со значением «string».
- – в ином случае.
Для примера, используем их в реализации всё того же объекта . Воспроизведём его поведение комбинацией методов и :
Как видим, получилось то же поведение, что и в предыдущем примере с .
Довольно часто мы хотим описать одно «универсальное» преобразование объекта к примитиву для всех ситуаций. Для этого достаточно создать один :
В отсутствие и , обработает все случаи преобразований к примитивам.
Ошибки доступа к свойствам
Выражения обращения к свойствам не всегда возвращают или изменяют значение свойства. В этом разделе описываются ситуации, когда операции чтения или записи свойства терпят неудачу.
Попытка обращения к несуществующему свойству не считается ошибкой. Если свойство x не будет найдено среди собственных или унаследованных свойств объекта obj, выражение обращения к свойству obj.x вернет значение undefined.
Однако попытка обратиться к свойству несуществующего объекта считается ошибкой. Значения null и undefined не имеют свойств, и попытки обратиться к свойствам этих значений считаются ошибкой:
Если нет уверенности, что user и user.password являются объектами (или ведут себя подобно объектам), нельзя использовать выражение user.password.length, так как оно может возбудить исключение. Ниже демонстрируются два способа защиты против исключений подобного рода:
Попытки установить значение свойства для других значений не всегда оканчиваются успехом: некоторые свойства доступны только для чтения и не позволяют изменять их значения. Кроме того, некоторые объекты не позволяют добавлять в них новые свойства. Однако самое интересное, что подобные неудачи, как правило, не приводят к возбуждению исключения:
Этот исторически сложившийся недостаток JavaScript исправлен в строгом режиме, определяемом стандартом ECMAScript 5. Все неудачные попытки изменить значение свойства в строгом режиме приводят к исключению TypeError.
Правила, позволяющие определить, когда попытка выполнить операцию присваивания завершится успехом, а когда неудачей, просты и понятны, но их сложно выразить в достаточно краткой форме. Попытка присвоить значение свойству p объекта obj потерпит неудачу в следующих случаях:
Объект obj имеет собственное свойство p, доступное только для чтения: нельзя изменить значение свойства, доступного только для чтения
(Обратите, однако, внимание на метод defineProperty(), который представляет собой исключение, позволяющее изменять значения настраиваемых свойств, доступных только для чтения.)
Объект obj имеет унаследованное свойство p, доступное только для чтения: унаследованные свойства, доступные только для чтения, невозможно переопределить собственными свойствами с теми же именами.
Объект obj не имеет собственного свойства p; объект obj не наследует свойство p с методами доступа и атрибут extensible объекта obj имеет значение false. Если свойство p отсутствует в объекте obj и для него не определен метод записи, то операция присваивания попытается добавить свойство p в объект obj
Но поскольку объект obj не допускает возможность расширения, то попытка добавить в него новое свойство потерпит неудачу.
Резервирование слов
Переменная не может иметь имя, равное одному из зарезервированных слов, таких как «за», «пусть», «возвращать» и т. д. Но при сортировке объектов JavaScript нет такого ограничения.
В принципе, любое имя разрешено, но есть специальное: оно «__proto__» получает специальное обращение по историческим причинам. Например, нельзя установить его для значения, отличного от объекта:
let obj = {};
obj.__proto__ = 5;
alert(obj.__proto__); // , didn’t work as intended
Как видно из кода, назначение примитива 5 игнорируется. Это может стать источником ошибок и даже уязвимостей, если оператор намерен хранить произвольные пары ключ-значение в объекте и разрешать посетителю указывать ключи. В этом случае посетитель может выбрать «proto» в качестве ключа и добавить в объект JavaScript. Существует способ сделать объекты обработанными __proto__ как регулярным свойством. Существует также другая карта структуры данных, которые поддерживают произвольные ключи.
Продвинутые методы
Если программист зацикливается над объектом и стремится получить все свойства в том же порядке, в каком они были добавлены, он может полагаться на «упорядочение по-особому», когда целочисленные свойства сортируются, а другие формируются в порядке создания JavaScript-объекта.
Продвинутые методы объекта имеют дело с концепциями, которые редко используются в JavaScripting. Это связано с тем, что в обычных сценариях эти мощные функции не нужны. Некоторые из этих методов могут не работать в старых браузерах, таких как ранние выпуски Netscape 4.
Использование прототипа могло быть применено для создания JavaScript-объектов и всех методов mycircle, а не только новых. Это дает смешанную нагрузку на производительность. Они не должны хранить отдельные копии методов для каждого экземпляра объекта, поэтому для работы может потребоваться меньше памяти, но для их поиска браузер должен искать текущие и родительские области. Это может привести к предельной задержке. Как правило, пользователь должен использовать то, что подходит для кода, а не основывать это решение на производительности, если только он не имеет дело с очень определенной контролируемой средой.
Array.isArray
Массивы не
образуют отдельный тип языка. Они основаны на объектах. Поэтому typeof не может
отличить простой объект от массива:
console.log(typeof {}); // object console.log (typeof ); // тоже object
Но массивы
используются настолько часто, что для этого придумали специальный метод: Array.isArray(value). Он возвращает
true, если value массив, и false, если нет.
console.log(Array.isArray({})); // false console.log(Array.isArray()); // true
Подведем итоги
по рассмотренным методам массивов. У нас получился следующий список:
Для |
|
push(…items) |
добавляет элементы в конец |
pop() |
извлекает элемент с конца |
shift() |
извлекает элемент с начала |
unshift(…items) |
добавляет элементы в начало |
splice(pos, deleteCount, …items) |
начиная с индекса pos, удаляет |
slice(start, end) |
создаёт новый массив, копируя в него |
concat(…items) |
возвращает новый массив: копирует все |
Для поиска |
|
indexOf/lastIndexOf(item, pos) |
ищет item, начиная с позиции pos, и |
includes(value) |
возвращает true, если в массиве |
find/filter(func) |
фильтрует элементы через функцию и |
findIndex(func) |
похож на find, но возвращает индекс |
Для перебора |
|
forEach(func) |
вызывает func для каждого элемента. |
Для |
|
map(func) |
создаёт новый массив из результатов |
sort(func) |
сортирует массив «на месте», а потом |
reverse() |
«на месте» меняет порядок следования |
split/join |
преобразует строку в массив и обратно |
reduce(func, initial) |
вычисляет одно значение на основе |
Видео по теме
JavaScipt #1: что это такое, с чего начать, как внедрять и запускать
JavaScipt #2: способы объявления переменных и констант в стандарте ES6+
JavaScript #3: примитивные типы number, string, Infinity, NaN, boolean, null, undefined, Symbol
JavaScript #4: приведение типов, оператор присваивания, функции alert, prompt, confirm
JavaScript #5: арифметические операции: +, -, *, /, **, %, ++, —
JavaScript #6: условные операторы if и switch, сравнение строк, строгое сравнение
JavaScript #7: операторы циклов for, while, do while, операторы break и continue
JavaScript #8: объявление функций по Function Declaration, аргументы по умолчанию
JavaScript #9: функции по Function Expression, анонимные функции, callback-функции
JavaScript #10: анонимные и стрелочные функции, функциональное выражение
JavaScript #11: объекты, цикл for in
JavaScript #12: методы объектов, ключевое слово this
JavaScript #13: клонирование объектов, функции конструкторы
JavaScript #14: массивы (array), методы push, pop, shift, unshift, многомерные массивы
JavaScript #15: методы массивов: splice, slice, indexOf, find, filter, forEach, sort, split, join
JavaScript #16: числовые методы toString, floor, ceil, round, random, parseInt и другие
JavaScript #17: методы строк — length, toLowerCase, indexOf, includes, startsWith, slice, substring
JavaScript #18: коллекции Map и Set
JavaScript #19: деструктурирующее присваивание
JavaScript #20: рекурсивные функции, остаточные аргументы, оператор расширения
JavaScript #21: замыкания, лексическое окружение, вложенные функции
JavaScript #22: свойства name, length и методы call, apply, bind функций
JavaScript #23: создание функций (new Function), функции setTimeout, setInterval и clearInterval
Примеры методов
Для начала давайте научим нашего пользователя здороваться:
Здесь мы просто использовали Function Expression (функциональное выражение), чтобы создать функцию для приветствия, и присвоили её свойству нашего объекта.
Затем мы вызвали её. Теперь пользователь может говорить!
Функцию, которая является свойством объекта, называют методом этого объекта.
Итак, мы получили метод объекта .
Конечно, мы могли бы заранее объявить функцию и использовать её в качестве метода, примерно так:
Объектно-ориентированное программирование
Когда мы пишем наш код, используя объекты для представления сущностей реального мира, – это называется объектно-ориентированное программирование или сокращённо: «ООП».
ООП является большой предметной областью и интересной наукой само по себе. Как выбрать правильные сущности? Как организовать взаимодействие между ними? Это – создание архитектуры, и есть хорошие книги по этой теме, такие как «Приёмы объектно-ориентированного проектирования. Паттерны проектирования» авторов Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес или «Объектно-ориентированный анализ и проектирование с примерами приложений» Гради Буча, а также ещё множество других книг.
Существует более короткий синтаксис для методов в литерале объекта:
Как было показано, мы можем пропустить ключевое слово и просто написать .
Нужно отметить, что эти две записи не полностью эквивалентны
Есть тонкие различия, связанные с наследованием объектов (что будет рассмотрено позже), но на данном этапе изучения это неважно. В большинстве случаев сокращённый синтаксис предпочтителен
Object.create()
Стандарт ECMAScript 5 определяет метод Object.create(), который создает новый объект и использует свой первый аргумент в качестве прототипа этого объекта. Дополнительно Object.create() может принимать второй необязательный аргумент , описывающий свойства нового объекта.
Синтаксис
Чтобы создать объект, не имеющий прототипа, можно передать в качестве первого аргумента значение , но в этом случае вновь созданный объект не унаследует никаких-либо свойств, ни базовых методов, таких как (а это означает, что этот объект нельзя будет использовать в выражениях с оператором ):
Выполнить код »
Скрыть результаты
Если в коде потребуется создать обычный пустой объект, который, например, возвращается литералом или выражением , передайте в первом аргументе :
Выполнить код »
Скрыть результаты
Чтобы создать объект с прототипом необходимо в качестве первого аргумента передать прототип объекта:
Выполнить код »
Скрыть результаты
В этом случае мы сначала определяем объект-прототип , а затем используем для создания нового объекта, который наследуется . Здесь мы добавили свойства и после создания объекта. Но, что если нам нужно, чтобы мы могли добавлять эти свойства сразу при создании объекта? Для этого мы будем использовать второй аргумент метода .
Если указан второй аргумент метода и он не равен , то он должен быть объектом. Требуется, чтобы этот объект имел собственные перечисляемые свойства, то есть такие, которые определены на самом объекте, а не унаследованы по цепочке прототипов. Эти свойства указывают дескрипторы свойств, добавляемых в новый объект. Имена добавляемых свойств совпадают с именами свойств в этом объекте.
Выполнить код »
Скрыть результаты
Внутренняя реализация: Ссылочный тип
Продвинутая возможность языка
Этот раздел объясняет сложную тему, чтобы лучше понимать некоторые запутанные случаи.
Если вы хотите продвигаться быстрее, его можно пропустить или отложить.
Некоторые хитрые способы вызова метода приводят к потере значения , например:
В последней строчке кода используется условный оператор , который определяет, какой будет вызван метод ( или ) в зависимости от выполнения условия. В данном случае будет выбран .
Затем метод тут же вызывается с помощью скобок . Но вызов не работает как положено!
Вы можете видеть, что при вызове будет ошибка, потому что значением внутри функции становится (полагаем, что у нас строгий режим).
Так работает (доступ к методу объекта через точку):
Так уже не работает (вызываемый метод вычисляется):
Почему? Если мы хотим понять, почему так происходит, давайте разберёмся (заглянем под капот), как работает вызов методов ().
Присмотревшись поближе, в выражении можно заметить две операции:
- Сначала оператор точка возвращает свойство объекта – его метод ().
- Затем скобки вызывают этот метод (исполняется код метода).
Итак, каким же образом информация о передаётся из первой части во вторую?
Если мы поместим эти операции в отдельные строки, то значение , естественно, будет потеряно:
Здесь сохраняет функцию в переменной, и далее в последней строке она вызывается полностью сама по себе, без объекта, так что нет .
Для работы вызовов типа , JavaScript использует трюк – точка возвращает не саму функцию, а специальное значение «ссылочного типа», называемого .
Этот ссылочный тип (Reference Type) является внутренним типом. Мы не можем явно использовать его, но он используется внутри языка.
Значение ссылочного типа – это «триплет»: комбинация из трёх значений , где:
- – это объект.
- – это имя свойства объекта.
- – это режим исполнения. Является true, если действует строгий режим ().
Результатом доступа к свойству является не функция, а значение ссылочного типа. Для в строгом режиме оно будет таким:
Когда скобки применяются к значению ссылочного типа (происходит вызов), то они получают полную информацию об объекте и его методе, и могут поставить правильный ( в данном случае, по ).
Ссылочный тип – исключительно внутренний, промежуточный, используемый, чтобы передать информацию от точки до вызывающих скобок .
При любой другой операции, например, присваивании , ссылочный тип заменяется на собственно значение (функцию), и дальше работа уже идёт только с ней. Поэтому дальнейший вызов происходит уже без .
Таким образом, значение передаётся правильно, только если функция вызывается напрямую с использованием синтаксиса точки или квадратных скобок (они делают то же самое). Позднее в этом учебнике мы изучим различные варианты решения проблемы потери значения . Например, такие как .
Целочисленные свойства
Термин «целочисленное свойство» здесь означает строку, которая может быть преобразована из целого без изменения. Итак, например, «49» — это целочисленное имя свойства, потому что когда оно преобразуется в целое число и обратно, оно все то же. Но «+49» и «1.2» не являются таковыми. С другой стороны, если ключи не целочисленные, то они перечисляются в порядке создания. Пример ниже.
Чтобы исправить проблему с помощью телефонных кодов, можно «обмануть», сделав коды нецелыми. Добавление «+» (знака плюс) перед каждым кодом достаточно. Теперь он будет работать по назначению.
В приведенном выше примере показано, что существует только один объект и admin, чтобы войти в него. Затем, если позже будет использовать другой ключ (user), пользователь обнаружит изменения.
Операторы равенства == и строгого равенства === для объектов работают одинаково. Два объекта равны, только если они являются одним и тем же объектом. Для сравнений, подобных obj1 > obj2 или для сравнения с примитивом obj == 5, объекты преобразуются в примитивы. Честно говоря, такие сравнения необходимы очень редко и обычно являются результатом ошибки кодирования.
Object.prototype
Давайте выведем пустой объект:
Где код, который генерирует строку ? Это встроенный метод , но где он? ведь пуст!
…Но краткая нотация – это то же самое, что и , где – встроенная функция-конструктор для объектов с собственным свойством , которое ссылается на огромный объект с методом и другими.
Вот что происходит:
Когда вызывается (или создаётся объект с помощью литерала ), свойство этого объекта устанавливается на по правилам, которые мы обсуждали в предыдущей главе:
Таким образом, когда вызывается , метод берётся из .
Мы можем проверить это так:
Обратите внимание, что по цепочке прототипов выше больше нет свойства :
Сериализация объектов
Сериализация объектов — это процесс преобразования объектов в строковую форму представления, которая позднее может использоваться для их восстановления. Для сериализации и восстановления объектов JavaScript стандартом ECMAScript 5 предоставляются встроенные функции JSON.stringify() и JSON.parse(). Эти функции используют формат обмена данными JSON. Название JSON происходит от «JavaScript Object Notation» (форма записи объектов JavaScript), а синтаксис этой формы записи напоминает синтаксис литералов объектов и массивов в языке JavaScript:
Синтаксис формата JSON является лишь подмножеством синтаксиса языка JavaScript и не может использоваться для представления всех возможных значений, допустимых в JavaScript. Поддерживаются и могут быть сериализованы и восстановлены: объекты, массивы, строки, конечные числовые значения, true, false и null. Значения NaN, Infinity и -Infinity сериализуются в значение null. Объекты Date сериализуются в строки с датами в формате ISO, но JSON.parse() оставляет их в строковом представлении и не восстанавливает первоначальные объекты Date.
Объекты Function, RegExp и Error и значение undefined не могут быть сериализованы или восстановлены. Функция JSON.stringify() сериализует только перечислимые собственные свойства объекта. Если значение свойства не может быть сериализовано, это свойство просто исключается из строкового представления. Обе функции, JSON.stringify() и JSON.parse(), принимают необязательный второй аргумент, который можно использовать для настройки процесса сериализации и/или восстановления, например, посредством определения списка свойств, подлежащих сериализации, или функции преобразования значений во время сериализации.
Координаты мыши: clientX(Y)/pageX(Y)
При обработке событий, связанных с мышью, нужен кроссбраузерный способ получения координат курсора из события в обработчике.
Координаты курсора мыши относительно окна находятся в стандартных свойствах . Они одинаково поддерживается всеми браузерами.
Если у вас есть окно 500×500, и мышь находится в центре, то и будут оба равны 250. Если вы затем проскроллируете документ вниз, налево или вверх, не двигая курсор — значения не изменятся, так как отсчитываются относительно окна, а не документа.
Как правило, при обработке события нужна позиция мыши относительно документа, учитывающая прокрутку. Стандарт W3C предоставляет для этого свойство .
Если у вас есть окно 500×500, и мышь находится в центре, то и будут оба равны 250. Если вы затем проскроллируете на 250 пикселей вниз, станет равным 750.
Таким образом содержат координаты, на каком месте документа произошло событие, учитывая все прокрутки.
Свойства поддерживаются всеми браузерами, кроме Internet Explorer.
В IE их можно получить из , прибавив к ним .
Обычно оно находится в <body>: , но это не всегда так. Например, при выборе Strict DTD оно высчитывается для <html>: . Кроме того, тэга <body> может просто не быть в документе.
Поэтому мы сначала возьмем (если есть), затем проверим . Если нет ни того, ни того, то 0.
var html = document.documentElement var body = document.body e.pageX = e.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0)
Кроме того, в IE может быть немного сдвинут с позиции 0,0. Значение сдвига находится в , и его также необходимо учесть.
Этот код позволяет надежно получить для IE, в котором его изначально нет:
if (e.pageX == null && e.clientX != null ) { var html = document.documentElement var body = document.body e.pageX = e.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0) e.pageY = e.clientY + (html && html.scrollTop || body && body.scrollTop || 0) - (html.clientTop || 0) }
Этот обработчик обновляет координаты мыши относительно документа.
function mouseShowHandler(e){ e = e || window.event if (e.pageX == null && e.clientX != null ) { var html = document.documentElement var body = document.body e.pageX = e.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0) e.pageY = e.clientY + (html && html.scrollTop || body && body.scrollTop || 0) - (html.clientTop || 0) } document.getElementById('mouseX').value = e.pageX document.getElementById('mouseY').value = e.pageY }
Координата X:
Координата Y:
Немного о «length»
Свойство автоматически обновляется при изменении массива. Если быть точными, это не количество элементов массива, а наибольший цифровой индекс плюс один.
Например, единственный элемент, имеющий большой индекс, даёт большую длину:
Обратите внимание, что обычно мы не используем массивы таким образом. Ещё один интересный факт о свойстве – его можно перезаписать
Ещё один интересный факт о свойстве – его можно перезаписать.
Если мы вручную увеличим его, ничего интересного не произойдёт. Зато, если мы уменьшим его, массив станет короче. Этот процесс необратим, как мы можем понять из примера:
Таким образом, самый простой способ очистить массив – это .
Javascript прототипы (Prototype) встроенных объектов
Добавление свойств и методов к встроенным объектам (прототип)
Рассмотрим работу с прототипами на примере:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Изменение прототипа */ // Добавление свойства по умолчанию к встроенному объекту String.prototype.color = "black"; // Добавление (изменение) метода к встроенному объекту String.prototype.write = stringWrite; function stringWrite(){ document.write('<span style="color:' + this.color + '">'); document.write(this.toString()); document.write('</span>'); } // используем измененный класс var s = new String("Это строка"); s.color = "red"; s.write(); |
Важно: К объекту Math нельзя добавлять свойства и методы
Задание js 6_4. Дополните код программы для выполнения задания: К встроенному классу добавить метод , который выводит слово «Ура!» как заголовок (тег ), указанного пользователем уровня ().
Уровень заголовка (1, 2 … 6) можно добавить в виде свойства класса .
Вспомним, как должны выглядеть теги заголовков в HTML:
<h1>Заголовок<h1> <h2>...<h2> ... |
Дополните код:
1 2 3 4 5 6 7 8 |
String.prototype.uroven="1"; ... function printZagolovok (){ ... ... } var s=new ...; ... |
Резюме: сравним еще раз два варианта использования пользовательских объектов в JavaScript:
- Создание объектов-коллекций
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
var myBook=new Object(); myBook.title="книга"; myBook.price="200"; alert(myBook"title"); // 1-й вариант обращения к свойствам alert(meBook.price); // 2-й вариант обращения к свойствам function myBookShow() { for (var i in myBook) { document.write(i+": "+myBooki+"<br>"); // Перебор свойств } } myBook.show=myBookShow; myBook.show(); |
Создание классов-конструкторов
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function myBook(title,price){ // определение свойств this.title = title; this.price = price; // определение метода this.show = show; function show() { document.write("Название: " + this.title); document.write("Цена: " + this.price); } } var book = new myBook("Книга", 200); book.show(); |
Задание js 6_5
Создать объект-коллекцию , который содержит сведения о сотруднике некоторой фирмы, такие как , , , и отображает данные об этом сотруднике (создать метод объекта для отображения данных)
Важно: Для объекта-коллекции невозможно создавать экземпляры. Свойства и методы создаются один раз для одного объекта
Задание js 6_6
Создать меню из пунктов-гиперссылок:
- Определить класс .
- Определить свойства: (название пункта меню или текст гиперссылки), (значение атрибута href для гиперссылки), метод (вывод на экран созданного меню).
- Добавить 4 пункта меню в виде списка (тег )
Вспомним код html для создания пунктов меню:
<li><a href="labs-org.ru">Перейти на главную страницу<a><li> <li> ... <li> <li> ... <li> |
*Сложное: количество пунктов меню, их названия и url необходимо запрашивать у пользователя
Совет: для вывода в методе строки на экран воспользуйтесь методом
Квадратные скобки
Для свойств, имена которых состоят из нескольких слов, доступ к значению «через точку» не работает:
JavaScript видит, что мы обращаемся к свойству , а затем идёт непонятное слово . В итоге синтаксическая ошибка.
Точка требует, чтобы ключ был именован по правилам именования переменных. То есть не имел пробелов, не начинался с цифры и не содержал специальные символы, кроме и .
Для таких случаев существует альтернативный способ доступа к свойствам через квадратные скобки. Такой способ сработает с любым именем свойства:
Сейчас всё в порядке
Обратите внимание, что строка в квадратных скобках заключена в кавычки (подойдёт любой тип кавычек)
Квадратные скобки также позволяют обратиться к свойству, имя которого может быть результатом выражения. Например, имя свойства может храниться в переменной:
Здесь переменная может быть вычислена во время выполнения кода или зависеть от пользовательского ввода. После этого мы используем её для доступа к свойству. Это даёт нам большую гибкость.
Пример:
Запись «через точку» такого не позволяет:
Мы можем использовать квадратные скобки в литеральной нотации для создания вычисляемого свойства.
Пример:
Смысл вычисляемого свойства прост: запись означает, что имя свойства необходимо взять из переменной .
И если посетитель введёт слово , то в объекте теперь будет лежать свойство .
По сути, пример выше работает так же, как и следующий пример:
…Но первый пример выглядит лаконичнее.
Мы можем использовать и более сложные выражения в квадратных скобках:
Квадратные скобки дают намного больше возможностей, чем запись через точку. Они позволяют использовать любые имена свойств и переменные, хотя и требуют более громоздких конструкций кода.
Подведём итог: в большинстве случаев, когда имена свойств известны и просты, используется запись через точку. Если же нам нужно что-то более сложное, то мы используем квадратные скобки.
Взаимосвязанные объекты
Теперь более сложный пример. Семья:
Функция «женит» два объекта, давая им ссылки друг на друга, и возвращает новый объект, содержащий ссылки на два предыдущих.
В результате получаем такую структуру памяти:
На данный момент все объекты достижимы.
Теперь удалим две ссылки:
Недостаточно удалить только одну из этих ссылок, потому что все объекты останутся достижимыми.
Но если мы удалим обе, то увидим, что у объекта John больше нет входящих ссылок:
Исходящие ссылки не имеют значения. Только входящие ссылки могут сделать объект достижимым. Объект John теперь недостижим и будет удалён из памяти со всеми своими данными, которые также стали недоступны.
После сборки мусора: