предисловие
Как следует из названия, это третий раз, когда я открываю Красную книгу, которая называется «Расширенное программирование на JavaScript, третье издание». Я должен сказать, что, хотя книге уже несколько лет, многие точки знаний не подходят для современного интерфейса. разработки, но для новичков, которые хотят освоить основы JavaScript, или, как я, кто хочет восстановить те части знаний, которые были забыты в уголке памяти, эта книга по-прежнему очень подходит, и она заслуживает быть под названием «Библия JavaScript».
Эта статья предназначена для чтения.Есть еще одна причина, по которой я решил перечитать эту книгу еще раз.Раньше я делал бумажные заметки.На этот раз я хочу использовать ее в виде электронной версии,что также можно рассматривать как аранжировку предыдущих знание.
本文篇幅较长,目的是作为我的电子版学习笔记,我会尽可能去其糟粕,取其精华,同时我会添加一些书上未记载但很重要的知识点补充
тип ссылки
Ссылочный тип — это структура данных, которая в других языках называется классом, но на самом деле в JavaScriptнисколькоКласс, хотя и предоставляет много «классового» синтаксиса (ключевое слово class), но многие книги считают, что это не очень хорошо.
let date = new Date()
console.dir(date)
здесь черезnewключевое слово для создания экземпляра ссылочного типа Date, вы можете обнаружить, что в его прототипе есть много общедоступных методов, а экземпляр ссылочного типа также называется значением ссылочного типа, который являетсяобъект
ECMAScript РоднойТипы ссылок
- Object
- Array
- Date
- RegExp
- Function
- Error
Далее я введем некоторые более часто используемые ссылочные типы для подробного анализа.
Object
Объект является наиболее распространенным типом ссылки.Собственные ссылочные типы наследуются от типа объекта.Вы можете получить доступ к объектам по точечным представлению и квадратным скобкам.
let obj = {} // 通过字面量表示法来创建对象,比 new 更加简便
obj.a = 1
obj["b"] = 2
obj["c d"] = 3 // 方括号可以支持点表示法不支持的语法
// 方括号也可以支持表达式
// ps:对象中含有数字的属性会被转为字符串
obj[1 + 2] = 4
obj[obj] = 5 // 如果属性是一个对象,会转为原始类型
console.log(obj) // {"3": 4, "a": 1, "b": 2, "c d": 3, "[object Object]": 5}
Вы можете использовать новое ключевое слово для динамической генерации объекта, и оно не ограничивается обычными объектами, но также может генерировать объекты типов-оболочек.
let str = "abc"
let wrappedStr = new Object("abc") // 等同于 new String("abc")
console.log(typeof str) // 'string'
console.log(typeof wrappedStr) // 'object'
console.log(wrappedStr instanceof String) // true 注意 String 首字母是大写,代表是 String 包装类型而非 string 基本类型
wrappedStr Этот объект-оболочка похож на базовый тип, но это объект, а также экземпляр типа-оболочки String, о котором мы поговорим позже.
Array
Тип Array может быть вызван ключевым словом new или литеральным выражением для генерации экземпляра.При использовании new и передаче параметра будет создан экземпляр длины параметра.разреженный массив(массив пустых ячеек), при передаче более двух параметров создается массив параметров
let arr1 = new Array(10)
let arr2 = new Array(10,20)
console.log(arr1) //[ <10 empty items> ]
console.log(arr2) // [ 10, 20 ]
Массивы имеют внутреннее свойство длины,его можно изменить, вы можете использовать эту функцию, чтобы быстро очистить массив и увеличить длину массива
let arr = [1,2,3] // 使用字面量创建数组
arr.length = 0
console.log(arr) // []
arr.length = 100
console.log(arr) // [ <100 empty items> ] 创建的都是空单元的稀疏数组,不推荐直接使用
При попытке преобразовать тип Array в строку (которая может существовать в неявных преобразованиях) вызывается метод toString по умолчанию для прототипа массива, который, в свою очередь, вызывает метод toString для каждого элемента в массиве (исключениями являются null и undefined). , они будут преобразованы непосредственно в пустые строки)
let arr = [{a:1},123,()=>{},undefined]
console.log(arr.toString()) // "[object Object],123,()=>{}," 最后以逗号结尾,因为 undefined 变成空字符串了
let obj = {}
obj[arr] = ""
console.log(obj) // { '[object Object],123,()=>{},': "" } 当对象的属性是一个对象,JS 会将其转为字符串再作为其属性,这里就发生了隐式转换
стеки и очереди
Массивы в JavaScript могут представлять как стеки, так и очереди.popМетод будет рассматриваться как стек, а вершина стека, являющаяся последним элементом массива, будет извлечена.shiftПри использовании метода он будет рассматриваться как очередь, а голова очереди, то есть первый элемент массива, будет исключена из очереди.
И способ добавления элементов массиваpush,unshiftвернет длину массива
let arr = [1,2,3]
console.log(arr.push(4)) // 4 表示数组长度为4
console.log(arr.unshift(0)) // 5 表示数组长度为5
console.log(arr.pop()) // 4 返回最后一个元素4
console.log(arr.shift()) // 0 返回第一个元素0
sort
позвонивsortможет сортировать элементы массива, но этот метод немного особенный,sort будет вызывать метод toString каждого элемента массива, из-за чего отсортированные результаты могут отличаться от ожидаемых.
let arr = [1,2,10,20,100,200]
console.log(arr.sort()) // [ 1, 10, 100, 2, 20, 200 ]
Вызов sort преобразует каждый элемент в строку, которая в конечном итоге отсортирует «1», «2», «10», «20», «10», «20», «100», «200», а впредыдущая главаКак я уже говорил в JavaScript, сравнение двух строк в JavaScript будет сравнивать кодировку каждой строки символов одну за другой. Если текущая кодировка символов одинакова, по очереди будет сравниваться следующий бит. Как только символ больше другого символ, результат будет возвращен напрямую. , никаких дальнейших сравнений производиться не будет.
Причина, по которой 10 здесь перед 2, заключается в том, что при сравнении «10» и «2» первое место сначала сравнивается со строкой 1 и строкой 2, потому что кодировка строки 2 больше, чем кодировка строки 1, поэтому напрямую выйдет из сравнения, что даст результат "10"
Это не странная ОШИБКА, а сортировка, используемая по умолчанию.лексикографическиСортировка, как Википедия объясняет лексикографический порядок
Представьте себе английский словарь слов, который, после чего бывший?
Очевидно, первая буква сначала расположена в порядке A, B, C ... Z; если первая буква та же, то вторая, третья и даже задняя буква. Если последние два слова разные (такие как вздох и вид), то короче размещены.
Таким образом, мы можем упорядочить слова, не связанные друг с другом. «Слово» можно рассматривать как строку «букв», и, в более широком смысле, его можно рассматривать как указание порядка для каждого упорядоченного кортежа, соответствующие элементы позиции которого принадлежат одному и тому же набору: следующее объясняется на формальном языке.
Если вы не используете метод сортировки по умолчанию, вы можете передать функцию сравнения методу сортировки.
let arr = [1,2,10,20,100,200]
console.log(arr.sort((a,b) => a - b)) // [ 1, 2, 10, 20, 100, 200 ]
sort — это высокоуровневая функция, то есть поддерживает передачу функции в качестве параметра, а переданные параметры вызываются для каждого сравнения, где параметры a и b — это две сравниваемые строки, о чем также упоминалось в предыдущем глава , если две строки вычитаются, они будут преобразованы в числовой тип, а затем вычислены, чтобы можно было избежать проблем, связанных со сравнением строковых типов.
При этом, если возвращаемое значение входящей функции больше 0, то b будет перед a, если меньше 0, то a будет перед b, а если равно 0, то останется неизменным.Согласно этой функции, порядок возвращаемого массива может контролироваться или изменяться.
let arr = [1,2,10,20,100,200]
// [ 200, 100, 20, 10, 2, 1 ] 倒序数组
// 第一次比较时 b 为 2,a 为 1,由于返回值大于 0,所以 b 将排在 a 的前面,变成 [2,1],以此类推
// 注意是插入排序
console.log(arr.sort((a,b) => b - a))
sort он изменит исходный массив вместо создания нового массива в качестве возвращаемого значения, пожалуйста, подумайте, нужно ли вам копировать исходный массив перед использованием
let arr = [1,2,10,20,100,200]
console.log(arr.sort((a,b) => b - a)) // [ 200, 100, 20, 10, 2, 1 ]
console.log(arr) // [ 200, 100, 20, 10, 2, 1 ] 原数组被修改了!
Отступление: в приведенной выше функции в качестве параметра вы можете случайным образом возвращать числа больше или меньше 0 через Math.random для достижения беспорядка массива, но на самом деле он не беспорядочный, иАлгоритм перемешиванияможет решить эту проблему
concat
concat добавит параметр в конец массива, в отличие от sort, который изменит исходный массив, он создаст копию (поверхностную копию) текущего массива, поэтому это относительно безопасно
Кроме того, если параметр содержит массив, для массива будет выполнен слой уменьшения размерности.
let arr = [1, 2, 3]
console.log(arr.concat(4, [5, 6], [7, [8, 9]])) // [ 1, 2, 3, 4, 5, 6, 7, [ 8, 9 ] ]
console.log(arr) // [1,2,3]
Конечно, сейчас больше рекомендуется использовать оператор распространения ES6, который более лаконичен и похож на функцию, реализованную concat, а также неглубоко копирует массив.
let arr = [1, 2, 3]
console.log([...arr, 4, ...[5, 6], ...[7, [8, 9]]]) // [ 1, 2, 3, 4, 5, 6, 7, [ 8, 9 ] ]
console.log(arr) // [1,2,3]
slice
slice будет обрезать массив на основе параметров, он также будет копировать массив неглубоко, когда будут переданы разные параметры, он будет иметь разные функции
- Если никакие параметры не переданы, будет возвращена неглубокая копия массива.
- При наличии только первого параметра индекс первого параметра будет возвращен в последний массив массива, если параметр превышает максимальный индекс, будет возвращен пустой массив.
- Когда передаются два параметра, он вернет первый параметр второму параметру - массиву индексов 1
- Если второй аргумент меньше первого аргумента (неотрицательного), вернуть пустой массив
- Если параметр содержит отрицательное число, будет добавлена длина массива и будут применены вышеуказанные правила.
Метод slice может преобразовать массив, подобный массиву, в настоящий массив.
let arr = [1, 2, 3, 4, 5]
console.log(arr.slice()) // [1, 2, 3, 4, 5] 浅拷贝原数组
console.log(arr.slice(2)) // [3, 4, 5]
console.log(arr.slice(2, 3)) // [3]
console.log(arr.slice(2, 1)) // []
console.log(arr.slice(2, -1)) // [3, 4] 等同于 arr.slice(2, -1 + 5)
console.log(Array.prototype.slice.call({0: "a", length: 1})) // ["a"]
splice
splice можно рассматривать как комбинацию push, pop, unshift, shift и может указывать позицию вставки/удаления.Это очень мощный инструмент, но параметры, которые он передает, также более сложны, поэтому, как правило, только тогда, когда конкретный элементы нижнего индекса массива манипулируются. будет использовать, в то время какон также изменяет исходный массив, обратите внимание при использовании
В то же время splice вернет массив.Если вы используете его функцию удаления, возвращаемый массив будет содержать удаленные элементы.Давайте рассмотрим некоторые частные примеры.
let arr = [1, 2, 3, 4, 5]
console.log(arr.splice(0, 1)) // [1]
console.log(arr) // [2, 3, 4, 5]
console.log(arr.splice(1)) // [3,4,5]
console.log(arr) // [2]
Первый вызов splice удалит элемент в индексе 0 массива, его возвращаемое значение — удаленный элемент 1, и в то же время распечатает массив, вы обнаружите, что splice был измененисходный массив, удаляется первый элемент исходного массива
Второй вызов splice передает только один параметр, что означает удаление с позиции, где нижний индекс массива равен 1, до последнего элемента массива, потому что массив в это время [2,3,4,5], поэтому удалите индекс с 1 до конца. Элементы 3, 4 и 5 используются в качестве возвращаемого значения splice, и, наконец, исходный массив содержит только элемент 2.
indexOf
Метод indexOf вернет индекс параметра в массиве.Если он не существует, он вернет -1.Особым случаем является NaN.Если вы используете indexOf, чтобы определить, есть ли NaN в массиве, он всегда будет возвращать - 1
let arr = [1,2,3,4,5,NaN]
console.log(NaN) // -1
Чтобы решить эту проблему, вы можете использовать ES6includesметод, он вернет логическое значение вместо нижнего индекса целевого элемента и может определить, существует ли NaN в целевом массиве.
let arr = [1,2,3,4,5,NaN]
console.log(arr.indexOf(NaN)) // -1
console.log(arr.includes(NaN)) // true
Я привык использовать include api, потому что во многих повседневных ситуациях вам нужно только знать, существует ли параметр в массиве, поэтому достаточно вернуть логическое значение.Если вам нужно вернуть индекс или искать параметры из указанная позиция в массиве, вы можете использовать indexOf
reverse
reverse, как sort и splice, изменяет исходный массив
let arr = [1,2,3,4,5]
console.log(arr.reverse()) // [5,4,3,2,1]
console.log(arr) // [5,4,3,2,1]
итерационный метод
ES5 предоставляет 5 методов итерации для массивов, все они являются функциями более высокого порядка, первый параметр — это функция, а второй параметр — это точка функции.
- every
- filter
- forEach
- map
- some
Эти API используются ежедневно, поэтому я не буду вдаваться в подробности, просто небольшая деталь
Вызов some вернет false для пустого массива, а вызов every вернет true, независимо от того, что возвращает функция в аргументе.
let arr = []
console.log(arr.some(()=>{})) // false
console.log(arr.every(()=>{})) // true
reduce
Уменьшение — это метод слияния. Я лично считаю, что это самый продвинутый метод использования в массивах. При правильном использовании он может выполнять очень мощные функции. Вот пример: сведение многомерных массивов.
const flat = function (depth = 1) {
let arr = Array.prototype.slice.call(this)
if(depth === 0 ) return arr
return arr.reduce((pre, cur) => {
if (Array.isArray(cur)) {
// 需要用 call 绑定 this 值,否则会指向 window
return [...pre, ...flat.call(cur,depth-1)]
} else {
return [...pre, cur]
}
}, [])
}
Также есть замечание по поводу индексов для редукции: когда редукция передает только один параметр, индекс индекса начинается с 1, который является вторым элементом массива (если массив в это время пуст, будет сообщено об ошибке). При передаче reduce второй параметр будет использоваться как начальное значение обхода, в это время нижний индекс индекса будет начинаться с 0, который является первым элементом массива.
let arr = ["b", "c", "d", "e"]
arr.reduce((pre, cur, index) => {
console.log(index)
return pre + cur
})
// 1
// 2
// 3
arr.reduce((pre, cur, index) => {
console.log(index)
return pre + cur
}, "a")
// 0
// 1
// 2
// 3
RegExp
Регулярные выражения можно генерировать динамически с помощью конструктора или быстро генерировать с помощью литералов. Поскольку экземпляры регулярных выражений также являются объектами, они также имеют атрибуты.
- global: установлен ли флаг g, то есть включено ли глобальное сопоставление
- ignoreCase: установлен ли флаг i, т.е. игнорируется регистр
- dotAll (ES9): установлен лиs(не d ) флаг, т.е. используя
.Может соответствовать любому одиночному символу, может пониматься как [\s\S] (по умолчанию.не будет соответствовать новой строке, возврату каретки, разделителям и т. д.) - lastIndex: позиция символа, с которой начинается поиск следующего совпадения, отсчитываемая от 0.
- источник: строковое представление текущего регулярного выражения
let reg = /\[abc]/ig
console.dir(reg)
let reg2 = new RegExp('\\[abc]', "ig") // RegExp 第二个参数为正则标志
console.dir(reg2)
console.log(reg.test("[abc]"), reg2.test("[abc]"))
Результат печати следующий
Функции, реализуемые reg и reg2, одинаковые, первая проще, вторая более гибкая, и ее нужно гибко использовать в сочетании с реальной ситуацией.
Кроме того, есть еще один важный момент: вы можете видеть, что lastIndex двух обычных объектов равен 5.Если вы продолжите использовать тестовый метод для сопоставления, он вернет false
let reg = /\[abc]/ig
console.dir(reg)
let reg2 = new RegExp('\\[abc]', "ig") // RegExp 第二个参数为正则标志
console.dir(reg2)
console.log(reg.test("[abc]"), reg2.test("[abc]"))
console.log(reg.test("[abc]"), reg2.test("[abc]"))
Причина, по которой это происходит, заключается в том, что свойство lastIndex, хранящееся в обычном объекте, будет определять позицию следующего регулярного совпадения. начать с 6-го параметра параметра.Элементы начинают совпадать.В это время обнаруживается, что ни один элемент не соответствует, поэтому он вернет false и сбросит lastIndex к значению по умолчанию 0
Закономерность на самом деле очень сложная.Будут задействованы точки углубленного знания, такие как конечный автомат, поиск с возвратом, жадное сопоставление и т. д. Плохое написание повлияет на производительность системы, но если вы сможете понять тайну и написать качественно регулярности, вы можете значительно освободить работу, например, заменить часть кода для всего проекта, а компиляция строки шаблона Vue также зависит от регулярного сопоставления для извлечения атрибутов, пользовательских инструкций и т. д.
Function
функции являются объектами, а имя функции используется только как указатель на функцию, о которой я также упоминал в предыдущей главе, JavaScript не позволяет напрямую манипулировать пространством памяти объекта, а все операции в разработке являются указателями на объекты кучи памяти
Функция может быть динамически сгенерирована с помощью нового ключевого слова
let func = new Function("a","console.log(a)")
console.log(func(123)) // 123
Когда функция Function используется в качестве конструктора, она принимает по крайней мере один параметр. Если передается только один параметр, параметр используется непосредственно как тело функции. Когда передается более одной функции, последний параметр используется как тело функции.Все предыдущие параметры будут аргументами сгенерированной функции
Преимущество динамического генерирования функций с помощью new заключается в большей гибкости.Например, компилятор Vue в конечном итоге будет передавать строки в код через new Function и выполнять их.
// src/compiler/to-function.js:11
function createFunction (code, errors) {
try {
return new Function(code)
} catch (err) {
errors.push({ err, code })
return noop
}
}
В общем, нам не нужно использовать этот метод, и создавать функции непосредственно в виде литералов, потому что хотя первый и более гибкий, его производительность не очень идеальна, и могут быть риски безопасности (аналогично eval, который может быть вредоносным Пользователь вводит вредоносный код для запуска, формируя XSS-атаку)
перегрузка
Функции в JavaScript не перегружаются, но могут достигать определенной степени перегрузки параметров.
import $ from 'jquery'
$("p").css("background-color"); // color
$("p").css("background-color",'red');
Вот код jquery. При вызове метода css для передачи параметра он вернет текущий цвет фона узла p. Если переданы два параметра, будет установлен цвет фона. Функция метода css зависит на количество переданных параметров. Принцип заключается в использовании количества параметров функции, чтобы определить, следует ли вернуть атрибут или установить атрибут
объявление функции, выражение функции
Когда JavaScript загружает данные (что также можно понимать как вход в новую среду или контекст), он сначала читает все объявления функций в среде, и это операция, выполняемая перед загрузкой кода, и когда все приготовления завершены, код будет выполняться построчно, то есть при выполнении кода до выражения функции функция будет фактически выполняться
func()
// 函数表达式
const func2 = function () {
console.log(2)
}
func2()
// 函数声明
function func() {
console.log(1)
}
Порядок выполнения: объявление func -> выполнение func -> объявление func2 -> выполнение func2
Перед входом в глобальную среду func продвигается на передний план из-за «продвижения объявления функции», а затем выполняется весь код, поэтому приведенный выше код не сообщит об ошибке, fun2 — это функциональное выражение, если код, выполняемый func2 помещается в func2 перед объявлением, возникает ошибка, потому что выражения функций не поднимаются
Есть еще несколько мелких деталей об объявлениях функций и выражениях функций:
- Если функция создается как объявление функции в глобальной среде, она будет рассматриваться как глобальная функция.
- Функциональные выражения можно понимать как создание анонимной функции, а затем назначение анонимной функции объявленной переменной.
- Вы можете использовать как объявления функций, так и выражения функций.
var sum = function sum() {
//...
sum() // 在函数内部 sum 指向的是右边的词法名称,而非左边的 sum 变量
}
правильноСумма будет использоваться как "лексическое имя" анонимной функции, которая часто используется для собственной рекурсии. Без этого лексического имени функция может использовать толькоarguments.calleeметод реализации рекурсии (нельзя использовать переменную суммы слева), а объект arguments внутри функции устарел из-за проблем с производительностью, поэтому, если есть требование рекурсии, рекомендуется добавить лексическое имя к анонимной функции.Также следует отметить, что лексическое имяпостоянный, который нельзя изменить внутри функции
Вопрос дняВ статье есть исследование этой точки знаний, а ниже приводится объяснение решателя проблем.
var b = 10;
(function b() {
// 内部作用域,会先去查找是有已有变量b的声明,有就直接赋值20,确实有了呀。发现了具名函数 function b(){},拿此b做赋值;
// IIFE的函数无法进行赋值(内部机制,类似const定义的常量),所以无效。
// (这里说的“内部机制”,想搞清楚,需要去查阅一些资料,弄明白IIFE在JS引擎的工作方式,堆栈存储IIFE的方式等)
b = 20;
console.log(b); // [Function b]
console.log(window.b); // 10,不是20
})();
length
Есть еще одна функцияlengthатрибут, который представляет количество формальных параметров, которые функция ожидает принять
Количество формальных параметров не включает количество остальных параметров, а только количество параметров до первого со значением по умолчанию.
function func(a,b,...c) {}
console.log(func.length) // 2
function func2(a = 1,b,c) {}
console.log(func2.length) // 0
function func2(a,b = 2,c) {}
console.log(func2.length) // 1
Видно, что свойство length первой функции равно 2, потому что остальные параметры не учитываются в длине длины, а вторая вернет a, так как параметр a имеет значение по умолчаниюДопараметр, и поскольку перед a нет параметра, он, наконец, возвращает 0. В третьем примере параметр b имеет значение по умолчанию, поэтому возвращается количество параметров до b, то есть 1
apply / call
функция во время выполненияОн также сгенерирует объект this, который можно понимать как указатель.В общем случае this указывает на объект, который вызывает функцию, и метод применения/вызова функции может изменить точку this (опять же, потому что функции также являются объектами , так что там тоже будут свойства и методы)
function func(a,b,c) {
console.log(a,b,c)
console.log(this)
}
func.call({a:1},1,2,3) // 1,2,3 {a:1}
func.call('123',1,2,3) // String{"123"} {a:1}
func.apply({a:1},[1,2,3]) // 1,2,3 {a:1}
Разница между apply и call заключается в том, что первый параметр apply — это значение this функции, которая должна быть выполнена, второй параметр — это массив или подобный массиву, представляющий параметры функции, которая должна быть выполнена, в то время как первый параметр вызов тот же, и второй параметр такой же.Последний параметр представляет параметр, который должен быть выполнен
То есть, apply будет использовать массив для сохранения параметров функции, а вызов будет разбит на плитки, в остальном нет никакой разницы (хотя метод вызова должен плитить параметры функции, но вы можете использовать оператор распространения ES6, чтобы записать его как массив, сейчас больше рекомендуется использовать call)
Кроме того, apply и call выполнит операцию упаковки первого параметра, то есть, если базовый тип передается и базовый тип имеет тип-оболочку (тип-оболочка будет подробно объяснен ниже), значение this равно тип-оболочка входящего базового типа. , в примере тип строки становится типом-оболочкой String
существуетв нестрогом режиме, если значение this равно null/undefined, оно будет автоматически указывать на глобальный объект окна, в то время как в строгом режиме такого поведения не будет (стоит отметить, что это не поведение apply/call)
function func() {
console.log(this)
}
func.call(undefined) // window 对象
function func2() {
"use strict"
console.log(this)
}
func2.call(undefined) // undefined
bind
Bind похож на метод apply/call, и это также метод, используемый для изменения этой точки функции, разница в том, что bind вернет функцию, привязанную к этой точке, а apply/call запустит ее напрямую. , Если вам нужно привязать эту точку, и если вы не хотите выполнять ее немедленно, вы можете использовать метод привязки, а затем вызывать связанную функцию, когда вам нужно ее использовать.
Первым параметром bind является этот указатель, а вторым и последующими параметрами являются параметры, переданные в связанную функцию заранее.Функция с предустановленными параметрами также называетсячастичная функция
function func(a,b,c,d) {
console.log(this)
console.log(a,b,c,d)
}
let boundFunc = func.bind({a:1},1,2)
boundFunc(3,4) // {a:1} 1,2,3,4
Через привязку заранее передаются параметры 1 и 2. Когда связанная функция вызывается, она заранее передает 1 и 2 в качестве первого и второго параметров. В это время параметры, переданные в функцию, будут использоваться как третий и третий параметры Четыре параметра, наконец, напечатайте 1, 2, 3, 4
Основной тип упаковки
Для облегчения манипулирования значениями примитивных типов ECMAScript предоставляет 3 специальных ссылочных типа:
- Boolean
- Number
- String
Они отличаются от boolean,number,string, вы можете обнаружить, что их первая буква заглавная, что означает, что они являются ссылочными типами, то есть объектами.
Расширенное программирование JS сказало:
Всякий раз, когда считывается значение базового типа, в фоновом режиме создается соответствующий объект базового типа-оболочки, что позволяет нам вызывать некоторые методы для управления данными.
var s1 = "some text"
var s2 = s1.substring(2)
Нам нужно знать, что базовый тип не имеет никакого метода, то есть строка «какой-то текст» не имеет метода подстроки, так почему же вторая строка кода не сообщает об ошибке?
Причина в том, что когда вторая строка кода обращается к переменной s1, содержащей строку, она находится в режиме чтения, пытаясь прочитать значение строки из памяти, а при доступе к строке в режиме чтения она будет следующие операции
- Создайте экземпляр типа String
- вызвать метод подстроки в экземпляре
- Вернуться к базовому примитивному примитивному типу
можно понять так
var s1 = "some text"
// 读取模式
s1 = new String("some text")
var s2 = s1.substring(2)
s1 = "some text" // 还原成基本类型
Тип оболочки String используется в качестве ссылочного типа и содержит метод подстроки, поэтому для выполнения метода необходимо преобразовать базовый тип в тип оболочки, присвоить возвращаемый результат переменной s2 и, наконец, восстановить s1. к исходному основному типу
Кроме тогоавтоматически созданТип оболочки (не объект, созданный активным вызовом new) будет существовать только в момент выполнения кода, а затем сразу же уничтожен
Непосредственный вызов функции String генерирует примитивный тип, а использование ключевого слова new для использования String в качестве конструктора создает тип-оболочку.
let str = String("abc") // "abc" string 基本类型
let wrappedStr = new String("abc") // String {"abc"} String 包装类型
let boolean = Boolean(true) // true boolean 基本类型
let wrappedBoolean = new Boolean(true) // Boolean {true} Boolean 包装类型
let number = Number(123) // 123 number 基本类型
let wrappedNumber = new Number(123) // Number {123} Number 包装类型
В общем, не рекомендуется активно генерировать типы упаковки, потому что их легко спутать с базовыми типами.
Тип упаковки номера
toFixed— это метод типа оболочки Number, который возвращает значение с указанным числом знаков после запятой.нитьУказывает, что когда значение меньше входящего параметра, оно будет округлено в большую сторону.
let num = 10
console.log(num.toFixed(2)) // "10.00"
let num2 = 1.68
console.log(num.toFixed(1)) // "1.7"
Но при использовании toFixed вам необходимо учитывать точность десятичных знаков Javascript.
let num = 1.335
console.log(num.toFixed(2)) // "1.33"
console.log(num.toFixed(50)) // "1.3349999999999999644..."
На самом деле число 1,335 на самом деле не хранится как 1,335 в нижней части языка.Возвратив 50 знаков после запятой методом toFixed, можно найти, что реальное значение 1,335 равно 1,3349999... После этого есть бесконечный цикл из-за максимальной точности, которую может представить JS. Длина равна 16, и все десятичные знаки будут иметь точность только до 16 знаков после запятой и автоматически округляться, поэтому после округления вы получите 1,335.
Поскольку представленное действительное число равно 1,3349999..., округленный результат toFixed равен 1,33, поскольку следующая цифра равна 4, и она округляется.
Тип оболочки строки
slice
Метод slice можно использовать как для типов массивов, так и для типов-оболочек String.Подробности см. в главе «Массивы» выше.
indexOf
Метод indexOf можно использовать как для типов массивов, так и для типов-оболочек String, он будет проходить с первой позиции, находить позицию параметра в строке (массиве) и возвращать индекс, а также принимать второй параметр для использования в Начать поиск после указанного места
let str = "hello world"
// 从下标 6 的位置开始寻找字符串 o
// 但返回值仍相对于整个字符串的位置
console.log(str.indexOf('o',6)) // 7
Хотя в ES6 есть более мощные методы, такие как include и find для поиска элементов, более удобно использовать indexOf, если вам нужно найти элементы из определенной позиции.Следующий пример вернет все индексы слова e в строке
let str = `
React makes it painless to create interactive UIs.
Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes
`
let arr = []
let pos = str.indexOf('e')
while (pos > -1) {
arr.push(pos)
pos = str.indexOf('e',pos + 1)
}
console.log(arr) // [6,14,25,34,37,42,49,62,73,77,85,94,122,132,138,149,156,159,169,183,190,208]
trim
Метод trim может удалить пробелы в начале и конце строки.Для некоторых входных данных формы пробелы не допускаются.Для их удаления можно использовать trim.При этом в ES10 есть два метода: trimStart и trimEnd , которые удаляют переднюю и заднюю часть строки соответственно.
replace
Метод replace может использоваться для замены строк в соответствии с параметрами, первый параметр может быть строкой или обычным, а второй параметр может быть строкой или функцией.
str.replace(regexp|substr, newSubStr|function)
Когда все параметры являются строками, просто найдите первый параметр в строке strпервое появление, и замените его вторым параметром
Если первый параметр является регулярным, будет заменена строка, соответствующая регулярной, в то же время, если регулярка содержит флаг g, будет выполнен глобальный поиск. не остановится, а продолжится. Поиск назад, чтобы увидеть, есть ли еще заменяемые строки
При этом второй параметр тоже можно передать в функцию, и совпавшая строка будет заменена возвращаемым значением функции.Введение функции делает метод замены более гибким
let str = "hello world"
console.log(str.replace('l','x')) // "hexlo world" 只将第一个 l 替换为 x
console.log(str.replace(/l/,'x')) // "hexlo world" 同上
console.log(str.replace(/l/g,'x')) // "hexxo worxd" 通过给正则添加全局搜索的标志符,可以实现全局替换
console.log(str.replace(/l/, (match,index,str) => {
console.log(match) // 'l' 匹配的子串
console.log(index) // 2 匹配到的子字符串在原字符串中的偏移量
console.log(str) // 'hello world' 被匹配的原字符串
return 'q' // 返回字符串 q 代表将第一个匹配到的字符串 l 替换为 q
})) // "heqlo world"
Кроме того, если первое регулярное выражение содержит захватываемую группу, то второй параметр также может получить захватываемую группу в предыдущем регулярном выражении.MDN
split
Что касается метода разделения, используемого для разделения строк, в дополнение к передаче строки, которую мы обычно используем, метод разделения также поддерживает передачу обычного значения в качестве параметра.если регулярное выражение, содержащее группы захвата, также поместит группу захвата в окончательный возвращаемый массив
let str = "hello world"
console.log(str.split(/(l)/)) // [ 'he', 'l', '', 'l', 'o wor', 'l', 'd' ]
Видно, что не только строка разделяется разделителем 'l', но и разделитель хранится в массиве
Монолитные встроенные объекты
На самом деле так называемой глобальной переменной или глобальной функции не существует. Все свойства и функции, определенные в глобальной области видимости, являются свойствами объекта Global, включая собственные ссылочные типы.
Причина, по которой это глобальный объект, а не объект окна, заключается в том, что объект окна существует только в браузере.В среде узла глобальный объект является глобальным, а в веб-воркере глобальным объектом является я. Глобальные объекты, все они используются как глобальные объекты.
// 在 node 环境运行以下代码
console.log(global) // node 中的全局对象 global
console.log(window) // 报错 window 对象不存在
// 在 webworker 中不允许操作 DOM,也没有 window 对象
существуетЧасть 1 из этой серииЯ упомянул, что на стороне браузера JavaScript состоит из трех частей.
- ECMAScript
- DOM
- BOM
Другими словами, некоторые методы не относятся к категории ECMAScript, например, методы alert и console, предоставляемые BOM, или createElement и appendChild, предоставляемые DOM, Другими словами, не только JavaScript, но и другие языки могут управлять DOM и консолью и т. д., браузеры предоставляют только интерфейс для доступа к ним
На этой неделе JavaScript Weekly порекомендовал мне хорошую статью о последних предложениях ECMAScript.globalThis, который существует на всех платформах, где работает JavaScript, и указывает на глобальный объект Global
Explaining the globalThis ES Proposal
Продолжение следует
использованная литература
Продвинутое программирование на JavaScript, 3-е издание
«JavaScript, которого вы не знаете»