Базовая концепция JavaScript в красной книге трех кистей

внешний интерфейс JavaScript

предисловие

Это третий раз, когда я открываю Красную книгу, которая называется «Расширенное программирование на JavaScript, 3-е издание». Я должен сказать, что, хотя книге уже несколько лет, многие знания не подходят для современной фронтенд-разработки, а для тех, для тех, кто хочет освоить JavaScript Basic для начинающих, или, как я, кто хочет восстановить те части знаний, которые были забыты в уголке памяти, эта книга все еще очень подходит, и она заслуживает того, чтобы называться «Библия JavaScript».

Эта статья предназначена для чтения.Есть еще одна причина, по которой я решил перечитать эту книгу еще раз.Раньше я делал бумажные заметки.На этот раз я хочу использовать ее в виде электронной версии,что также можно рассматривать как аранжировку предыдущих знание.

本文篇幅较长,目的是作为我的电子版学习笔记,我会尽可能去其糟粕,取其精华,同时我会添加一些书上未记载但很重要的知识点补充

let's go

Введение в JavaScript

Полный JavaScript состоит из 3 частей: ядра (синтаксис ECMAScript), DOM, BOM, последние две в настоящее время являются необязательными или могут быть абстрагированы как хост, поскольку JS больше не ограничивается запуском в браузерах.

Использование JavaScript в HTML

Использование JS в браузере можно сделать черезscriptТег для выполнения JS-файла, который далее можно разделить на 3 способа, встроенный JS-код, указание на локальный JS-файл через src, указание на JS-файл (доменное имя) статического сервера через src, рекомендуется использовать форму src, по сравнению с Inline, может использовать кеш для повышения скорости загрузки страниц и скорости анализа DOM, а поскольку JS и HTML не связаны, он более удобен в сопровождении.

Когда тег script имеет форму srcвнешний скрипт, можно установить вdefer,asyncАтрибуты, первый позволяет запускать скрипт после парсинга страницы, второй асинхронно загружает скрипт и выполняет его, и в то же время асинхронно выполняет код JS Эти два атрибута должны решить проблему, которую браузер должен ждать пока код JS в теге script. После загрузки и выполнения следующие элементы будут проанализированы, что приведет к долгосрочной проблеме с белым экраном.

<script src="xxx" async></script>

Основные концепции JavaScript

идентификатор

Идентификаторы относятся к именам переменных, функций и свойств.Основные имена в основном это camelCase, или $,_

Первый символ не может быть числом (но разрешено начинать со второго символа)

// illegal
let 123hello = '123'

// legitimate
let $123hello = '123'
let helloWorld = '123'
let hello123World = '123'
let _$hello = '123'

тип данных

На сегодняшний день JavaScript имеет 7 простых типов данных и 1 сложный тип данных.

Простые типы данных:

  • Undefined
  • Null
  • Boolean
  • Number
  • String
  • Symbol
  • BigInt (черновик ES10)

Сложные типы данных:

  • Object

Function 是 Object 的子类,即继承于 Object

Неопределенный тип

Неопределенный тип имеет только одно значение, то есть неопределенное, его легко спутать с неопределенным, их сходства и различия очевидны.

  • Использование оператора typeof возвращает 'undefined'
  • Использование неопределенных переменных безопасно, использование неопределенных переменных вызовет ошибку
let foo

console.log(typeof foo) // 'undefined'
console.log(typeof bar) // 'undefined'

console.log(foo) // undefined
console.log(bar) // Uncaught ReferenceError: bar is not defined

Нулевой тип

Тип Null также имеет только одно значение, равное null.обозначает нулевой объект указатель NULL, если используется оператор typeof, возвращаемый тип — 'object', но это всего лишь языковая ошибка, исправить которую в настоящее время почти невозможно. вернет false, что доказывает, что null и Object не являются неважными

console.log(typeof null) // 'object'
console.log(null instanceof Object) // false

