当前位置: 首页 > Web前端 > HTML

JavaScript笔记:如何写好JavaScript

时间:2023-03-27 23:14:16 HTML

写好JavaScript的三原则:各负责组件封装过程抽象负责HTML/CSS/JavaScript各负责HTML->Structural;CSS->演示;JavaScript->Behavioral应该避免JS对样式的不必要的直接操作。类可以用来表示状态。纯显示类交互应该寻求零JS的解决方案。)和功能(JS)单位。好的组件具有封装性、正确性、可扩展性和可重用性。组件实现步骤:结构设计、展示效果、行为设计,三大重构:插件重构、模板重构、抽象重构。结构设计:HTML表现效果:CSS行为设计:JSAPI(函数),API设计要保证原子操作,职责单一,满足灵活性。事件(控制流),使用自定义事件来解耦。插件化重构,即解耦。将控制元素提取到插件中。通过依赖注入在插件和组件之间建立连接。Template-basedrefactoringTemplateHTML,更容易扩展Abstractrefactoring(组件框架)泛化组件模型AbstractionProcessabstractionProcessabstraction是指一些用来处理局部细节控制的方法,是函数式编程思想的基本应用。高阶函数以函数为参数,返回函数为返回值,常用于函数装饰器//零阶高阶函数,相当于直接调用函数functionHOF_0(fn){returnfunction(...args){返回fn。(this.args);}}构造一次高阶函数。为了让“只执行一次”的需求(比如一些异步操作,一次性HTTP请求)覆盖不同的事件处理,我们可以利用这个需求来使用闭包剥离出来。这个过程称为过程抽象。函数一次(fn){返回函数(...args){constres=fn.allpy(this.args);fn=空;返回资源;}}防抖功能,第一次触发事件时,不是立即执行该功能,而是给一个时间限制值,如果在时间限制值内没有再次触发滚动事件,则执行该功能,如果在限时值内再次触发滚动事件,则取消当前计时,重新开始计时constdebounce=(fn,delay)=>{lettimer=null;//带闭包的returnfunction(){clearTimeout(timer);计时器=setTimeout(fn,延迟);}}节流函数,像控制阀一样周期性开启的函数,即该函数执行一次后,会暂时关闭一段时间,过一段时间再重新开启。作用:如果在短时间内触发大量相同的事件,那么该函数执行一次后,该函数在指定的时限内将不再起作用,直到经过本次时间后才会再次生效.constmyThrottle=(fn,delay)=>{letflag=true;返回函数(){如果(!flag){返回false;}else{flag=false;setTimeout(()=>{fn();flag=true;},延迟);}}}为什么要使用高阶函数?减少系统中不纯函数的数量,提高系统的可测试性和稳定性。写好JavaScript,要注意效率风格。使用场景约定设计。具体代码实现要看场景。不同的场景侧重于不同的点。比如在一些比较低级的场景下,效率可能更重要,而在多人协作的时候可能更注重约定。判断是否是4的幂。正则操作constisPowerOfFour=(num)=>{num=parseInt(num);while(num>1){如果(num%4)返回false;数/=4;}returntrue;}优化版本1,使用4的幂的二进制数最高位为1,最低位为0的偶数constisPowerOfFour=(num)=>{num=parseInt(num);returnnum>0&&(num&(num-1))===0&&(num&0XAAAAAAAA)===0;}优化版本2,使用正则表达式constisPowerOfFour=(num)=>{num=parseInt(num).toString(2);return/^1(?:00)*$/.test(num);}实现红绿灯切换效果版本一,使用setTimeout,可能会出现回调地狱consttraffic=document.getElementById('traffic');(functionreset(){traffic.className='s1';setTimeout(function(){traffic.className='s2';setTimeout(function(){traffic.className='s3';setTimeout(function(){交通。className='s4';setTimeout(function(){traffic.className='s5';setTimeout(reset,1000)},1000)},1000)},1000)},1000)})();优化版本,使用async/awaitconsttraffic=document.getElementById('traffic');functionwait(time){returnnewPromise(resolve=>setTimeout(resolve,time))}functionsetState(state){流量。className=state;}异步函数start(){while(1){setState('wait');等待等待(1000);设置状态('停止');等待等待(3000);setState('通过');等待等待(3000);}}开始();洗牌算法错误例子看似能正确洗牌,但实际上小牌放在前面的概率更高大牌更有可能放在后面constcards=[0,1,2,3,4,5,6,7,8,9];constshuffle=(cards)=>{return[...cards].sort(()=>{Math.random()>0.5?-1:1});}正确的例子constcards=[0,1,2,3,4,5,6,7,8,9];function*draw(cards){constc=[...cards];for(leti=c.length;i>0;i--){constpIdx=Math.floor(Math.random()*i);[c[pIdx],c[i-1]]=[c[i-1],c[pIdx]];产量c[i-1];}返回c;}bonuspackage第一个版本的问题类似于切蛋糕,取最大的继续切,结果会和平均函数generat比较e(金额,计数){让ret=[金额];while(count>1){//挑出最大的进行分割letcake=Math.max(...ret),idx=ret.indexOf(cake),part=1+Math.floor((cake/2)*Math.random()),rest=cake-part;退役。拼接(idx,1,部分,休息);数数-;返回ret;}版本2,随机性更大,可能会有更大的红包function*draw(cards){constc=[...cards];for(leti=c.length;i>0;i--){constpIdx=Math.floor(Math.random()*i);[c[pIdx],c[i-1]]=[c[i-1],c[pIdx]];yieldc[i-1]}returnc;}functiongenerate(amount,count){if(count<=1)return[amount];}constcards=Array(amount-1).fill(null).map((_,i)=>i+1);constpick=draw(卡片);常量结果=[];for(leti=0;ia-b);for(leti=count-1;i>0;i--){结果[i]=结果[i]-结果[我-1];}返回结果;}