Интенсивное чтение «JavaScript, которого вы не знаете (Том 1)»

внешний интерфейс Шаблоны проектирования Безопасность JavaScript
Интенсивное чтение «JavaScript, которого вы не знаете (Том 1)»

предисловие

«JavaScript, которого вы не знаете» — это серия статей, обязательная к прочтению для изучения интерфейсов. Она позволяет разработчикам JavaScript, которые мало что знают о трудностях, углубиться в язык и выяснить назначение каждого компонента JavaScript. Эта книга охватывает две темы из серии: "Область действия и замыкания" и "это и прототипы объектов". Эти две части также заслуживают нашего повторного изучения и размышления. Эти две части - только содержание. Сегодня мы будем использовать интеллект-карту, чтобы интенсивно читать их. (Изображение интеллект-карты может быть немного маленьким, не забудьте нажать и посмотреть, вы что-то получите)

Часть 1 Область применения и закрытия

каков охват

Область видимости — это набор правил для определения, где и как искать переменные (идентификаторы). Если целью поиска является присвоение переменной, то используется запрос LHS, если целью является получение значения переменной, используется запрос RHS. Оператор присваивания приводит к поиску LHS. операция присваивания. Оператор = или операция передачи аргументов при вызове функции приводит к присваиванию в связанной области. Механизм JavaScript сначала компилирует код перед его выполнением, и в этом процессе объявление типа var a = 2 разбивается на два отдельных шага:

  1. Во-первых, var a объявляет новую переменную в своей области видимости. Это делается в самом начале, до выполнения кода.
  2. Затем a = 2 запрашивает (запрос LHS) переменную a и присваивает ей значение.

И LHS, и RHS-запросы начинаются в текущей области выполнения, а при необходимости (то есть не находят требуемый идентификатор) продолжают поиск целевого идентификатора в верхней области видимости, так что каждый раз при повышении области видимости на единицу уровень (один этаж) и, наконец, достичь глобальной области (верхний уровень), он остановится независимо от того, найден он или нет.

Неудачная ссылка RHS приведет к возникновению исключения ReferenceError. Неудачная ссылка LHS приводит к автоматическому неявному созданию глобальной переменной (в нестрогом режиме) с использованием цели ссылки LHS в качестве идентификатора или к исключению ReferenceError (в строгом режиме).

лексический охват

Лексическая область видимости означает, что область видимости определяется расположением объявления функции при написании кода. Фаза лексического анализа компиляции в основном знает, где и как объявлены все идентификаторы, и, таким образом, может предсказать, как они будут искаться во время выполнения.

В JavaScript есть два механизма для «обмана» лексической области видимости: eval(..) и с . Первый может работать со строкой «кода», содержащей одно или несколько объявлений, и тем самым изменять существующие лексические области видимости (во время выполнения). Последний по существу создает новую лексическую область (опять же во время выполнения), рассматривая ссылку на объект как область, а свойства объекта как идентификатор в области.

Побочным эффектом этих двух механизмов является то, что движок не может оптимизировать поиск областей во время компиляции, потому что движок может только предусмотреть, что такие оптимизации неэффективны. Использование любого из этих механизмов приведет к тому, что ваш код будет работать медленнее. Не используйте их.

область действия функции и область действия блока

Функции являются наиболее распространенной единицей области видимости в JavaScript. По сути, переменная или функция, объявленная внутри функции, «скрыта» от области, в которой она находится, что по замыслу является принципом хорошего программного обеспечения.

Но функции — не единственная единица области видимости. Блочная область видимости означает, что переменные и функции могут принадлежать не только той области видимости, в которой они расположены, но и блоку кода (обычно внутри { .. } ).

Начиная с ES3, конструкции try/catch имеют область действия блока в предложениях catch. Ключевое слово let (двоюродный брат ключевого слова var) было введено в ES6 для объявления переменных в произвольных блоках кода. if(..) { let a = 2; } объявляет переменную, которая захватывает блок if { .. } и добавляет переменную в блок.

Некоторые утверждают, что область видимости блока не следует использовать целиком как замену области видимости функции. Обе функции должны существовать одновременно, и разработчики могут и должны выбирать, какую область использовать по мере необходимости для создания хорошего кода, удобочитаемого и поддерживаемого.

продвигать

Мы привыкли думать о var a = 2; как о декларации, хотя на самом деле движок JavaScript этого не делает. Он обрабатывает var a и a = 2 как два отдельных объявления, первое для задачи фазы компиляции, а второе — для задачи фазы выполнения.

Это означает, что везде, где появляются объявления в области видимости, они будут обработаны в первую очередь до того, как будет выполнен сам код. Этот процесс можно визуализировать, поскольку все объявления (переменных и функций) «перемещаются» в верхнюю часть соответствующих областей видимости, этот процесс называется подъемом.

