javascriptJS原生面经从初级到高级近1.5W字前端小而全的知识归纳

在ES5中函数内容的this指向和调用方法有关

包括函数名()和匿名函数调用,this指向window

functiongetSum(){console.log(this)//window}getSum()(function(){console.log(this)//window})()vargetSum=function(){console.log(this)//window}getSum()1.2.2方法调用对象.方法名(),this指向对象

varobjList={name:'methods',getSum:function(){console.log(this)//objList对象}}objList.getSum()1.2.3构造器调用new构造函数名(),this指向构造函数

functionPerson(){console.log(this);//指向实例}varpersonOne=newPerson();1.2.4间接调用利用call和apply来实现,this就是call和apply对应的第一个参数,如果不传值或者第一个值为null,undefined时this指向window

functionfoo(){console.log(this);}foo.apply('我是apply改变的this值');//我是apply改变的this值foo.call('我是call改变的this值');//我是call改变的this值1.3ES6中函数的调用箭头函数不可以当作构造函数使用,也就是不能用new命令实例化一个对象,否则会抛出一个错误箭头函数的this是和定义时有关和调用无关调用就是函数调用模式

(()=>{console.log(this)//window})()letarrowFun=()=>{console.log(this)//window}arrowFun()letarrowObj={arrFun:function(){(()=>{console.log(this)//指向对象arrowObj})()}}arrowObj.arrFun();1.4.call,apply和bind1.IE5之前不支持call和apply,bind是ES5出来的;2.call和apply可以调用函数,改变this,实现继承和借用别的对象的方法;

调用方法,用一个对象替换掉另一个对象(this)对象.call(新this对象,实参1,实参2,实参3.....)对象.apply(新this对象,[实参1,实参2,实参3.....])

1.间接调用函数,改变作用域的this值2.劫持其他对象的方法

varfoo={name:"张三",logName:function(){console.log(this.name);}}varbar={name:"李四"};foo.logName.call(bar);//李四实质是call改变了foo的this指向为bar,并调用该函数3.两个函数实现继承

functionAnimal(name){this.name=name;this.showName=function(){console.log(this.name);}}functionCat(name){Animal.call(this,name);}varcat=newCat("BlackCat");cat.showName();//BlackCat4.为类数组(arguments和nodeList)添加数组方法push,pop

(function(){Array.prototype.push.call(arguments,'王五');console.log(arguments);//['张三','李四','王五']})('张三','李四')5.合并数组

letarr1=[1,2,3];letarr2=[4,5,6];Array.prototype.push.apply(arr1,arr2);//将arr2合并到了arr1中6.求数组最大值

Math.max.apply(null,arr)7.判断字符类型

Object.prototype.toString.call({})1.4.3bindbind是function的一个函数扩展方法,bind以后代码重新绑定了func内部的this指向,不会调用方法,不兼容IE8

varname='李四'varfoo={name:"张三",logName:function(age){console.log(this.name,age);}}varfooNew=foo.logName;varfooNewBind=foo.logName.bind(foo);fooNew(10)//李四,10fooNewBind(11)//张三,11因为bind改变了fooNewBind里面的this指向1.4.4call,apply和bind原生实现call实现:

Function.prototype.newCall=function(context,...parameter){if(typeofcontext==='object'||typeofcontext==='function'){context=context||window}else{context=Object.create(null)}context[fn]=thisconstres=context[fn](...parameter)deletecontext.fn;returnres}letperson={name:'Abiel'}functionsayHi(age,sex){console.log(this.name,age,sex);}sayHi.newCall(person,25,'男');//Abiel25男apply实现:

Function.prototype.newApply=function(context,parameter){if(typeofcontext==='object'||typeofcontext==='function'){context=context||window}else{context=Object.create(null)}letfn=Symbol()context[fn]=thisreturnres=context[fn](..parameter);deletecontext[fn]returnres}sayHi.newApply(person,[25,'男'])//Abiel25男bind实现:

Function.prototype.bind=function(context,...innerArgs){varme=thisreturnfunction(...finnalyArgs){returnme.call(context,...innerArgs,...finnalyArgs)}}letperson={name:'Abiel'}functionsayHi(age,sex){console.log(this.name,age,sex);}letpersonSayHi=sayHi.bind(person,25)personSayHi('男')1.4.5三者异同同:都是改变this指向,都可接收参数异:bind和call是接收单个参数,apply是接收数组

节流:

//html部分

//js部分letthrottle=function(func,delay){lettimer=null;returnfunction(){if(!timer){timer=setTimeout(()=>{func.apply(this,arguments);//或者直接func()timer=null;},delay);}};};//处理函数functionhandle(){console.log(arguments)console.log(Math.random());}//测试用例document.getElementsByClassName('scroll-box')[0].addEventListener("scroll",debounce(handle,3000));1.5.2防抖//html部分同上//js部分letdebounce=function(fn,wait){lettimeout=null;returnfunction(){if(timeout!==null)clearTimeout(timeout);//如果多次触发将上次记录延迟清除掉timeout=setTimeout(()=>{fn.apply(this,arguments);//或者直接fn()timeout=null;},wait);};}//处理函数functionhandle(){

console.log(arguments)console.log(Math.random());}//测试用例document.getElementsByClassName('scroll-box')[0].addEventListener("scroll",debounce(handle,3000));

对象继承属性的一个链条

varPerson=function(name){this.name=name;}//person是构造函数varo3personTwo=newPerson('personTwo')//personTwo是实例

原型对象都有一个默认的constructor属性指向构造函数

1.字面量

letobj={'name':'张三'}2.Object构造函数创建

letObj=newObject()Obj.name='张三'3.使用工厂模式创建对象

functioncreatePerson(name){varo=newObject();o.name=name;returno;}varperson1=createPerson('张三');4.使用构造函数创建对象

functionPerson(name){this.name=name;}varperson1=newPerson('张三');1.6.4new运算符1.创了一个新对象;2.this指向构造函数;3.构造函数有返回,会替换new出来的对象,如果没有就是new出来的对象4.手动封装一个new运算符

varnew2=function(func){varo=Object.create(func.prototype);//创建对象vark=func.call(o);//改变this指向,把结果付给kif(k&&typeofk==='object'){//判断k的类型是不是对象returnk;//是,返回k}else{returno;//不是返回返回构造函数的执行结果}}1.6.5对象的原型链

JS是一门弱类型动态语言,封装和继承是他的两大特性

将父类的实例作为子类的原型1.代码实现定义父类:

//定义一个动物类functionAnimal(name){//属性this.name=name||'Animal';//实例方法this.sleep=function(){console.log(this.name+'正在睡觉!');}}//原型方法Animal.prototype.eat=function(food){console.log(this.name+'正在吃:'+food);};子类:

functionCat(){}Cat.prototype=newAnimal();Cat.prototype.name='cat';//TestCodevarcat=newCat();console.log(cat.name);//catconsole.log(cat.eat('fish'));//cat正在吃:fishundefinedconsole.log(cat.sleep());//cat正在睡觉!undefinedconsole.log(catinstanceofAnimal);//trueconsole.log(catinstanceofCat);//true2.优缺点简单易于实现,但是要想为子类新增属性和方法,必须要在newAnimal()这样的语句之后执行,无法实现多继承

实质是利用call来改变Cat中的this指向1.代码实现子类:

functionCat(name){Animal.call(this);this.name=name||'Tom';}2.优缺点可以实现多继承,不能继承原型属性/方法

为父类实例添加新特性,作为子类实例返回1.代码实现子类

functionCat(name){varinstance=newAnimal();instance.name=name||'Tom';returninstance;}2.优缺点不限制调用方式,但不能实现多继承

将父类的属性和方法拷贝一份到子类中1.子类:

functionCat(name){varanimal=newAnimal();for(varpinanimal){Cat.prototype[p]=animal[p];}Cat.prototype.name=name||'Tom';}2.优缺点支持多继承,但是效率低占用内存

通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用1.子类:

//父类classPerson{//constructor是构造方法constructor(skin,language){this.skin=skin;this.language=language;}say(){console.log('我是父类')}}//子类classChineseextendsPerson{constructor(skin,language,positon){//console.log(this);//报错super(skin,language);//super();相当于父类的构造函数//console.log(this);调用super后得到了this,不报错,this指向子类,相当于调用了父类.prototype.constructor.call(this)this.positon=positon;}aboutMe(){console.log(`${this.skin}${this.language}${this.positon}`);}}//调用只能通过new的方法得到实例,再调用里面的方法letobj=newChinese('红色','中文','香港');obj.aboutMe();obj.say();1.8.高阶函数1.8.1定义函数的参数是函数或返回函数

map,reduce,filter,sort

1.定义:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数

fn(a,b,c,d)=>fn(a)(b)(c)(d)2.代码实现:

constcurrying=fn=>{constlen=fn.lengthreturnfunctioncurr(...args1){if(args1.length>=len){returnfn(...args1)}return(...args2)=>curr(...args1,...args2)}}

1.定义:

obj.func(arg1,arg2)=>func(obj,arg1,arg2)2.代码实现:

Function.prototype.uncurrying=function(){varthat=this;returnfunction(){returnFunction.prototype.call.apply(that,arguments);}};functionsayHi(){return"Hello"+this.value+""+[].slice.call(arguments);}letsayHiuncurrying=sayHi.uncurrying();console.log(sayHiuncurrying({value:'world'},"hahaha"));1.8.5偏函数1.定义:指定部分参数来返回一个新的定制函数的形式2.例子:

Obejct.create(obj,descriptor),obj是对象,describe描述符属性(可选)

1.数据属性4个特性:configurable(可配置),enumerable(可枚举),writable(可修改),value(属性值)

2.访问器属性2个特性:get(获取),set(设置)

3.内部属性由JavaScript引擎内部使用的属性;不能直接访问,但是可以通过对象内置方法间接访问,如:[[Prototype]]可以通过Object.getPrototypeOf()访问;内部属性用[[]]包围表示,是一个抽象操作,没有对应字符串类型的属性名,如[[Prototype]].

1.定义:将一个属性的所有特性编码成一个对象返回2.描述符的属性有:数据属性和访问器属性3.使用范围:作为方法Object.defineProperty,Object.getOwnPropertyDescriptor,Object.create的第二个参数,

1.访问对象存在的属性

get,set与wriable,value是互斥的,如果有交集设置会报错

1.定义属性的函数有两个:Object.defineProperty和Object.defineProperties.例如:Object.defineProperty(obj,propName,desc)

2.在引擎内部,会转换成这样的方法调用:obj.[[DefineOwnProperty]](propName,desc,true)

1.赋值运算符(=)就是在调用[[Put]].比如:obj.prop=v;

2.在引擎内部,会转换成这样的方法调用:obj.[[Put]]("prop",v,isStrictModeOn)

是一种数据类型;不能new,因为Symbol是一个原始类型的值,不是对象。

Symbol(),可以传参

vars1=Symbol();vars2=Symbol();s1===s2//false//有参数的情况vars1=Symbol("foo");vars2=Symbol("foo");s1===s2//false2.3.3用法1.不能与其他类型的值进行运算;2.作为属性名

letmySymbol=Symbol();//第一种写法vara={};a[mySymbol]='Hello!';//第二种写法vara={[mySymbol]:'Hello!'};//第三种写法vara={};Object.defineProperty(a,mySymbol,{value:'Hello!'});//以上写法都得到同样结果a[mySymbol]//"Hello!"3.作为对象属性名时,不能用点运算符,可以用[]

leta={};letname=Symbol();a.name='lili';a[name]='lucy';console.log(a.name,a[name]);4.遍历不会被for...in、for...of和Object.keys()、Object.getOwnPropertyNames()取到该属性

1.定义:在全局中搜索有没有以该参数作为名称的Symbol值,如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值2.举例:

vars1=Symbol.for('foo');vars2=Symbol.for('foo');s1===s2//true2.3.5Symbol.keyFor1.定义:返回一个已登记的Symbol类型值的key2.举例:

vars1=Symbol.for("foo");Symbol.keyFor(s1)//"foo"vars2=Symbol("foo");Symbol.keyFor(s2)//undefined2.4.遍历2.4.1一级对象遍历方法方法特性for...in遍历对象自身的和继承的可枚举属性(不含Symbol属性)Object.keys(obj)返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)Object.getOwnPropertyNames(obj)返回一个数组,包括对象自身的所有可枚举属性(不含Symbol属性)Object.getOwnPropertySymbols(obj)返回一个数组,包含对象自身的所有Symbol属性Reflect.ownKeys(obj)返回一个数组,包含对象自身的所有(不枚举、可枚举和Symbol)属性Reflect.enumerate(obj)返回一个Iterator对象,遍历对象自身的和继承的所有可枚举属性(不含Symbol属性)总结:1.只有Object.getOwnPropertySymbols(obj)和Reflect.ownKeys(obj)可以拿到Symbol属性2.只有Reflect.ownKeys(obj)可以拿到不可枚举属性

数据模型:

vartreeNodes=[{id:1,name:'1',children:[{id:11,name:'11',children:[{id:111,name:'111',children:[]},{id:112,name:'112'}]},{id:12,name:'12',children:[]}],users:[]},];递归:

varparseTreeJson=function(treeNodes){if(!treeNodes||!treeNodes.length)return;for(vari=0,len=treeNodes.length;i0){parseTreeJson(childs);}}};console.log('-------------递归实现------------------');parseTreeJson(treeNodes);2.5.深度拷贝2.5.1Object.assign1.定义:将源对象(source)的所有可枚举属性,复制到目标对象(target)2.用法:

合并多个对象vartarget={a:1,b:1};varsource1={b:2,c:2};varsource2={c:3};Object.assign(target,source1,source2);3.注意:这个是伪深度拷贝,只能拷贝第一层

1.原理:是将对象转化为字符串,而字符串是简单数据类型

functiondeepClone(source){consttargetObj=source.constructor===Array[]:{};//判断复制的目标是数组还是对象for(letkeysinsource){//遍历目标if(source.hasOwnProperty(keys)){if(source[keys]&&typeofsource[keys]==='object'){//如果值是对象,就递归一下targetObj[keys]=source[keys].constructor===Array[]:{};targetObj[keys]=deepClone(source[keys]);}else{//如果不是,就直接赋值targetObj[keys]=source[keys];}}}returntargetObj;}2.6.数据拦截定义:利用对象内置方法,设置属性,进而改变对象的属性值

1.ES5出来的方法;2.三个参数:对象(必填),属性值(必填),描述符(可选);3.defineProterty的描述符属性

数据属性:value,writable,configurable,enumerable访问器属性:get,set注:不能同时设置value和writable,这两对属性是互斥的4.拦截对象的两种情况:

letobj={name:'',age:'',sex:''},defaultName=["这是姓名默认值1","这是年龄默认值1","这是性别默认值1"];Object.keys(obj).forEach(key=>{Object.defineProperty(obj,key,{get(){returndefaultName;},set(value){defaultName=value;}});});console.log(obj.name);console.log(obj.age);console.log(obj.sex);obj.name="这是改变值1";console.log(obj.name);console.log(obj.age);console.log(obj.sex);letobjOne={},defaultNameOne="这是默认值2";Object.defineProperty(obj,'name',{get(){returndefaultNameOne;},set(value){defaultNameOne=value;}});console.log(objOne.name);objOne.name="这是改变值2";console.log(objOne.name);5.拦截数组变化的情况

leta={};bValue=1;Object.defineProperty(a,"b",{set:function(value){bValue=value;console.log("setted");},get:function(){returnbValue;}});a.b;//1a.b=[];//setteda.b=[1,2,3];//setteda.b[1]=10;//无输出a.b.push(4);//无输出a.b.length=5;//无输出a.b;//[1,10,3,4,undefined];结论:defineProperty无法检测数组索引赋值,改变数组长度的变化;但是通过数组方法来操作可以检测到多级对象监听

letinfo={};functionobserve(obj){if(!obj||typeofobj!=="object"){return;}for(variinobj){definePro(obj,i,obj[i]);}}functiondefinePro(obj,key,value){observe(value);Object.defineProperty(obj,key,{get:function(){returnvalue;},set:function(newval){console.log("检测变化",newval);value=newval;}});}definePro(info,"friends",{name:"张三"});info.friends.name="李四";6.存在的问题

2.两个参数:对象和行为函数

lethandler={get(target,key,receiver){console.log("get",key);returnReflect.get(target,key,receiver);},set(target,key,value,receiver){console.log("set",key,value);returnReflect.set(target,key,value,receiver);}};letproxy=newProxy(obj,handler);proxy.name="李四";proxy.age=24;涉及到多级对象或者多级数组监听

1.defineProterty是es5的标准,proxy是es6的标准;

2.proxy可以监听到数组索引赋值,改变数组长度的变化;

3.proxy是监听对象,不用深层遍历,defineProterty是监听属性;

数组基本上考察数组方法多一点,所以这里就单纯介绍常见的场景数组的方法,还有很多场景后续补充;本文主要从应用来讲数组api的一些骚操作;如一行代码扁平化n维数组、数组去重、求数组最大值、数组求和、排序、对象和数组的转化等;上面这些应用场景你可以用一行代码实现?

1.终极篇

[1,[2,3]].flat(2)//[1,2,3][1,[2,3,[4,5]].flat(3)//[1,2,3,4,5][1,[2,3,[4,5]]].toString()//'1,2,3,4,5'[1[2,3,[4,5[...]].flat(Infinity)//[1,2,3,4...n]Array.flat(n)是ES10扁平数组的api,n表示维度,n值为Infinity时维度为无限大

2.开始篇

functionflatten(arr){while(arr.some(item=>Array.isArray(item))){arr=[].concat(...arr);}returnarr;}flatten([1,[2,3]])//[1,2,3]flatten([1,[2,3,[4,5]])//[1,2,3,4,5]实质是利用递归和数组合并方法concat实现扁平

Array.from(newSet([1,2,3,3,4,4]))//[1,2,3,4][...newSet([1,2,3,3,4,4])]//[1,2,3,4]set是ES6新出来的一种一种定义不重复数组的数据类型Array.from是将类数组转化为数组...是扩展运算符,将set里面的值转化为字符串2.开始篇

Array.prototype.distinct=nums=>{constmap={}constresult=[]for(constnofnums){if(!(ninmap)){map[n]=1result.push(n)}}returnresult}[1,2,3,3,4,4].distinct();//[1,2,3,4]取新数组存值,循环两个数组值相比较

[1,2,3,4].sort((a,b)=>a-b);//[1,2,3,4],默认是升序[1,2,3,4].sort((a,b)=>b-a);//[4,3,2,1]降序sort是js内置的排序方法,参数为一个函数2.开始篇冒泡排序:

Array.prototype.bubleSort=function(){letarr=this,len=arr.length;for(letouter=len;outer>=2;outer--){for(letinner=0;inner<=outer-1;inner++){if(arr[inner]>arr[inner+1]){//升序[arr[inner],arr[inner+1]]=[arr[inner+1],arr[inner]];console.log([arr[inner],arr[inner+1]]);}}}returnarr;}[1,2,3,4].bubleSort()//[1,2,3,4]选择排序

Array.prototype.selectSort=function(){letarr=this,len=arr.length;for(leti=0,len=arr.length;iarr[j]){[arr[i],arr[j]]=[arr[j],arr[i]];}}}returnarr;}[1,2,3,4].selectSort()//[1,2,3,4]3.4最大值1.终极篇

Math.max(...[1,2,3,4])//4Math.max.apply(this,[1,2,3,4])//4[1,2,3,4].reduce((prev,cur,curIndex,arr)=>{returnMath.max(prev,cur);},0)//4Math.max()是Math对象内置的方法,参数是字符串;reduce是ES5的数组api,参数有函数和默认初始值;函数有四个参数,pre(上一次的返回值),cur(当前值),curIndex(当前值索引),arr(当前数组)

2.开始篇先排序再取值

[1,2,3,4].reduce(function(prev,cur){returnprev+cur;},0)//102.开始篇

functionsum(arr){varlen=arr.length;if(len==0){return0;}elseif(len==1){returnarr[0];}else{returnarr[0]+sum(arr.slice(1));}}sum([1,2,3,4])//10利用slice截取改变数组,再利用递归求和

[1,2,3,4].concat([5,6])//[1,2,3,4,5,6][...[1,2,3,4],...[4,5]]//[1,2,3,4,5,6]letarrA=[1,2],arrB=[3,4]Array.prototype.push.apply(arrA,arrB))//arrA值为[1,2,3,4]2.开始篇

letarr=[1,2,3,4];[5,6].map(item=>{arr.push(item)})//arr值为[1,2,3,4,5,6],注意不能直接return出来,return后只会返回[5,6]3.7判断是否包含值1.终极篇

[1,2,3].includes(4)//false[1,2,3].indexOf(4)//-1如果存在换回索引[1,2,3].find((item)=>item===3))//3如果数组中无值返回undefined[1,2,3].findIndex((item)=>item===3))//2如果数组中无值返回-1includes(),find(),findIndex()是ES6的api

[1,2,3].some(item=>{returnitem===3})//true如果不包含返回false3.8类数组转化1.终极篇

Array.prototype.slice.call(arguments)//arguments是类数组(伪数组)Array.prototype.slice.apply(arguments)Array.from(arguments)[...arguments]类数组:表示有length属性,但是不具备数组的方法call,apply:是改变slice里面的this指向arguments,所以arguments也可调用数组的方法Array.from是将类似数组或可迭代对象创建为数组...是将类数组扩展为字符串,再定义为数组

Array.prototype.slice=function(start,end){varresult=newArray();start=start||0;end=end||this.length;//this指向调用的对象,当用了call后,能够改变this的指向,也就是指向传进来的对象,这是关键for(vari=start;i

[1,2,3].fill(false)//[false,false,false]fill是ES6的方法2.开始篇

[1,2,3].map(()=>0)3.10每一项是否满足[1,2,3].every(item=>{returnitem>2})//falseevery是ES5的api,每一项满足返回true

[1,2,3].some(item=>{returnitem>2})//truesome是ES5的api,有一项满足返回true

[1,2,3].filter(item=>{returnitem>2})//[3]filter是ES5的api,返回满足添加的项的数组

Object.keys({name:'张三',age:14})//['name','age']Object.values({name:'张三',age:14})//['张三',14]Object.entries({name:'张三',age:14})//[[name,'张三'],[age,14]]Object.fromEntries([name,'张三'],[age,14])//ES10的api,Chrome不支持,firebox输出{name:'张三',age:14}3.14对象数组[{count:1},{count:2},{count:3}].reduce((p,e)=>p+(e.count),0)4.数据结构篇数据结构是计算机存储、组织数据的方式,算法是系统描述解决问题的策略。了解基本的数据结构和算法可以提高代码的性能和质量。也是程序猿进阶的一个重要技能。手撸代码实现栈,队列,链表,字典,二叉树,动态规划和贪心算法4.1栈栈的特点:先进后出

classStack{constructor(){this.items=[];}//入栈push(element){this.items.push(element);}//出栈pop(){returnthis.items.pop();}//末位getpeek(){returnthis.items[this.items.length-1];}//是否为空栈getisEmpty(){return!this.items.length;}//长度getsize(){returnthis.items.length;}//清空栈clear(){this.items=[];}}//实例化一个栈conststack=newStack();console.log(stack.isEmpty);//true//添加元素stack.push(5);stack.push(8);//读取属性再添加console.log(stack.peek);//8stack.push(11);console.log(stack.size);//3console.log(stack.isEmpty);//false4.2队列队列:先进先出

classQueue{constructor(items){this.items=items||[];}enqueue(element){this.items.push(element);}dequeue(){returnthis.items.shift();}front(){returnthis.items[0];}clear(){this.items=[];}getsize(){returnthis.items.length;}getisEmpty(){return!this.items.length;}print(){console.log(this.items.toString());}}constqueue=newQueue();console.log(queue.isEmpty);//truequeue.enqueue("John");queue.enqueue("Jack");queue.enqueue("Camila");console.log(queue.size);//3console.log(queue.isEmpty);//falsequeue.dequeue();queue.dequeue();4.3链表链表:存贮有序元素的集合,但是不同于数组,每个元素是一个存贮元素本身的节点和指向下一个元素引用组成要想访问链表中间的元素,需要从起点开始遍历找到所需元素

classDictionary{constructor(){this.items={};}set(key,value){this.items[key]=value;}get(key){returnthis.items[key];}remove(key){deletethis.items[key];}getkeys(){returnObject.keys(this.items);}getvalues(){/*也可以使用ES7中的values方法returnObject.values(this.items)*///在这里我们通过循环生成一个数组并输出returnObject.keys(this.items).reduce((r,c,i)=>{r.push(this.items[c]);returnr;},[]);}}constdictionary=newDictionary();dictionary.set("Gandalf","gandalf@email.com");dictionary.set("John","johnsnow@email.com");dictionary.set("Tyrion","tyrion@email.com");console.log(dictionary);console.log(dictionary.keys);console.log(dictionary.values);console.log(dictionary.items);4.5二叉树特点:每个节点最多有两个子树的树结构

特点:第三项等于前面两项之和

functionfibonacci(num){if(num===1||num===2){return1}returnfibonacci(num-1)+fibonacci(num-2)}5.3动态规划特点:通过全局规划,将大问题分割成小问题来取最优解案例:最少硬币找零美国有以下面额(硬币):d1=1,d2=5,d3=10,d4=25如果要找36美分的零钱,我们可以用1个25美分、1个10美分和1个便士(1美分)

classMinCoinChange{constructor(coins){this.coins=coinsthis.cache={}}makeChange(amount){if(!amount)return[]if(this.cache[amount])returnthis.cache[amount]letmin=[],newMin,newAmountthis.coins.forEach(coin=>{newAmount=amount-coinif(newAmount>=0){newMin=this.makeChange(newAmount)}if(newAmount>=0&&(newMin.length

functionMinCoinChange(coins){varcoins=coins;varcache={};this.makeChange=function(amount){varchange=[],total=0;for(vari=coins.length;i>=0;i--){varcoin=coins[i];while(total+coin<=amount){change.push(coin);total+=coin;}}returnchange;};}varminCoinChange=newMinCoinChange([1,5,10,25]);console.log(minCoinChange.makeChange(36));console.log(minCoinChange.makeChange(34));console.log(minCoinChange.makeChange(6));6设计模式设计模式如果应用到项目中,可以实现代码的复用和解耦,提高代码质量。本文主要介绍14种设计模式写UI组件,封装框架必备6.1简单工厂模式1.定义:又叫静态工厂方法,就是创建对象,并赋予属性和方法2.应用:抽取类相同的属性和方法封装到对象上3.代码:

letUserFactory=function(role){functionUser(opt){this.name=opt.name;this.viewPage=opt.viewPage;}switch(role){case'superAdmin':returnnewUser(superAdmin);break;case'admin':returnnewUser(admin);break;case'user':returnnewUser(user);break;default:thrownewError('参数错误,可选参数:superAdmin、admin、user')}}//调用letsuperAdmin=UserFactory('superAdmin');letadmin=UserFactory('admin')letnormalUser=UserFactory('user')//最后得到角色,可以调用6.2工厂方法模式1.定义:对产品类的抽象使其创建业务主要负责用于创建多类产品的实例2.应用:创建实例3.代码:

varFactory=function(type,content){if(thisinstanceofFactory){vars=newthis[type](content);returns;}else{returnnewFactory(type,content);}}//工厂原型中设置创建类型数据对象的属性Factory.prototype={Java:function(content){console.log('Java值为',content);},PHP:function(content){console.log('PHP值为',content);},Python:function(content){console.log('Python值为',content);},}//测试用例Factory('Python','我是Python');6.3原型模式1.定义:设置函数的原型属性2.应用:实现继承3.代码:

functionAnimal(name){//属性this.name=name||'Animal';//实例方法this.sleep=function(){console.log(this.name+'正在睡觉!');}}//原型方法Animal.prototype.eat=function(food){console.log(this.name+'正在吃:'+food);};functionCat(){}Cat.prototype=newAnimal();Cat.prototype.name='cat';//TestCodevarcat=newCat();console.log(cat.name);//catconsole.log(cat.eat('fish'));//cat正在吃:fishundefinedconsole.log(cat.sleep());//cat正在睡觉!undefinedconsole.log(catinstanceofAnimal);//trueconsole.log(catinstanceofCat);//true6.4单例模式1.定义:只允许被实例化依次的类2.应用:提供一个命名空间3.代码:

1.定义:不改变原对象的基础上,给对象添加属性或方法2.代码

1.作用:解决类与对象,对象与对象之间的耦合2.代码:

HTTP是一个连接客户端,网关和服务器的一个协议。

支持客户/服务器模式:可以连接客户端和服务端;简单快速:请求只需传送请求方法,路径和请求主体;灵活:传输数据类型灵活;无连接:请求结束立即断开;无状态:无法记住上一次请求。

无连接:可以通过自身属性Keep-Alive。

HTTP(S)请求地址→DNS解析→三次握手→发送请求→四次挥手

在这里插入图片描述

只允许客户端发送GET这一种请求;且不支持请求头,协议只支持纯文本;无状态性,每个访问独立处理,完成断开;无状态码。

有身份认证,三次握手;请求与响应支持头域;请求头内容;

响应头内容;

注意

请求头增加Cache-Control

采用二进制格式传输多路复用,其实就是将请求数据分成帧乱序发送到TCP中。TCP只能有一个steam,所以还是会阻塞报头压缩服务器推送主动向B端发送静态资源,避免往返延迟。

1.是基于QUIC协议,基于UDP2.特点:自定义连接机制:TCP以IP/端口标识,变化重新连接握手,UDP是一64位ID标识,是无连接;自定义重传机制:TCP使用序号和应答传输,QUIC是使用递增序号传输;无阻塞的多路复用:同一条QUIC可以创建多个steam。

3.协商缓存对比:etag优先级高于last-modified;4.etag精度高,last-modified精度是s,1s内etag修改多少次都会被记录;last-modified性能好,etag要得到hash值。

5.浏览器读取缓存流程:会先判断强缓存;再判断协商缓存etag(last-modified)是否存在;存在利用属性If-None-match(If-Modified-since)携带值;请求服务器,服务器对比etag(last-modified),生效返回304。

THE END
1.枚举类型简单理解腾讯云开发者社区注意:System.Enum 类型是所有枚举类型的抽象基类(它是一种与枚举类型的基础类型不同的独特类型),并且从 System.Enum 继承的成员在任何枚举类型中都可用。存在从任何枚举类型到System.Enum 的装箱转换,并且存在从 System.Enum 到任何枚举类型的取消装箱转换。System.Enum 本身不是枚举类型。相反,它是一个类类型,所有枚https://cloud.tencent.com/developer/article/2477568
2.2024年12月19日随笔档案CloverJoyi摘要: 枚举思想——算法学习(一) 前言 在算法学习的道路上,枚举思想是一种简单却强大的思想。作为一种暴力求解方法,枚举算法通过穷尽所有可能的解,从中找到满足条件的最优解或所有解。虽然它看似“低效”,但在解决许多实际问题时却显得直观且有效,尤其是在问题规模可控的情况下。 (本文代码均使用C#语言) 概念 枚https://www.cnblogs.com/CloverJoyi/p/archive/2024/12/19
3.愚数的定义和应用嘲是什么?这些应用如何提升数据分析效率?在密码学中,余数运算常用于加密和解密算法,以增加数据的安全性。 在循环和周期性问题中,余数可以帮助确定某个元素在周期中的位置。比如一周有 7 天,计算经过若干天后是星期几,就可以通过计算总天数除以 7 的余数来确定。 在资源分配问题上,余数能够辅助判断资源分配的剩余情况。例如将一定数量的物品平均分配给若干https://funds.hexun.com/2024-12-16/216204553.html
4.小学(奥数题):五年级数学思维训练7《枚举法》【分析】用一个四位数表示田忌的马的出场顺序,按照顺序枚举出所有方法:1423、2143、2413、3124、3142、3412、3421、4123、4132、4213、4312、4321,所有共有12种方法。 6. 小珊到邮局购买5张邮票,并要求这些邮票的式样都要相同且全部都要互相连接在一起(https://mp.weixin.qq.com/s?__biz=MzU3NTkzMzk4Ng==&mid=2247631745&idx=8&sn=293879d5466ce507db6b7d33d2a55784&chksm=fc29dd3bc314acf8293ed562dc23abcd91810d258fe453bfc8b00fb8fe80e447f5349b87a70d&scene=27
5.Go语言实现MerkleTree(但是这样有一个问题,全节点是根据什么找到对应的红色哈希值的呢?这一点暂时还不是很清楚,后续弄清楚了正确完整的过程会回来补充,有大佬懂的可以发在评论区) 2. Go语言实现 定义默克尔树节点结构和默克尔树结构 // MerkleNode 默克尔树节点结构typeMerkleNodestruct{Left*MerkleNodeRight*MerkleNodeData[]byte}// https://zhuanlan.zhihu.com/p/13482161972
6.枚举法算法视频解析枚举法和解析法的区别?六、枚举法是什么? 枚举法(Enumeration Method)又叫穷举法或者暴力法,是一种搜寻所有可能答案的算法。其基本思想就是通过逐一列举所有可能的情况,从中选出符合条件的结果。枚举法适用于问题规模较小、并且不易用其他算法处理的情况。枚举法可以在较短时间内求得结果,但随着问题规模的增大,计算量也会成倍增长,因此对https://tool.a5.cn/article/show/48402.html
7.枚举算法(精选六篇)并行枚举(m,n)-选择算法的基本思想是:将待查找数据进行分组,由p个处理机并发地调用串行枚举(m,n)-选择算法对各分组进行(m,n)-选择,再将各分组选出的m个最小数据重新组成待查找数据,递归地进行并行枚举(m,n)-选择,当待查找数据元素的个数足够小(分组数为1)时,直接进行串行(m.n)-枚举选择。算法描述如下https://www.360wenmi.com/f/cnkey6jhs3mx.html
8.《枚举算法》教学设计我们把解决上述问题所用的方法称为枚举算法。 教师给出枚举算法的定义: 一一列举出问题所有可能的解,并在逐一列举的过程中,检验每个可能解是否是问题的真正解,若是,则采纳这个解,否则抛弃它。这种方法就叫做枚举算法。 讨论一: 根据定义和开锁过程,试总结用枚举算法解题的关键有哪些? https://qpez.qpedu.cn/kcjh/jxqjs/208532.htm
9.常见算法思想1:枚举法一、枚举法 枚举算法的思想是:将问题的所有可能的答案一一列举,然后根据条件判断此答案是否合适,保留合适的,丢弃不合适的。 使用枚举算法解题的基本思路如下所示: (1)确定枚举对象、枚举范围和判定条件。 (2)逐一枚举可能的解,验证每个解是否是问题的解。 https://www.jianshu.com/p/9f2b46e8e7cf
10.详细实例说明+典型案例实现对枚举法进行全面分析C++一、枚举法是什么? 1.简要介绍 枚举法又被称为穷举法、暴力法,是一种常见的数学方法。也是经常被使用的一种算法,它的核心思想:将问题所有的可能性列举出来,再根据具体问题的要求去逐一列举解答。或者为了去便于解决问题,进而将问题分为不重复,不遗漏的多种情况,对其进行逐一解决从而最终达到解决整个问题的目的。该https://blog.51cto.com/zhangzhichaoya/6021768
11.枚举法用枚举法解题的最大的缺点是运算量比较大,解题效率不高,如果枚举范围太大(一般以不超过两百万次为限),在时间上就难以承受。但枚举算法的思路简单,程序编写和调试方便,比赛时也容易想到,在竞赛中,时间是有限的,我们竞赛的最终目标就是求出问题解,因此,如果题目的规模不是很大,在规定的时间与空间限制内能够求出解https://baike.sogou.com/v7938570.htm
12.高中信息技术枚举算法经管文库(原现金交易版、、、1137029 枚举法:象这种列举出问题的所有可能解,并在逐一列举的过 注意:在列举的 枚举算法找到https://bbs.pinggu.org/thread-13333730-1-1.html
13.面向时序图数据的快速环枚举算法?E-mail: jos@iscas.ac.cn http://www.jos.org.cn Tel: +86-10-62562563 面向时序图数据的快速环枚举算法? 潘敏佳 1, 李荣华 1, 赵宇海 2, 王国仁 1 1(北京理工大学 计算机科学与技术学院,北京 100081) 2(东北大学 计算机科学与工程学院,辽宁 沈阳 110819) 通讯作者: 李荣华, Email: lironghuabit@https://jos.org.cn/jos/article/pdf/5968
14.四个实例超详细讲解Java贪心和枚举的特点与使用java贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解,枚举法的本质就是从所有候选答案中去搜索正确的解,枚举算法简单粗暴,他暴力的枚举所有可能,尽可能地尝试所有的方法https://www.jb51.net/article/243773.htm
15.算法分析与设计期末答案2023秋6.动态规划算法的特点()A:子问题独立 B:自顶向下计算 C:子问题重叠 D:自底向上计算 答案:子问题重叠###自底向上计算 7.时间复杂度为O(nlogn)的排序算法有A:堆排序 B:计数排序 C:快速排序 D:合并排序 答案:合并排序###堆排序 8.枚举算法的优化方法有A:优化数学模型 B:优化数据结构 C:减少枚举变量 https://www.wkebb.com/c/776b56604264529595bfd59c2f472142.html
16.用枚举(穷举)法解猜数字游戏下载用枚举(穷举)法解猜数字游戏绿色版这个计算器使用枚举(也叫穷举)的算法,可以解一些电子辞典上面附带的“猜数字”游戏。 什么是“猜数字”游戏? 出题者想好4个0到9之间互不相同的整数,并按照一定的顺序排列。玩家猜4个数,出题者回答形如“mAnB”,其中m和n是0到4之间的整数,m表示数字正确且在正确的位置上的数字个数,n表示数字正确但不在在正http://www.onlinedown.net/soft/60077.htm
17.啊哈!算法这就是最简单的枚举算法。枚举算法的基本思想就是“有序地去尝试每一种可能”。 现在小哼又遇到一个稍微复杂一点的奥数题,□□□+□□□=□□□,将数字1~9分别填入9个□中,每个数字只能使用一次使得等式成立。例如173+286=459就是一个合理的组合,请问一共有多少种合理的组合呢?注意:173+286=459 与 286+https://www.ituring.com.cn/book/tupubarticle/29875
18.算法基础MOOC中国算法代表着用系统的方法描述解决问题的策略机制,北京大学《算法基础》课程将带你一一探索枚举、二分、贪心、递归、深度优先搜索、广度优先搜索、动态规划等经典算法,体会他们巧妙的构思,感受他们利用计算解决问题的独特魅力。顺利完成本课程,你将不但能够掌握这些算法的原理,还能够对这些算法进行灵活应用以及准确实现。本https://www.mooc.cn/course/1516.html
19.枚举(穷举)算法枚举穷举如一定要把数值赋予枚举变量,则必须用强制类型转换,如: a=(enum weekday)2;其意义是将顺序号为2的枚举元素赋予枚举变量a,相当于: a=tue; 还应该说明的是枚举元素不是字符常量也不是字符串常量, 使用时不要加单、双引号。 六、枚举算法实例 百钱买百鸡 https://blog.csdn.net/qq_43657344/article/details/89049022
20.枚举算法60秒读懂世界本文将深入探讨枚举算法的基本原理、应用场景、优缺点以及在实际问题中的优化策略。通过对枚举算法的全面解析,帮助读者更好地理解其在算法领域的重要性。 一、枚举算法的基本原理 定义:枚举算法是一种穷举所有可能性的算法,通过对问题解空间中所有候选解进行逐一检查,以找出满足条件的最优解。 https://blog.yyzq.team/post/468420.html
21.(插补模式算法)InterpolationMode枚举枚举(亦称穷举)算法 原理:枚举法的本质就是从所有候选答案中去搜索正确的解,使用该算法需要满足两个条件:(1)可预先确定候选答案的数量;(2)候选答案的范围在求解之前必须有一个确定的集合。 核心思想:枚举所有的可能。枚举算法简单粗暴,他暴力的枚举所有可能,尽可能地尝试所有的方法。虽然枚举算法非常暴力,而且速度可https://www.pianshen.com/article/89611033396/
22.“枚举算法”教学实践的几点反思“枚举算法”并没有出现在我们高中信息科技教材上,然而它又是非常普遍和实用的算法之一,因此,在学生已经能够理解并掌握程序设计的三种基本结构之后,我们备课组决定将此纳入课堂,作为循环结构的拓展之一。我也在此基础上进行了教学实践与反思。 教学设计 本节课的教学目标,知识技能方面,要求学生理解枚举法的概念https://www.qpshs.sh.cn/site/73ee013c-6b37-41a3-b0e1-71a0871ff706/detail/3a59efd3-f778-4616-9d9e-6e9053421306_222a947a-688e-46e2-925e-00b84ff8fd4e.html