неопределенные значения получены из нулевых значений, поэтому они примерно равны

console.log(undefined == null) // true

Тип номера

Числовой тип JS использует формат IEEE754 для представления целых чисел и значений с плавающей запятой, что вызовет небольшие проблемы.Например, 0,1 в JS на самом деле не 0,1, его двоичное значение равно 0,001100110011..., бесконечный цикл (от малого десятичного до двоичный файл (правило умножается на 2 и округляется в большую сторону), который хранится внутри, как это

Вы можете передать функцию Number для преобразования входящих параметров в соответствующий тип Number (обратите внимание на яму неявного преобразования)

console.log(Number('123')) // 123
console.log(Number(null)) // 0
console.log(Number(undefined)) // NaN
console.log(Number('false')) // NaN
console.log(Number(true)) // 1

NaN относится к типу Number, а NaN не равен самому себе, вы можете передать объект окнаisNaNчтобы судить, является ли параметр NaN, но у него есть недостаток, заключающийся в том, что он сначала преобразует параметр в числовой тип (также неявное преобразование), поэтому он будет отображатьсяisNaN('foo')Возвращает true, ES6Number.isNaNВосполняет этот недостаток, он вернет false, доказывая, что строка «foo» не является NaN.

console.log(NaN === NaN) // false
console.log(isNaN(NaN)) // true
console.log(isNaN('foo')) // true 但这是不合理的,因为 'foo' 并不是 NaN
console.log(Number.isNaN('foo')) // false

window.isNaN используется, чтобы определить, является ли параметр числом, Number.isNaN используется, чтобы определить, является ли параметр NaN

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

console.log(parseInt('123.456')) // 123
console.log(parseInt('123foo')) // 123
console.log(Number('123foo')) // NaN

parseInt будет анализировать параметр «123foo» один за другим, когда встретитнечисловые символы или десятичная точка(здесь строка f), которая вернет ранее преобразованное число, а Number преобразует весь параметр в число

(Стоит отметить, что parseFloat встречает нечисловые символы иливторойдесятичной точки, он вернет ранее преобразованное число)

String

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

Object

И DOM, и BOM-объекты являются хост-объектами, предоставляемыми хостом. Хостом здесь является браузер. Другими словами, в небраузерной среде могут отсутствовать некоторые глобальные переменные и методы в браузере. Например, в узел.

оператор

унарный оператор

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

let num1 = 2
let num2 = 20
let num3 = --num1 + num2 // 21
let num4 = num1 + num2 // 21
let num1 = 2
let num2 = 20
let num3 = num1-- + num2 // 22
let num4 = num1 + num2 // 21

Первый сначала уменьшает num1 на 1, а затем выполняет накопление с num2, а второй сначала накапливает с num2, а затем уменьшает num на 1. , другой унарный оператор сначала попытается преобразовать переменную в число

логический оператор

Логические операторы И и логические НЕ являются операциями короткого замыкания, то есть первый операнд определяет результат, а второй операнд не оценивается.

let num = 0
true || num++
console.log(num) //0

Следующая часто используемая логика и результаты суждений

первый операнд оператор второй операнд результат
null && Любые первый операнд
undefined && Любые первый операнд
NaN && Любые первый операнд
false && Любые первый операнд
"" && Любые первый операнд
0 && Любые первый операнд
объект && Любые второй операнд
true && Любые второй операнд

Когда первый аргумент ложен, логическое И возвращает первый операнд, в противном случае возвращает второй операнд.

Вот список всех ложных значений: false, null, undefined, 0, NaN, ""

Логика или с логикой и наоборот, следующие общие результаты логики или суждения

первый операнд оператор второй операнд результат
null || Любые второй операнд
undefined || Любые второй операнд
NaN || Любые второй операнд
false || Любые второй операнд
"" || Любые второй операнд
0 || Любые второй операнд
объект || Любые первый операнд
true || Любые первый операнд

Когда первый параметр равен false, логическое или возвращает второй операнд, в противном случае возвращает первый операнд.

Аддитивный оператор

В ECMAScript аддитивный оператор имеет некоторые особенности поведения, которые делятся на случаи со строками в операндах и без них.

Все строки рассматриваются как сращивание строк.Если одна из них является строкой, а другая не является строкой, она будет преобразована в строку, а затем сплайсирована, и тогда возникнут две ситуации.

  • Второй операнд - это объект, он вызовет[[toPrimitive]]Преобразуйте его в исходное значение, если исходное значение является строкой, оно все равно будет выполнять конкатенацию строк.
  • Если операнд не является объектом, он напрямую рассматривается как конкатенация строк.
console.log("123" + 123) // "123123"
console.log('123' + NaN) // "123NaN"
console.log("123" + {}) // "123[object Object]"
console.log("123" + undefined) // "123undefined"

Если оба операнда не являются строками, возможны два случая.

  • операнд является объектом, он вызовет[[toPrimitive]]Преобразуйте его в исходное значение, если исходное значение является строкой, оно все равно будет выполнять конкатенацию строк.
  • Если операнд не является объектом, он будет преобразован в числовой тип, а затем рассчитан

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

console.log(123 + true) // 124
console.log(123 + undefined) // NaN 因为 undefined 被转为 NaN
console.log(NaN + {}) // "NaN[object Object]" 含有对象会转为原始值,因为是字符串所以视为拼接

оператор отношения

Как и аддитивные операторы, реляционные операторы в JS (>, =,

  • Если оба операнда числовые, выполнить числовое сравнение (если один из них NaN, всегда возвращать false)
  • Два операнда представляют собой строки, сравнивающие кодовое значение строки одно за другим.
  • где один из операндов является объектом, вызов[[toPrimitive]]Преобразование в исходное значение и сравнение в соответствии с предыдущими правилами
  • Один из операндов — логическое значение, которое преобразуется в числовой тип, а затем выполняется сравнение

Для второй статьи, например

console.log('abc' < 'abd') // true

Внутренне он оценивается следующим образом.Поскольку оба являются строками, сначала оцените первый бит строки и найдите, что все они равны «a», затем сравните второй и найдите, что он одинаков, затем сравните третий, потому что "c" " имеет меньшую кодировку, чем "d" (первое 99, а второе 100), поэтому строка abc "меньше" строки abd

оператор равенства

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

undefined==null //true
[]==[] //false
[]==![] //true
{}==!{} //false
![]=={} //false
[]==!{} //true
[1,2]==![1] //false

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

  • Если типы совпадают, непосредственно определите, равны ли они, и неявное преобразование будет происходить для разных типов.
  • Когда объект задействован, он вызывает[[toPrimitive]]
  • NaN и ничего не хочет ждать, в том числе и себя
  • Обе части уравнения будут максимально преобразованы в тип Number.Если это уже тот же тип на пути к номеру, то он не будет преобразован дальше.
  • null и undefined имеют некоторые особенности поведения, прежде всего, это свободное равенство (==), но не строгое равенство (===), за исключением того, что ни одно значение не потеряет/строгое равенство с null/undefined

В общем, чтобы избежать ямы неявного преобразования, попробуйте использовать строгое равенство (===)

для заявления

Оператор for фактически является производным от оператора while. Оператор for содержит три выражения, разделенных точкой с запятой. Первое выражение обычно является объявлением или оператором присваивания, второе выражение является условием завершения цикла, а третье выражение является выражением для выполняться после одного цикла

let i = 0

for (;;i++){
    //...
}

Приведенный выше код попадет в бесконечный цикл и вылетит из браузера, потому что второе выражение не задано, оно будет считаться всегда истинным, то есть цикл никогда не завершится, а переменная цикла i будет каждый раз +1, и нет начального оператора, сам код не имеет смысла, он просто означает, что три выражения цикла for необязательны

Если порядок выполнения оператора for отсортирован в соответствии с порядком выполнения, он выглядит так:

for (/* 1 */let i = 0;/* 2 */i < 10;/* 3 */i++) {
    /* 4 */ console.log(i)
} 

Последовательность 1 -> 2 -> 4 -> 3 -> 4 -> 3 -> 4 -> ... -> выход

в заявлении

Оператор for in возвращает свойства объекта,Возвращаемый порядок может варьироваться в зависимости от браузера, потому что спецификации нет, поэтому не полагайтесь на порядок, который он возвращает, в то время как Reflect.ownKeys , Object.getOwnPropertyNames , Object.getOwnPropertySymbols определяются алгоритмом [[OwnPropertyKeys]] спецификации ES6, который читается следующим образом

  • Свойства, возвращающие целые числа первыми по порядку (свойства массивов)
  • Возвращает строковые свойства по очереди в том порядке, в котором они были созданы
  • Наконец возвращает все свойства символа

заявление этикетки

Используйте оператор label для добавления меток к оператору for.Когда оператор for выходит через операторы break и continue, вы можете дополнительно указать имя метки для выхода во внешний цикл, который будет использоваться в многоуровневых циклах for.

let num = 0

outer: for (let i = 0; i < 10; i++) {
    for (let j = 0; j < 10; j++) {
        if (i === 5 && j === 5) {
            continue outer
        }
        num++
    }
}

console.log(num) // 95

Когда i и j оба равны 5, 5 обходов (55, 56, 57, 58, 59) будут пропущены, а окончательный результат равен 95, то есть цикл выполняется 95 раз.

оператор переключения

В операторе switch, если каждое условие не записывает ключевое слово break для выхода из решения, произойдет проникновение условия.

let i = 25

switch (i) {
    case 25:
        console.log('25')
    case 35:
        console.log('35')
        break;
    default:
        console.log('default')
}

// "25"
// "35"

i удовлетворяет первому случаю, поэтому печатается строка 25, но поскольку разрыва нет, она будетИгнорироватьВторое условие суждения напрямую выполняет утверждение второго случая, и если второе условие не имеет перерыва, он будет продолжать проникать в по умолчанию

Условие суждения случая в операторе switch строго равно, строка 10 не равна числу 10

функция

До ES6 аргументы функций хранились в файле с именемargumentsОбъект создается при выполнении функции, он похож на массив, имеет свойство длины, представляющее количество параметров.Количество параметров здесь — это количество параметров, переданных при выполнении функции, а не количество параметров, определенных функцией.

function func(a,b,c) {
    console.log(arguments)
}

func(1,2) // Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ, length:2]

Даже если определены три параметра, arguments отражает только количество параметров во время работы функции.Кроме того, у arguments есть некоторые особенности.в нестрогом режимеОн установит связь с параметрами времени выполнения функции, при изменении параметров это отразится на аргументах, и наоборот

function func(a,b,c) {
    console.log(arguments)
    a = 123
    console.log(arguments)
}

func(1,2) 
// Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ, length:2]
// Arguments(2) [123, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ, length:2]
function func(a,b,c) {
    console.log(a)
    arguments[0] = 123
    console.log(a)
}

func(1,2) 
// 1
// 123

а такжестрогий режимЭта связь не установлена, они полностью разделены, хотя ES6 все еще может использовать аргументы.был заброшен, рекомендуется оператор rest (...)

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

let obj = {}

function func(o) {
    o.a = '123'
}

console.log(obj) // {}
func(obj)
console.log(obj) // {a:"123"}

Поскольку оно передается по значению, переменная obj и формальный параметр o указывают на один и тот же объект памяти кучи.Свойство a добавляется к объекту через формальный параметр o внутри func, что будет отражено в переменной obj в момент в то же время.

Продолжение следует

использованная литература

Продвинутое программирование на JavaScript, 3-е издание

«JavaScript, которого вы не знаете»

ECMA-262

MDN