Сами объявления поднимаются, а операции присваивания, включая присваивания функциональным выражениям, — нет.

Будьте осторожны, чтобы избежать дублирования объявлений, особенно при смешивании обычных объявлений var с объявлениями функций, иначе это может вызвать много опасных проблем!

закрытие области

Замыкания похожи на мистический нецивилизованный мир, отпочковавшийся от JavaScript, куда могут попасть только самые смелые. Но на самом деле это просто стандарт, видимо о том, как писать код в лексическом окружении, где функции передаются как значения по запросу.

Замыкания создаются, когда функция может запомнить и получить доступ к лексической области, в которой она находится, даже если функция выполняется за пределами текущей лексической области.

Если вы не узнаете замыкание и не понимаете, как оно работает, при его использовании легко допустить ошибку, например, в цикле. Но в то же время замыкания также являются очень мощным инструментом, который можно использовать во многих формах для реализации шаблонов, таких как модули. Модули имеют две основные характеристики:

(1) Функция-оболочка вызывается для создания внутренней области видимости; (2) Возвращаемое значение функции-оболочки должно включать хотя бы одну ссылку на внутреннюю функцию, которая создаст замыкание, охватывающее всю внутреннюю область действия функции-оболочки.

Теперь мы увидим, что в нашем коде повсюду есть замыкания, и мы можем распознавать замыкания и использовать их для чего-то полезного!

Вторая часть это и прототип объекта

этот всеобъемлющий анализ

Если вы хотите определить привязку this к работающей функции, вам нужно найти место прямого вызова функции. Найдя его, вы можете применить следующие четыре правила, чтобы определить объект привязки this.

  1. Вызывается new?Привязывается к только что созданному объекту.

  2. Вызывается вызовом или применением (или привязкой)? Привязывается к указанному объекту.

  3. Вызывается объектом контекста? Привязывается к этому объекту контекста.

  4. По умолчанию: привязка к undefined в строгом режиме, в противном случае привязка к глобальному объекту.

Важно отметить, что некоторые вызовы могут непреднамеренно использовать правила привязки по умолчанию. Если вы хотите «безопасно» игнорировать эту привязку, вы можете использовать объект DMZ, например ø = Object.create(null) , для защиты глобального объекта. Стрелочные функции в ES6 не используют четыре стандартных правила привязки, но определяют это в соответствии с текущей лексической областью видимости, в частности, стрелочные функции наследуют привязку this вызова внешней функции (независимо от того, к чему эта привязка). На самом деле это тот же механизм, что и self = this в коде до ES6.

объект

Объекты в JavaScript имеют литеральную форму (например, var a = { .. } ) и сконструированную форму (например, var a = new Array(..) ). Буквенные формы используются чаще, но иногда составные формы предоставляют больше возможностей.

Многие люди думают, что «все в JavaScript является объектом», что неверно. Объекты являются одним из 6 (или 7, в зависимости от вашей точки зрения) базовых типов. Объекты имеют подтипы, включая функцию, и разные подтипы имеют разное поведение.Например, внутренняя метка [массив объектов] указывает, что это массив подтипов объектов.

Объект представляет собой набор пар ключ/значение. Значение свойства можно получить с помощью синтаксиса .propName или ["propName"]. При доступе к свойству движок фактически вызовет внутреннюю операцию [[Get]] по умолчанию ([[Put]] при установке значения свойства), а операция [[Get]] проверит, содержит ли сам объект свойство, если не найден, он также ищет цепочку [[Prototype]] (см. главу 5).

Свойства свойств можно контролировать с помощью дескрипторов свойств, таких как writable и configurable. Кроме того, Object.preventExtensions(..) , Object.seal(..) и Object.freeze(..) можно использовать для установки уровня неизменности объекта (и его свойств).

Свойства не обязательно содержат значения — они могут быть «дескрипторами доступа» с геттерами/сеттерами. Кроме того, свойства могут быть перечисляемыми или неперечисляемыми, что определяет, будут ли они появляться в цикле for..in.

Вы можете использовать синтаксис ES6 for..of для перебора значений в структуре данных (массив, объект и т. д.), for..of будет искать встроенный или пользовательский объект @@iterator и вызывать его следующий () метод для перебора значений данных.

объект миксина "класс"

Класс — это шаблон проектирования. Многие языки предоставляют собственный синтаксис для программного дизайна. JavaScript имеет аналогичный синтаксис, но он полностью отличается от классов в других языках.

Класс означает копию.

Когда создается экземпляр традиционного класса, его поведение копируется в экземпляр. Когда класс наследуется, поведение также копируется в подклассы.

Полиморфизм (функции с одним и тем же именем, но разные функции на разных уровнях цепочки наследования) может показаться ссылкой на родительский класс из подкласса, но по сути ссылка является результатом копирования.

