1. Введение
С фронтендом я знаком уже несколько лет со времен колледжа.По моим впечатлениям, для программистов, если они хотят повысить свой технический уровень и писать код, который легко читать и поддерживать, я не думаю, что они Вы можете писать посредственный код каждый день, но еще более необходимо внимательно изучать, исследовать и оптимизировать код, обобщать навыки и активно прислушиваться к предложениям других людей, чтобы ваш технический уровень повышался быстрее. Итак, сегодня я поделюсь некоторыми практическими навыками и предложениями по написанию javascript здесь. Эти навыки и предложения - это то, что я обычно использую в проектах разработки. Роль обмена мнениями, то есть, если у вас есть хорошие навыки или предложения, добро пожаловать поделиться, или если вы думаете, что есть какие-то проблемы с моими идеями, пожалуйста, укажите!
2. Более короткий массив для перезаписи метода
[...new Set([2,"12",2,12,1,2,1,6,12,13,6])]
//[2, "12", 12, 1, 6, 13]
//es6的新特性
3. Объект глубокого и поверхностного копирования
По поводу глубокой и мелкой копии объекта, мое личное мнение, есть несколько моментов:
1. Глубокое копирование и мелкое копирование предназначены только для данных ссылочного типа, таких как объект и массив.
2. Поверхностная копия заключается в копировании ссылочного адреса объекта и не открывает новый стек, то есть результатом копирования является то, что два объекта указывают на один и тот же ссылочный адрес, изменяются свойства одного из объектов. , свойства другого объекта также будут изменены.
3. Глубокая копия — открыть новый стек, два объекта соответствуют двум разным ссылочным адресам, изменение свойств одного объекта не изменит свойства другого объекта.
мелкая копия
var myInfo={name:'守候',sex:'男'};
var newInfo=myInfo;
newInfo.sex='女';
console.log(myInfo) //{name: "守候", sex: "女"}
поддельная глубокая копия
Подделка-глубокая копия Это я назвал, просто взгляните на это, не принимайте всерьез!
var myInfo={name:'守候',sex:'男'};
var newInfo=Object.assign({},myInfo)
newInfo.sex='女';
console.log(myInfo) //{name: "守候", sex: "男"}
console.log(newInfo) //{name: "守候", sex: "女"}
истинная глубокая копия
Правда - это глубокая копия с собственным неймингом, похоже, не воспринимайте всерьез!
Посмотрите на неглубокую копию, разница очень простая, а вот глубокая копия топа проблематична. Посмотрите на случай
var arr=[{a:1,b:2},{a:3,b:4}]
var newArr=Object.assign([],arr)
//截断数组
newArr.length=1
console.log(newArr)//[{a:1,b:2}]
console.log(arr)//[{a:1,b:2},{a:3,b:4}]
//操作newArr,这里看着对arr没影响,实际上已经挖了一个坑,下面就跳进去
newArr[0].a=123
//修改newArr[0]这个对象,也是影响了arr[0]这个对象
console.log(arr[0])//{a: 123, b: 2}
Почему это происходит, ведь Object.assign — это не глубокая копия, это мелкая копия, одетая как глубокая копия. В лучшем случае Object.assign скопирует значение первого уровня, а значение первого уровня будет глубокой копией, а когда оно достигнет второго уровня, будет копией ссылки. Есть похожие ситуации, метод среза и метод concat и т. д.
Чтобы решить эту проблему, вы должны сами инкапсулировать метод! следующим образом
//利用递归来实现深拷贝,如果对象属性的值是引用类型(Array,Object),那么对该属性进行深拷贝,直到遍历到属性的值是基本类型为止。
function deepClone(obj){
if(!obj&& typeof obj!== 'object'){
return;
}
var newObj= obj.constructor === Array ? [] : {};
for(var key in obj){
if(obj[key]){
if(obj[key] && typeof obj[key] === 'object'){
newObj[key] = obj[key].constructor === Array ? [] : {};
//递归
newObj[key] = deepClone(obj[key]);
}else{
newObj[key] = obj[key];
}
}
}
return newObj;
}
var arr=[{a:1,b:2},{a:3,b:4}]
var newArr=deepClone(arr)
console.log(arr[0])//{a:1,b:2}
newArr[0].a=123
console.log(arr[0])//{a:1,b:2}
Другой метод — простой и грубый метод, которым я сейчас и пользуюсь! Принцип очень прост, то есть сначала преобразуйте объект в строку, а затем преобразуйте строку в объект! можно добиться такого же эффекта
var newArr2=JSON.parse(JSON.stringify(arr));
console.log(arr[0])//{a:1,b:2}
newArr2[0].a=123
console.log(arr[0])//{a:1,b:2}
Мелкая копия, упомянутая выше, истинная и ложная глубокая копия (название по желанию), эти ситуации могут быть использованы в разработке, а какой метод использовать, зависит от ситуации!
4. Используйте делегирование событий
Для простого требования, например, если вы хотите добавить событие клика в li под ul, по которому li щелкнули, будет отображаться innerHTML этого li. Это кажется таким простым! код показывает, как показано ниже!
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<ul id="ul-test">
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
</ul>
</body>
<script type="text/javascript">
var oUl=document.getElementById("ul-test");
var oLi=oUl.getElementsByTagName("li");
for(var i=0,len=oLi.length;i<len;i++){
oLi[i].addEventListener("click",function(){
alert(this.innerHTML)
})
}
</script>
</html>
Очень просто, так это достигается На самом деле здесь есть ямы, и их нужно оптимизировать!
1. Цикл цикла li, 10 циклов li 10 раз, связывает 10 событий, 100 циклов 100 раз, связывает 100 событий!
2. Если li изначально нет на странице, это будущий элемент, страница загружается, а затем загружается динамически через js, написанное выше недействительно, и нажатие li не будет реагировать!
Таким образом, кандидату необходимо использовать делегирование событий (даже если второй случай выше не рассматривается, рекомендуется использовать делегирование событий)! код показывает, как показано ниже
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<ul id="ul-test">
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
</ul>
</body>
<script type="text/javascript">
var oUl=document.getElementById("ul-test");
oUl.addEventListener("click",function(ev){
var ev=ev||window.event;
var target=ev.target||ev.srcElement;
//如果点击的最底层是li元素
if(target.tagName.toLowerCase()==='li'){
alert(target.innerHTML)
}
})
</script>
</html>
Таким образом, даже динамически добавленные клики li будут реагировать.Другое, что ul только один, и событие привязано к ul.Независимо от того, сколько li, это событие, которое нужно добавить! Но могут быть проблемы.Если есть подэлементы под li, то при клике целью может быть не li, а самый нижний элемент в той позиции, где щелкает мышь! Как показано на рисунке ниже, если мышь щелкает белую область, целью является элемент body, мышью щелкает зеленая область, целью является элемент div, мышью щелкает синяя область, целью которой является ul, а оранжевым щелчком является ли.
5. Использование объектов в качестве параметров функции
Только представьте себе такую функцию - функция принимает несколько параметров, но эти параметры не являются обязательными, с функцией как быть? Разве это не следующее
function personInfo(name,phone,card){
...
}
//以上函数,可以任意传参数。比如我想传card等于1472586326。这下是不是这样写
personInfo('','','1472586326')
Вы чувствуете, что это странно, что это странно, не изящно? Вот что-то удобное!
function personInfo(opt){
...
}
personInfo({card:'1472586326'})
Подумайте еще раз, если у функции много параметров, как с этим быть?
function test(arg1,arg2,arg3,arg4,arg5,arg6,arg7){
...
}
Интенсивный рецидив фобии не повторился? Так будет немного удобнее!
function personInfo(opt){
...
}
Наконец, подумайте об этом еще раз, если требования меняются, функция работы также должна быть изменена! Функция также добавляет параметр.
//原来函数
function personInfo(name,phone,card){
...
}
//修改后
function personInfo(name,age,phone,card){
...
}
Это означает, что параметры изменяются один раз, и параметры функции должны быть изменены один раз! Если вы используете объекты, такой проблемы не будет!
//修改前后都是这样,变得是函数的操作内容和调用时候的传参!
function personInfo(opt){
...
}
Прочитав вышеприведенные каштаны, в заключение, когда параметры функции не фиксированы, а параметров много (три и более), для записи параметров рекомендуется использовать объект, что будет удобнее, а также на будущее.Если параметры надо изменить, оставьте выход!
6. Используйте push и apply для объединения массивов
Слияние массивов — распространенная тема, и есть много способов сделать это!
concat
var arr1=[1,2,3,4,5],arr2=[6,7,8,9,10];
arr1=arr1.concat(arr2)
console.log(arr1)//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
concat создаст совершенно новый массив, представляющий собой комбинацию двух массивов arr1 и arr2, и оставит arr1 и arr2 без изменений. Простой не так ли?
Но если обе длины arr1 и arr2 велики, получается очень длинный массив, и на столько занимает память. Но нет ограничений на длину массива!
for
var arr1=[1,2,3,4,5],arr2=[6,7,8,9,10];
for(var i=0,len=arr2.length;i<len;i++){
arr1.push(arr2[i])
}
console.log(arr1)//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Вот добавить элементы arr2 в arr1 в цикле, но есть ситуация, что длина arr1 намного меньше, чем длина arr2.Можно ли зациклить arr1 с лучшей производительностью и меньшим количеством циклов. С этим легко справиться, но что, если вы не знаете, какая из строк arr1 и arr2 имеет меньшую длину? Кроме того, цикл for недостаточно элегантен! (Конечно, это можно заменить итерационным методом)
reduce
var arr1=[1,2,3,4,5],arr2=[6,7,8,9,10];
arr1 = arr2.reduce( function(coll,item){
coll.push( item );
return coll;
}, arr1 );
console.log(arr1)//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Это немного выше, и использование стрелочных функций ES6 также может уменьшить объем кода, но для этого все еще требуется функция, которую нужно вызывать один раз для каждого элемента.
push.apply
var arr1=[1,2,3,4,5],arr2=[6,7,8,9,10];
arr1.push.apply(arr1,arr2);
console.log(arr1)//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Сила выглядит высокой, кода мало, новые массивы не генерируются, да и понять не сложно, просто вызовитеarr1.push
Примеры этой функцииapply
Метод, при этомarr2
передается в качестве параметра, поэтомуarr1.push
Этот метод будет проходитьarr2
Все элементы массива объединяются для достижения эффекта слияния. эквивалентноarr1.push.apply(arr1,[6,7,8,9,10]);
, что окончательно эквивалентноarr1.push(6,7,8,9,10)
. К сожалению, этот метод имеет ограничение на длину массива, в интернете говорят, что разные браузеры имеют разное ограничение на длину, как правило, не более 100 000!
Предварительно рекомендуется push.apply, но теперь оговорки, которые мы считаем, что это путь, с помощью которого! Это не обязательно правильно или неправильно!
7.Тофиксированное зарезервированное целое число
В разработке часто встречается, сколько знаков после запятой сохранять или подобные проблемы.Для этого использование toFixed может легко решить проблему, но если данные должны взаимодействовать с фоном, а данные, хранящиеся в фоновом режиме, обычно сохраняются в цифровом типе, а после использования toFixed генерируется строка, в этом случае необходимо преобразовать строку, сгенерированную toFixed, в числовой тип и переслать лот. Сегодня я скажу один из самых простых --+. код показывает, как показано ниже
var a=123.36896335.toFixed(2)
console.log(a)//'123.37'
a=+a
console.log(a)//123.37
PS: a=a|0 и ~~a также могут быть реализованы, но генерируется целое число, как показано ниже
var a=123.36896335.toFixed(2)
console.log(a)//'123.37'
a=a|0
console.log(a)//123
//---------------------------------分割线
var a=123.36896335.toFixed(2)
console.log(a)//'123.37'
a=~~a
console.log(a)//123
8. Преобразование других типов данных в логические данные
Следующее преобразование, все поймут с первого взгляда, нечего сказать.
console.log(!!'123')
//true
!!12
//true
!!-1
//true
!![]
//true
!!''
//false
!!null
//false
9. Переменные кэша
для длины кеша цикла
var arr=[1,2,3,4,5,6]
for(var i=0,i<arr.length;i++){
...
}
//------------------------分割线
var arr=[1,2,3,4,5,6]
for(var i=0,len=arr.length;i<len;i++){
...
}
Первый абзац — запрашивать arr.length каждый раз, когда вы зацикливаетесь. Второй кусок кода кэширует arr.length, и хорошо бы каждый раз сравнивать len, по идее второй кусок кода написан лучше и имеет более высокую производительность! Однако с развитием браузеров влияние этой детали на производительность кажется намного меньшим, чем ожидалось, и кэширование по-прежнему рекомендуется! Я написал тестовый пример ниже (тест Google Chrome)!
var arr100=[], arr10000=[];
for(var i=0;i<100;i++){
arr100.push(i)
}
for(var i=0;i<10000;i++){
arr10000.push(i)
}
//缓存情况
function testCache(arr){
console.time();
for(var i=0,len=arr.length;i<len;i++){
}
console.timeEnd()
}
//不缓存情况
function testNoCache(arr){
console.time();
for(var i=0,len=arr.length;i<len;i++){
}
console.timeEnd()
}
testCache(arr100)//default: 0.007ms
testCache(arr10000)//default: 0.035ms
testNoCache(arr100)//default: 0.012ms
testNoCache(arr10000)//default: 0.109ms
//这只是一个最简单的数组,如果遍历的是一个nodeList(元素列表),效果可能会更明显。
событие элемента
Здесь я использую jquery для объяснения, который легче понять, и то же самое верно для нативного js! Следующий код
$('.div1').click(function(){
...
})
//--------------------------分割线
var $div1=$('.div1');
$div1.click(function(){
...
})
В приведенном выше коде $('.div1') также кэшируется, но здесь второй способ записи, потому что первый щелкает, чтобы запросить .div1 один раз, а работу Дом еще можно сократить!
10. Используйте innerHTML для добавления элементов
Например, если есть необходимость,ul
добавить 10li
, два метода, следующий код
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<ul id="ul-test">
</ul>
</body>
<script type="text/javascript">
var oUl=document.getElementById("ul-test");
//createElement方式
console.time();
for(var i=0;i<10;i++){
var oLi=document.createElement('li');
oLi.innerHTML=i;
oUl.appendChild(oLi);
}
console.timeEnd();
//innerHTML方式
console.time();
var _html='';
for(var i=0;i<10;i++){
_html+='<li>'+i+'</li>'
}
oUl.innerHTML=_html;
console.timeEnd();
</script>
</html>
Все открыли код в браузере и обнаружили, что второй способ в принципе быстрее, как было сказано в пункте 8, операции с DOM можно сделать как можно меньше! Первому нужно управлять DOM 10 раз, а второму — только один раз. Другое дело, что это очень простой список, а что, если это следующий список? Во-первых, сколько раз вам придется создавать элементы createElement, innerHTML и appendChild? Кода много, а логика и взаимосвязь вложенности каждого узла тоже хаотичны! Второй способ — это операция сращивания строк, он намного лучше первого, а если использовать шаблонные строки es6, то еще проще!
11. Преобразование параметров в массивы
Хотя аргументы в функции имеют свойство length, аргументы представляют собой не массив, а массив классов, без push, slice и других методов. Иногда необходимо преобразовать аргументы в массив, и существует несколько способов их преобразования.Рекомендуемый метод следующий!
var _arguments=Array.prototype.slice.apply(arguments)
12. Функция дроссельной заслонки
Вот возьмем скажем каштан, например, при срабатывании mousemove, onscroll, onresize эти события могли вызвать событие 60 раз, так что это производительность потребления, и на самом деле нам не нужен такой частый срабатывание, всего около 100 миллисекунд для срабатывания достаточно! Тогда такое ограничение должно работать!
обычное письмо
var count = 0;
function beginCount() {
count++;
console.log(count);
}
document.onmousemove = function () {
beginCount();
};
Эффект
Дроссельная запись
var count = 0;
function beginCount() {
count++;
console.log(count);
}
function delayFn(method, thisArg) {
clearTimeout(method.props);
method.props = setTimeout(function () {
method.call(thisArg)
},100)
}
document.onmousemove = function () {
delayFn(beginCount)
};
Эффект
Этот метод на самом деле проблематичен, он останавливается и ждет 100 мс, прежде чем начнет выполняться, а промежуточная операция слишком быстрая, чтобы ее можно было игнорировать. Итак, я нашел следующее решение в Интернете!
Второй способ написать троттлинг
function delayFn2 (fn, delay, mustDelay){
var timer = null;
var t_start;
return function(){
var context = this, args = arguments, t_cur = +new Date();
//先清理上一次的调用触发(上一次调用触发事件不执行)
clearTimeout(timer);
//如果不存触发时间,那么当前的时间就是触发时间
if(!t_start){
t_start = t_cur;
}
//如果当前时间-触发时间大于最大的间隔时间(mustDelay),触发一次函数运行函数
if(t_cur - t_start >= mustDelay){
fn.apply(context, args);
t_start = t_cur;
}
//否则延迟执行
else {
timer = setTimeout(function(){
fn.apply(context, args);
}, delay);
}
};
}
var count=0;
function fn1(){
count++;
console.log(count)
}
//100ms内连续触发的调用,后一个调用会把前一个调用的等待处理掉,但每隔200ms至少执行一次
document.onmousemove=delayFn2(fn1,100,200)
Сейчас я редко использую дросселирование функций. Эти два метода написания относительно просты. Я надеюсь, что каждый может поделиться своими лучшими методами!
13. Другие советы по написанию
Некоторые другие навыки письма и предложения более распространены, например, соглашения об именах, принцип функционального единства и т. д. Эта часть моего собственного резюме в основном такая же, как и то, что написали другие! Я не буду его расширять (мне кажется, что расширение - это в основном копирование и вставка чужих статей, я этим не занимаюсь), поэтому всем рекомендую прочитать эту статью (Как элегантно писать код JavaScript). Я тоже получил некоторые знания отсюда!
14. Резюме
Ну, вот несколько практических советов и советов для моего собственного резюме! Что касается навыков и предложений по javascript, вам все равно нужно читать больше ресурсов в Интернете и больше обобщать самостоятельно, ведь то, что я обобщил, - это только то, что я нашел сам, и это только верхушка айсберга. Но я все же надеюсь, что эта статья сможет помочь всем и позволит каждому получить знания. Конечно, больше надежды сыграть свою роль в обмене мнениями. Если есть предложения, советы. Делиться тоже приветствуется. Если вы считаете, что я написал что-то не так или недостаточно хорошо, пожалуйста, укажите! Давайте помогать друг другу и учиться друг у друга!
------------------------- Великолепная разделительная линия --------------------
Хотите узнать больше, обратите внимание на мой публичный аккаунт WeChat: В ожидании книжного магазина