Некоторые вещи очень полезны, но вы можете об этом не знать; некоторые вещи вы могли использовать, но не знали как.
Есть много способов достичь цели, как говорится, все дороги ведут в Рим. Много контента происходит из обычных подборок и замечательных комментариев под прошлыми статьями блога, собирайте и организуйте волну расширения, разнообразьте свое мышление и расширите свои знания.
Есть четыре варианта написания слова фенхель, 233333..., в конце текста пасхалки и сюрпризы.
1. Короткая и элегантная реализация функции сна
многие языки имеютsleep
функция, очевидноjs
Нет, так как же реализовать этот метод коротко и элегантно?
1.1 Обычное издание
function sleep(sleepTime) {
for(var start = +new Date; +new Date - start <= sleepTime;) {}
}
var t1 = +new Date()
sleep(3000)
var t2 = +new Date()
console.log(t2 - t1)
Достоинства: простой и грубый, понятный. Недостаток: Это самая простая и грубая реализация.Он действительно спит, и он действительно застревает.ЦП будет парить,независимо от того,насколько нибилен процессор вашего сервера.
1.2 Обещанная версия
function sleep(time) {
return new Promise(resolve => setTimeout(resolve, time))
}
const t1 = +new Date()
sleep(3000).then(() => {
const t2 = +new Date()
console.log(t2 - t1)
})
Преимущества: этот метод фактически использует setTimeout, который не вызывает блокировку процесса и не вызывает проблем с производительностью и нагрузкой. Недостатки: Хоть слоев и не так много, как callback-сетов, но все равно не очень красиво, и когда нам нужно остановить выполнение в каком-то процессе (или вернуть неверное значение посередине), мы тоже должны выскакивать после слоев из суждение, что очень хлопотно, и эта асинхронность не столь основательна, все равно выглядит несуразно.
1.3 Версия генератора
function sleep(delay) {
return function(cb) {
setTimeout(cb.bind(this), delay)
};
}
function* genSleep() {
const t1 = +new Date()
yield sleep(3000)
const t2 = +new Date()
console.log(t2 - t1)
}
async(genSleep)
function async(gen) {
const iter = gen()
function nextStep(it) {
if (it.done) return
if (typeof it.value === "function") {
it.value(function(ret) {
nextStep(iter.next(ret))
})
} else {
nextStep(iter.next(it.value))
}
}
nextStep(iter.next())
}
Преимущества: Те же преимущества, что и у Promise, кроме того, код становится очень простым и чистым, а не таким тупым и отвратительным, как тогда.
Недостатки: Но недостатки тоже очевидны, то есть каждый раз выполнять next() очень хлопотно, хотя и естьco(Сторонний пакет) решается, но добавляется лишний слой, что некрасиво, и на ошибку тоже надо нажиматьcoЛогика, с которой нужно иметь дело, не годится.
coНедаром он так популярен, конечно, не только для достиженияsleep
Такая скучная вещь, но она живаgenerator/yield
достигнуто очень похожееasync/await
Эффект! Это то, что действительно поражает меня.
const co = require("co")
function sleep(delay) {
return function(cb) {
setTimeout(cb.bind(this), delay)
}
}
co(function*() {
const t1 = +new Date()
yield sleep(3000)
const t2 = +new Date()
console.log(t2 - t1)
})
1.4 Асинхронная/ожидающая версия
function sleep(delay) {
return new Promise(reslove => {
setTimeout(reslove, delay)
})
}
!async function test() {
const t1 = +new Date()
await sleep(3000)
const t2 = +new Date()
console.log(t2 - t1)
}()
Преимущества: Те же преимущества, что и у Promise и Generator. Async/Await можно рассматривать как синтаксический сахар Generator.Async и Await более семантичны, чем * и yield.Кроме того, каждая функция плоская, не генерируется лишняя вложенность, а код чище и легче читается. Недостатки: синтаксис ES7 имеет проблемы с совместимостью, с Babel вся совместимость не проблема.
Что касаетсяAsync/Await
СравниватьPromise
а такжеGenerator
Преимущества могут относиться к этим двум статьям:
Четыре улучшения Async/Await по сравнению с Generator
6 причин заменить Promise на Async/Await
1.5 Не забывайте о силе открытого исходного кода
Как элегантно написать сон в javascript равно элегантно и неэлегантно, 2333
Вот модули, реализованные на C++:GitHub.com/Erik dub be lb…
const sleep = require("sleep")
const t1 = +new Date()
sleep.msleep(3000)
const t2 = +new Date()
console.log(t2 - t1)
Преимущества: он может обеспечить более точную точность времени и выглядит как настоящая функция сна, четкая и понятная.
Недостатки: Недостатки необходимо установить этот модуль,^_^
, что нельзя считать недостатком.
Из простой функции сна мы можем мельком увидеть леопарда и увидеть быстрое развитие JavaScript в последние годы, не только асинхронного программирования, но и различных новых технологий и новых фреймворков, свидетельствующих о развитии JavaScript.
Возможности, которые вы не знали о фронтенде: Async/Await в настоящее время является самым элегантным способом асинхронного написания фронтенда.
2, получить метку времени
Первый выше реализован несколькими способамиsleep
функция, мы можем найти, что код имеет+new Date()
Использование получения метки времени, это только один из них, давайте поговорим о двух других и+new Date()
принцип.
2.1 Обычное издание
var timestamp=new Date().getTime()
Достоинства: универсален, этим пользуются все Недостаток: пока не нашел
2.2 Advanced Edition.
var timestamp = (new Date()).valueOf()
Метод valueOf возвращает примитивное значение объекта (Primitive,'Null','Undefined','String','Boolean','Number'один из пяти основных типов данных), которое может быть строкой, числовым значением или логическое значение и т. д. См. конкретный объект.
Преимущества: это показывает, что у разработчика есть особое понимание исходной ценности, что заставляет людей сиять. Недостатки: Пока не нашел
2.3 Окончательное издание
var timestamp = +new Date()
Преимущества: более четкое понимание неявных преобразований JavaScript. Недостатки: пока не найдено.
Теперь коротко разберем, почему+new Date()
Получите метку времени.
Одним словом, это метафизика неявного преобразования, а метод valueOf() по-прежнему вызывается по существу.
давайте сначала посмотримECMAScript
Спецификация для унарных операторов:
Унарный + оператор
Один юань+
оператор преобразует свой операнд вNumber
введите и поменяйте его знак. Обратите внимание на негатив+0
производить-0
,минус-0
производить+0
. производствоUnaryExpression : - UnaryExpression
Следуйте приведенной ниже процедуре.
- Пусть expr будет результатом интерпретации выполнения UnaryExpression.
- Пусть oldValue будет ToNumber(GetValue(expr)).
- Если oldValue равно NaN, вернуть NaN.
- Возвращает отрицательное значение oldValue (то есть возвращает значение с тем же числом, но с противоположным знаком).
+новая дата() эквивалентна ToNumber(новая дата())
Посмотрим еще разECMAScript
каноническая параToNumber
Определение:
мы знаемnew Date()
объект, который удовлетворяет вышеизложенномуToPrimitive()
, поэтому становитсяToPrimitive(new Date())
.
Тогда давайте посмотримECMAScript
каноническая параToPrimitive
Определение , приходит слой за слоем, срывает кокон.
этоToPrimitive
Сначала это может быть нелегко понять, поэтому позвольте мне объяснить:
ToPrimitive(obj,preferredType)
JavaScript
Внутренне преобразовано в примитивные значения движкомToPrimitive(obj,preferredType)
Функция принимает два параметра, первыйobj
это преобразованный объект, второйpreferredType
это тип, в который вы хотите преобразовать (по умолчанию пусто, принятое значениеNumber
илиString
)
в исполненииToPrimitive(obj,preferredType)
когда второй параметр пуст иobj
дляDate
Примеры того, когда в это времяpreferredType
будет установлен наString
, иначеpreferredType
будет установлен наNumber
еслиpreferredType
дляNumber
,ToPrimitive
Процесс выполнения следующий:
- Если obj является примитивным значением, возвращайтесь напрямую;
- В противном случае вызовите obj.valueOf(), если результатом выполнения является исходное значение, верните его;
- В противном случае вызовите obj.toString(), если результатом выполнения является исходное значение, верните его;
- В противном случае сгенерируйте исключение.
еслиpreferredType
дляString
, вышеперечисленные шаги 2 и 3 меняются местами, а именно:
- Если obj является примитивным значением, возвращайтесь напрямую;
- В противном случае вызовите obj.toString(), если результатом выполнения является исходное значение, верните его;
- В противном случае вызовите obj.valueOf(), если результатом выполнения является исходное значение, верните его;
- В противном случае сгенерируйте исключение.
Сначала мы должны понятьobj.valueOf()
а такжеobj.toString()
Также есть то, что означает исходное значение, что является одной из предпосылок для понимания приведенного выше описания:
toString
Используется для возврата строкового представления объекта.
var obj = {};
console.log(obj.toString());//[object Object]
var arr2 = [];
console.log(arr2.toString());//""空字符串
var date = new Date();
console.log(date.toString());//Sun Feb 28 2016 13:40:36 GMT+0800 (中国标准时间)
valueOf
Метод возвращает исходное значение объекта, которое может быть строкой, числом илиbool
стоимость и т.д., в зависимости от конкретного объекта.
var obj = {
name: "obj"
}
console.log(obj.valueOf()) //Object {name: "obj"}
var arr1 = [1]
console.log(arr1.valueOf()) //[1]
var date = new Date()
console.log(date.valueOf())//1456638436303
如代码所示,三个不同的对象实例调用valueOf返回不同的数据
Исходное значение относится к'Null','Undefined','String','Boolean','Number','Symbol'
Один из 6 основных типов данных, концепция которого упоминалась выше и повторяется здесь.
Наконец, разбейте процесс:+new Date():
- оператор
new
имеет более высокий приоритет, чем унарные операторы+
, поэтому процесс можно разложить на:
var time=new Date();
+time- Согласно упомянутым выше правилам эквивалентен:
ToNumber(time)
time
является объектом даты, согласноToNumber
Правила преобразования , поэтому это эквивалентно:ToNumber(ToPrimitive(time))
- согласно с
ToPrimitive
Правила преобразования для:ToNumber(time.valueOf())
,time.valueOf()
То есть исходное значение является отметкой времени, предполагая, чтоtime.valueOf()=1503479124652
- так
ToNumber(1503479124652)
Возвращаемое значение1503479124652
этот номер.- Анализ завершен
Точки знаний о внешнем интерфейсе, о которых вы могли не знать: магия неявного преобразования
3. Дедупликация массива
Примечание: пока не рассматривается对象字面
количество,函数
Дождитесь дедупликации ссылочных типов и не считайтеNaN
, undefined
, null
и другие специальные виды.
Образцы массива: [1, 1, '1', '2', 1]
3.1 Обычное издание
无需思考,我们可以得到 O(n^2) 复杂度的解法。定义一个变量数组 res 保存结果,遍历需要去重的数组,如果该元素已经存在在 res 中了,则说明是重复的元素,如果没有,则放入 res 中。
var a = [1, 1, '1', '2', 1]
function unique(arr) {
var res = []
for (var i = 0, len = arr.length; i < len; i++) {
var item = arr[i]
for (var j = 0, len = res.length; j < jlen; j++) {
if (item === res[j]) //arr数组的item在res已经存在,就跳出循环
break
}
if (j === jlen) //循环完毕,arr数组的item在res找不到,就push到res数组中
res.push(item)
}
return res
}
console.log(unique(a)) // [1, 2, "1"]
Преимущества: нет проблем с совместимостью, легко понять, не требует затрат на понимание.
Недостатки: выглядит раздутым и громоздким, временная сложность относительно высока.O(n^2)
3.2 Расширенная версия
var a = [1, 1, '1', '2', 1]
function unique(arr) {
return arr.filter(function(ele,index,array){
return array.indexOf(ele) === index//很巧妙,这样筛选一对一的,过滤掉重复的
})
}
console.log(unique(a)) // [1, 2, "1"]
Достоинства: очень лаконичный, продуманный, интуитивно понятный и простой для понимания.
Недостаток: не поддерживаетсяIE9
Для следующих браузеров временная сложность по-прежнемуO(n^2)
3.3 Временная сложность O(n)
var a = [1, 1, '1', '2', 1]
function unique(arr) {
var obj = {}
return arr.filter(function(item, index, array){
return obj.hasOwnProperty(typeof item + item) ?
false :
(obj[typeof item + item] = true)
})
}
console.log(unique(a)) // [1, 2, "1"]
преимущество:hasOwnProperty
Является методом проверки существования свойства (имени) объекта. Свойства объекта могут быть основаны наHash
реализация таблицы, поэтому временная сложность доступа к свойствам может достигатьO(1)
;
filter
Это метод итерации массива, и он по-прежнемуfor
петля, поэтому временная сложностьO(n)
.
Недостатки: не совместимIE9
Следующие браузеры на самом деле легко решаются, поставьтеfilter
методfor
Вместо этого зациклите или смоделируйте метод фильтра самостоятельно.
3.4 Окончательное издание
Взяв в качестве примера Set, ES6 предоставляет новую структуру данных Set. Он похож на массив, но все значения членов уникальны и нет повторяющихся значений.
const unique = a => [...new Set(a)]
преимущество:ES6
Синтаксис, лаконичный и эффективный, мы видим, что метод дедупликации исходный14
строка кода дляES6
из1
Строка кода, по сути, также показываетJavaScript
Этот язык постоянно совершенствуется, и я верю, что дальнейшее развитие будет становиться все более и более эффективным.
Недостатки: Проблемы с совместимостью, поддерживается только современными браузерами, даbabel
Это всего лишь мелкие препятствия.
Знания внешнего интерфейса, о которых вы могли не знать: новая структура данных ES6 Установить дедупликацию
4. Числовой формат 1234567890 --> 1 234 567 890
Издание 4.1
function formatNumber(str) {
let arr = [],
count = str.length
while (count >= 3) {
arr.unshift(str.slice(count - 3, count))
count -= 3
}
// 如果是不是3的倍数就另外追加到上去
str.length % 3 && arr.unshift(str.slice(0, str.length % 3))
return arr.toString()
}
console.log(formatNumber("1234567890")) // 1,234,567,890
Преимущества: я чувствую себя более ясной и прямолинейной, чем логика кучи циклов for и суждений if-else, написанных в Интернете. Недостатки: слишком обычный
4.2 Расширенная версия
function formatNumber(str) {
// ["0", "9", "8", "7", "6", "5", "4", "3", "2", "1"]
return str.split("").reverse().reduce((prev, next, index) => {
return ((index % 3) ? next : (next + ',')) + prev
})
}
console.log(formatNumber("1234567890")) // 1,234,567,890
Достоинства: Я очень хорошо знаю API JS
4.3 Обычная версия
function formatNumber(str) {
return str.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}
console.log(formatNumber("123456789")) // 1,234,567,890
Ниже приводится простой анализ регулярного/\B(?=(\d{3})+(?!\d))/g
:
/\B(?=(\d{3})+(?!\d))/g
: Регулярная граница совпадения\B
Следовать за границей(\d{3})+(?!\d)
;(\d{3})+
: должно быть 1 или более из 3 последовательных чисел;(?!\d)
: 3 числа на шаге 2 не могут сопровождаться числами;(\d{3})+(?!\d)
: поэтому за согласованной границей должен следовать3*n
(n>=1) число.
Наконец, замените все совпадающие границы на,
для достижения цели.
Преимущества: меньше кода, суть сжата. Недостатки: необходимо иметь более глубокое понимание сопоставления позиций регулярных выражений, порог больше.
4.4 Версия API
(123456789).toLocaleString('en-US') // 1,234,567,890
На фото вы можете не знатьJavaScript
изtoLocaleString
Можно еще так играть.
также можно использовать Международные объекты — MDN
Объект Intl — это пространство имен для API интернационализации ECMAScript, которое обеспечивает точное сравнение строк, форматирование чисел, а также форматирование даты и времени. Конструкторы для объектов Collator, NumberFormat и DateTimeFormat являются свойствами объекта Intl.
new Intl.NumberFormat().format(1234567890) // 1,234,567,890
Достоинства: просто и грубо, вызов API напрямую
недостаток:Международная совместимостьНе очень хорошо, но IE6 поддерживает toLocaleString.
Элементы знаний о внешнем интерфейсе, о которых вы могли не знать: объекты Intl и методы toLocaleString.
5, замена двух целых чисел
пусть a = 3,b = 4 становится a = 4, b = 3
5.1 Обычное издание
Во-первых, самый обычный способ - ввести временную промежуточную переменную
let a = 3,b = 4
let temp = a
a = b
b = temp
console.log(a, b)
Преимущества: это лучшее преимущество, чтобы понять с первого взгляда. Недостаток: недостаток в том, что вводится дополнительная переменная.
5.2 Расширенная версия
Взаимодействие двух переменных без введения промежуточных переменных
let a = 3,b = 4
a += b
b = a - b
a -= b
console.log(a, b)
Достоинства: По сравнению с тем, что выше, который не вводит избыточных переменных, он немного умнее, чем тот, что выше Недостатки: Конечно, недостатки тоже очевидны Переполнение целочисленных данных, например, для 32-битных символов, максимальное представление чисел со знаком 2147483647. Это Math.pow(2,31)-1.Если это 2147483645 и 2147483646, обмен завершится ошибкой.
5.3 Окончательное издание
Использование числа XOR само по себе равно 0, и операция XOR соответствует обменному курсу.
let a = 3,b = 4
a ^= b
b ^= a
a ^= b
console.log(a, b)
Ниже приводится простое описание в вертикальном формате: (десятичное в двоичное)
a = 011
(^) b = 100
则 a = 111(a ^ b的结果赋值给a,a已变成了7)
(^) b = 100
则 b = 011(b^a的结果赋给b,b已经变成了3)
(^) a = 111
则 a = 100(a^b的结果赋给a,a已经变成了4)
Из вертикальной формы выше мы можем ясно видеть основной процесс использования операции XOR для реализации обмена двумя значениями.
Давайте проанализируем это подробно:
1. Для первых двух операторов присваивания a = a ^ b, b = b ^ a, что эквивалентно b = b ^ (a ^ b) = a ^ b ^ b, а b ^ b, очевидно, равно 0 . Таким образом, b = a^0, очевидно, результат равен a. 2. Аналогичным образом можно проанализировать третий оператор присваивания: a = a ^ b = (a ^ b) ^ a = b
Примечание:
- ^ — это оператор «исключающее или».
Это означает судить, являются ли два соответствующих битовых значения «различными», если они «различны» (значение отличается), это будет истина (1); в противном случае это ложь (0).
- Характеристика оператора ^ состоит в том, чтобы выполнять XOR с 0, сохраняя исходное значение; XOR с самим собой, результат равен 0.
Преимущества: промежуточные переменные не вводятся, и целочисленное переполнение отсутствует. Недостатки: фронтальная битовая операция может быть не совсем понятной и непростой для понимания.
5.4 Окончательное издание
знакомыйES6
Специалисты по грамматике, безусловно, знакомы с деструктурированием.
var a = 3,b = 4;
[b, a] = [a, b]
Принцип деконструкции, я еще не читал спецификацию ES6, поэтому не знаю конкретных правил, но мы можем взглянутьbabel
Он компилируется сам собой, мы видим путь.
Ха-ха, просто и грубо, я не знаю, соответствует ли это спецификациям ES, но вы действительно можете взглянуть на исходный код версии 8. Chrome уже реализовал это использование деконструкции.
Чем этот пример отличается от стиля написания предыдущего примера?, если вы будете внимательны, то обнаружите, что у этих двух строк кода есть еще однаточка с запятой, для чистого фрика вроде меня, который не пишет точки с запятой в коде, на самом деле есть причина, по которой точка с запятой добавлена здесь.Вот простая популяризация.Рекомендуется по-прежнему писать код и ставить точки с запятой..
5.4 Автоматическая точка с запятой ECMAScript; вставить (как дополнение, чтобы в будущем никто не наступал на яму)
Хотя JavaScript имеет стиль кода C, он не требует использования точек с запятой в коде и фактически может их опускать.
JavaScript не является языком без точек с запятой, наоборот, он требует точек с запятой для разбора исходного кода. Таким образом, синтаксический анализатор JavaScript автоматически вставляет точку с запятой в исходный код, когда обнаруживает ошибку синтаксического анализа из-за отсутствия точки с запятой.
5.4.1 Примеры
var foo = function() {
} // 解析错误,分号丢失
test()
Автоматически вставляется точка с запятой, и синтаксический анализатор выполняет повторный анализ.
var foo = function() {
}; // 没有错误,解析继续
test()
5.4.2 Работы
В приведенном ниже коде нет точек с запятой, поэтому синтаксическому анализатору нужно выяснить, где их вставлять.
(function(window, undefined) {
function test(options) {
log('testing!')
(options.list || []).forEach(function(i) {
})
options.value.test(
'long string to pass here',
'and another long string to pass'
)
return
{
foo: function() {}
}
}
window.test = test
})(window)
(function(window) {
window.someLibrary = {}
})(window)
Ниже представлен результат «угадывания» парсера.
(function(window, undefined) {
function test(options) {
// 没有插入分号,两行被合并为一行
log('testing!')(options.list || []).forEach(function(i) {
}); // <- 插入分号
options.value.test(
'long string to pass here',
'and another long string to pass'
); // <- 插入分号
return; // <- 插入分号, 改变了 return 表达式的行为
{ // 作为一个代码段处理
foo: function() {}
}; // <- 插入分号
}
window.test = test; // <- 插入分号
// 两行又被合并了
})(window)(function(window) {
window.someLibrary = {}; // <- 插入分号
})(window); //<- 插入分号
Парсер существенно изменил поведение кода выше, а в других случаях обработал его некорректно.
5.4.3 Правила ECMAScript для автоматической вставки точки с запятой
Обратимся к главе 7.9, чтобы увидеть механизм и принцип вставки точки с запятой.Понятно, что только написав, можно стараться в дальнейшем как можно меньше наступать на ямы.
**Некоторые операторы ECMAScript (пустой оператор, оператор объявления переменной, оператор выражения, оператор do-while, оператор continue, оператор break, оператор return, оператор throw) должны заканчиваться точкой с запятой. Эти точки с запятой всегда явно отображаются в исходном тексте. Однако для удобства в некоторых случаях эти точки с запятой могут быть опущены в исходном тексте. Описывая эту ситуацию, можно сказать: в этом случае точка с запятой автоматически вставляется в поток токенов исходного кода. **
Это все еще относительно абстрактно. Не беда, если вы этого не понимаете. Давайте рассмотрим практические примеры и обобщим несколько правил.превратить абстрактное в конкретное.
Прежде всего, эти правила основаны на двух моментах:
- в обмен на основу;
- Синтаксический анализатор попытается объединить новую строку с текущей строкой и обработает новую строку как отдельный оператор тогда и только тогда, когда она соответствует правилам ASI.
5.4.3.1 Правила АСИ
1. Объединение новой строки с текущей будет считаться недопустимым оператором, и точка с запятой будет вставлена автоматически.
if(1 < 10) a = 1
console.log(a)
// 等价于
if(1 < 10) a = 1;
console.log(a);
2. Автоматически вставлять точку с запятой после continue, return, break, throw
return
{a: 1}
// 等价于
return;
{a: 1};
3. Выражение суффикса ++, -- используется в качестве начала новой строки, а в начале строки автоматически вставляется точка с запятой.
a
++
c
// 等价于
a;
++c;
4. В последний оператор блока кода автоматически вставляется точка с запятой.
function(){ a = 1 }
// 等价于
function(){ a = 1; }
5.4.3.2 Правила отсутствия ASI
1. Новая строка начинается с (
var a = 1
var b = a
(a+b).toString()
// 会被解析为以a+b为入参调用函数a,然后调用函数返回值的toString函数
var a = 1
var b =a(a+b).toString()
2. Новая строка начинается с [
var a = ['a1', 'a2']
var b = a
[0,1].slice(1)
// 会被解析先获取a[1],然后调用a[1].slice(1)。
// 由于逗号位于[]内,且不被解析为数组字面量,而被解析为运算符,而逗号运算符会先执
行左侧表达式,然后执行右侧表达式并且以右侧表达式的计算结果作为返回值
var a = ['a1', 'a2']
var b = a[0,1].slice(1)
3. Новые линии/старт
var a = 1
var b = a
/test/.test(b)
// /会被解析为整除运算符,而不是正则表达式字面量的起始符号。浏览器中会报test前多了个.号
var a = 1
var b = a / test / .test(b)
4. Новые строки начинаются с + , - , % и *
var a = 2
var b = a
+a
// 会解析如下格式
var a = 2
var b = a + a
5. Новая строка начинается с , или .
var a = 2
var b = a
.toString()
console.log(typeof b)
// 会解析为
var a = 2
var b = a.toString()
console.log(typeof b)
На данный момент у нас есть определенное понимание правил ASI, и есть еще одна интересная вещь, а именно «пустой оператор».
// 三个空语句
;;;
// 只有if条件语句,语句块为空语句。
// 可实现unless条件语句的效果
if(1>2);else
console.log('2 is greater than 1 always!');
// 只有while条件语句,循环体为空语句。
var a = 1
while(++a < 100);
5.4.4 Заключение
Рекомендуется никогда не опускать точку с запятой, а также рекомендуется помещать фигурные скобки и соответствующее выражение в одну строку, а фигурные скобки не следует опускать для выражения if или else только с одной строкой кода. Эти передовые методы программирования относятся не только к согласованности кода, но и к обработке ошибок, которая не позволяет синтаксическому анализатору изменять поведение кода.
Следует ли добавлять точку с запятой после оператора JavaScript? (нажмите на меня, чтобы посмотреть)Мы можем взглянуть на мнения больших коров на Zhihu по этому вопросу.
Элементы знаний о внешнем интерфейсе, о которых вы могли не знать: исходный JavaScript также имеет битовые операции и использование точек с запятой.
6. Преобразуйте объект аргументов (подобный массиву) в массив
{0:1,1:2,2:3,length:3}
Эта форма принадлежит массиву классов, который представляет собой объект, отсортированный в соответствии с нижним индексом массива, и существуетlength
Свойства, иногда нам нужен такой объект, чтобы иметь возможность вызывать метод под массивом, в это время нам нужно преобразовать массив класса в реальный массив.
6.1 Обычное издание
var makeArray = function(array) {
var ret = []
if (array != null) {
var i = array.length
if (i == null || typeof array === "string") ret[0] = array
else while (i) ret[--i] = array[i];
}
return ret
}
makeArray({0:1,1:2,2:3,length:3}) //[1,2,3]
Плюсы: Универсальная версия без каких-либо проблем с совместимостью Минусы: Слишком часто
6.2 Расширенная версия
var arr = Array.prototype.slice.call(arguments);
Это должен быть наиболее часто используемый метод, который использовали все. Что касается того, почему его можно использовать таким образом, многие люди, вероятно, мало что о нем знают. В любом случае, я вижу, что все используют его таким образом, и я использую его так же. Чтобы узнать почему, давайте поговорим о спецификации и исходном коде.
Согласно стандартному процессу, вы можете понять, посмотрев вывод самостоятельно:
Английский 15.4.4.10 Array.prototype.slice (начало, конец)
Китайская версия 15.4.4.10 Array.prototype.slice (начало, конец)
Если вы хотите знатьJavaScript
изsort
Механизм сортировки, какой сорт лучше, и какой используется, тоже видно из спецификации.
В официальном объяснении, например [mdn]
The slice() method returns a shallow copy of a portion of an array into a new array object.
Проще говоря, возвращает часть массива по параметрам.copy
. Поэтому разберитесь с его внутренней реализацией, чтобы определить, как он работает. так что проверяйV8
в исходном кодеArray.js
Вы можете увидеть следующий код:
методArraySlice
,Адрес источника, первый660
строку, добавить непосредственно вArray.prototype
«Вход» наSparseSlice
а такжеSimpleSlice
иметь дело с.
slice.call
Принцип роли заключается в том, что утилизацияcall
,Будуslice
метод работает наarrayLike
,slice
Два параметра пусты,slice
Внутренний разбор делаетarguments.lengt
Когда он равен 0, это эквивалентно обработкеslice(0)
: т.е. выбрать весь массив,slice
Внутри метода не должно быть обязательного суждения.Array
Типы,slice
Возвращается только что созданный массив (используя цикл для получения значения)», так что это реализует преобразование массива класса в массив,call
этот удивительный метод,slice
обработка необязательна.
смотреть прямоslice
Как этого добиться. На самом деле, это будетarray-like
Объект помещается в новыйArray
в:
// This will work for genuine arrays, array-like objects,
// NamedNodeMap (attributes, entities, notations),
// NodeList (e.g., getElementsByTagName), HTMLCollection (e.g., childNodes),
// and will not fail on other DOM objects (as do DOM elements in IE < 9)
Array.prototype.slice = function(begin, end) {
// IE < 9 gets unhappy with an undefined end argument
end = (typeof end !== 'undefined') ? end : this.length;
// For native Array objects, we use the native slice function
if (Object.prototype.toString.call(this) === '[object Array]'){
return _slice.call(this, begin, end);
}
// For array like object we handle it ourselves.
var i, cloned = [],
size, len = this.length;
// Handle negative value for "begin"
var start = begin || 0;
start = (start >= 0) ? start : Math.max(0, len + start);
// Handle negative value for "end"
var upTo = (typeof end == 'number') ? Math.min(end, len) : len;
if (end < 0) {
upTo = len + end;
}
// Actual expected size of the slice
size = upTo - start;
if (size > 0) {
cloned = new Array(size);
if (this.charAt) {
for (i = 0; i < size; i++) {
cloned[i] = this.charAt(start + i);
}
} else {
for (i = 0; i < size; i++) {
cloned[i] = this[start + i];
}
}
}
return cloned;
};
Преимущества: наиболее часто используемая версия с хорошей совместимостью. Недостатки: младшая версия ie не может обрабатывать вызов среза коллекции dom в массив. (Хотя у него числовое значение ключа и длина соответствует определению ArrayLike, но сообщается об ошибке) Поиск данных, я получаю: Поскольку объект dom под ie реализован в виде объекта com, объект js и COM-объект не может быть преобразован.
6.3 Версия ES6
использоватьArray.from
, значение требует, чтобы объект имелlength
свойство, вы можете преобразовать его в массив
var arr = Array.from(arguments);
спред оператор
var args = [...arguments];
ES6
Оператор распространения в ... также может преобразовывать некоторые структуры данных в массивы, которые должны иметь удобный интерфейс.
Преимущества: прямое использование встроенного API, простота и удобство обслуживания.
Недостатки: совместимость, использование преобразования профилей Babel может увеличить код и пакет файлов.
Точки знаний о внешнем интерфейсе, о которых вы могли не знать: конкретный принцип метода среза
7. Число округлено 2,33333 => 2
7.1 Обычное издание
const a = parseInt(2.33333)
parseInt()
Функция анализирует строковый аргумент и возвращает целое число по указанной системе счисления (основа математической системы). Эта оценка является наиболее распространенным методом прямого округления.
больше оparseInt()
функцию можно посмотретьДокументация MDN
7.2 Расширенная версия
const a = Math.trunc(2.33333)
Math.trunc()
Метод удалит дробную часть числа и сохранит только целую часть.
Особо следует отметить:Internet Explorer
Этот метод не поддерживается, но напишитеPolyfill
Тоже очень просто:
Math.trunc = Math.trunc || function(x) {
if (isNaN(x)) {
return NaN;
}
if (x > 0) {
return Math.floor(x);
}
return Math.ceil(x);
};
Математические вопросы лучше решаются с помощью математических методов.
7.3 Черная версия технологии
7.3.1 ~~number
Оператор двойная тильда ~~ также известен как оператор «двойного побитового НЕ». Обычно вы можете использовать это как более быстрый метод вместо Math.trunc() .
console.log(~~47.11) // -> 47
console.log(~~1.9999) // -> 1
console.log(~~3) // -> 3
console.log(~~[]) // -> 0
console.log(~~NaN) // -> 0
console.log(~~null) // -> 0
Возвращает 0 в случае ошибки, что может быть хорошей заменой при устранении ошибок преобразования Math.trunc(), возвращающих NaN. Но когда диапазон чисел превышает ±2^31−1, то есть: 2147483647, возникает исключение:
// 异常情况
console.log(~~2147493647.123) // -> -2147473649 🙁
7.3.2 number | 0
|(Побитовое ИЛИ) Выполняет операцию ИЛИ (ИЛИ) над каждой парой битов.
console.log(20.15|0); // -> 20
console.log((-20.15)|0); // -> -20
console.log(3000000000.15|0); // -> -1294967296 🙁
7.3.3 number ^ 0
^ (побитовое исключающее ИЛИ), которое выполняет операцию исключающее ИЛИ (XOR) для каждой пары битов.
console.log(20.15^0); // -> 20
console.log((-20.15)^0); // -> -20
console.log(3000000000.15^0); // -> -1294967296 🙁
7.3.4 number << 0
Оператор
console.log(20.15 < < 0); // -> 20
console.log((-20.15) < < 0); //-20
console.log(3000000000.15 << 0); // -> -1294967296 🙁
Вышеупомянутые методы побитовых операторов работают очень быстро и очень полезны, когда вы выполняете миллионы таких операций, которые значительно быстрее, чем другие методы. Но код менее читаем. Также следует обратить внимание на особый момент: при работе с относительно большими числами (когда диапазон чисел превышает ±2^31−1, то есть: 2 147 483 647) будут некоторые исключения. Явно проверяйте диапазон входных значений при использовании.
8. Суммирование массива
8.1 Обычное издание
let arr = [1, 2, 3, 4, 5]
function sum(arr){
let x = 0
for(let i = 0; i < arr.length; i++){
x += arr[i]
}
return x
}
sum(arr) // 15
Достоинства: понятный, простой и грубый Недостатки: без ярких пятен, слишком популярный
8.2 Элегантное издание
let arr = [1, 2, 3, 4, 5]
function sum(arr) {
return arr.reduce((a, b) => a + b)
}
sum(arr) //15
Преимущества: простой и понятный, метод итератора массива понятен и интуитивно понятен Недостатки: не совместим с браузерами ниже IE 9
8.3 Ultimate Edition.
let arr = [1, 2, 3, 4, 5]
function sum(arr) {
return eval(arr.join("+"))
}
sum(arr) //15
Преимущества: То, что люди не понимают какое-то время, — это «хороший путь». недостаток:
eval не легко отлаживать. Инструменты отладки, такие как chromeDev, не могут сломать точечную отладку, поэтому неприятные вещи не рекомендуются...
Проблемы с производительностью, в старых браузерах, если вы используете eval, производительность упадет в 10 раз. В современных браузерах есть два режима компиляции: быстрый путь и медленный путь. Быстрый путь — компилировать стабильный и предсказуемый код. И, очевидно, eval непредсказуем, поэтому будет использоваться медленный путь, поэтому он будет медленным.
больше оeval
Обсуждение может следовать этой статье:Почему eval устарел в JavaScript?
Точки знаний о внешнем интерфейсе, о которых вы могли не знать: правила использования eval
наконец
Счастливого Рождества всем, Добро пожаловать, чтобы добавить и обменять.