JavaScript не создает копии объектов автоматически (как это делают классы).

Шаблоны примесей (явно или неявно) могут использоваться для имитации поведения копирования классов, но обычно приводят к уродливому и хрупкому синтаксису, такому как явный псевдополиморфизм ( OtherObj.methodName.call(this, ...) ), This делает код сложнее для понимания и сложнее в обслуживании.

Кроме того, явный миксин не может на самом деле полностью имитировать поведение копирования класса, потому что объекты (и функции! Не забывайте, что функции тоже являются объектами) могут копировать только ссылки, а не сам объект или функцию, на которую они ссылаются. Игнорирование этого может привести ко многим проблемам.

В общем, имитация классов в JavaScript не стоит потерь, хотя она и может решить текущую проблему, но может таить в себе больше скрытых опасностей.

прототип

Чтобы получить доступ к свойству, не существующему в объекте, операция [[Get]] (см. главу 3) ищет объект, связанный с [[Prototype]] внутри объекта. Эта ассоциация фактически определяет «цепочку прототипов» (что-то вроде вложенной цепочки областей видимости), которая проходится при поиске свойств.

Все обычные объекты имеют встроенный Object.prototype , который указывает на вершину цепочки прототипов (например, на глобальную область видимости) и останавливается, если указанное свойство не найдено в цепочке прототипов. toString() , valueOf() и некоторые другие общие функции существуют в объектах Object.prototype, поэтому все объекты языка могут их использовать.

Самый распространенный способ связать два объекта — использовать ключевое слово new для вызова функции, которая создает новый объект, связывающий другие объекты в главе о вызовах. За 4 шага (глава 2) создается новый объект, связанный с другими объектами.

Вызов функции с помощью new связывает свойство .prototype нового объекта с «другими объектами». Вызовы функций с оператором new часто называют «вызовами конструктора», хотя на самом деле они не совпадают с конструкторами классов в традиционных языках, ориентированных на классы.

Основное различие между механизмами в JavaScript заключается в том, что копирование не выполняется, объекты

Хотя эти механизмы очень похожи на «инициализацию класса» и «наследование класса» в традиционных объектно-ориентированных языках, механизм javascript очень похож на «инициализацию класса» и «наследование класса» в традиционных объектно-ориентированных языках классов, но механизмы в javascript: Основное отличие состоит в том, что нет копирования, а объекты связаны через внутреннюю цепочку [[Prototype]].

По разным причинам термины, оканчивающиеся на «наследование» (включая «прототипное наследование»), и другие объектно-ориентированные термины не помогают вам понять реальную механику JavaScript (и не только ограничивают наше мышление).

Напротив, «делегировать» — более подходящий термин, потому что отношения между объектами — это не копирование, а делегирование.

делегирование поведения

В архитектуре программного обеспечения вы можете выбрать, использовать ли шаблоны проектирования классов и наследования. Большинство разработчиков считают классы само собой разумеющимся единственным (подходящим) способом организации кода, но в этой главе мы рассмотрели другой менее распространенный, но более мощный шаблон проектирования: делегирование поведения.

Делегирование поведения считает, что между объектами и делегатами друг друга существуют родственные отношения, а не отношения между родительским и дочерним классами. Механизм JavaScript [[Prototype]] по существу является механизмом делегирования поведения. Тем не менее, мы можем стремиться к механизму классов в JavaScript (см. главы 4 и 5) или можем использовать более естественный механизм делегирования [[Prototype]].

Когда вы используете только объекты для разработки своего кода, вы не только делаете синтаксис более кратким, но и делаете структуру кода более понятной.

Ассоциация объектов (объекты связаны друг с другом ранее) — это стиль кодирования, который поддерживает создание и связывание объектов напрямую, без абстрагирования их в классы. Ассоциации объектов могут быть реализованы очень естественно с делегированием поведения на основе [[Prototype]] .

расширять

Карта разума может более четко восстановить систему структуры знаний всей книги.Если вы еще не читали эту книгу, вы можете быстро просмотреть ее в соответствии с идеями этой карты разума, чтобы повысить эффективность обучения. Изучение новых вещей всегда легко забыть. Я предпочитаю использовать интеллект-карты, чтобы делать некоторые заметки при чтении книг, чтобы я мог просмотреть их позже. Если вы прочитали эту книгу, также рекомендуется собрать и просмотреть. Если у вас есть предложения или идеи Shenma, оставьте сообщение или добавьте меня в WeChat: 646321933

JavaScript, который вы не знаете, сворачивает онлайн-документацию, часть 2

JavaScript, которого вы не знаете (увеличьте громкость) Адрес загрузки PDF

Интенсивное чтение тома II "JavaScript, которого вы не знаете"

Интенсивное чтение "Иллюстрированного HTTP"

Адрес для скачивания ментальной карты