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

js基础知识总结

时间:2023-03-27 23:12:25 HTML

1.JS数据类型分为:原始类型和对象类型;原始类型:布尔数字字符串未定义空符号bigint对象类型:ObjectFunction;原始类型存储在栈中,对象类型存储在堆中,但他的引用地址仍然存在于堆栈中。?题型:对象修饰,将一个对象传入函数,在函数内部修改参数。对于这一类题,记住以下几点:1.对象存储引用地址,传递给别人,赋值给别人。value(栈中存储的内容),一旦其他人修改对象中的属性,所有人都会被修改;2.但是对象一旦被赋值,只要不对原对象重新赋值,原对象就永远不会被修改。2、类型判断1、typeof:原始类型中除了null外,其他类型都可以通过typeof进行判断。(typeofnull=obejct)=>长期存在的错误;2.instanceof使用内部原型链判断是否是构造函数的实例,用于判断具体的对象类型;3.Object.prototype.toString相对来说,判断类型更齐全;Object.prototype.toString.call(1)=>'[ObjectNumber]';Object.prototype.toString.call(null)=>'[ObjectNull]';....4。具体API数组:Array.isArray([])是否为非数:isNaN(',')3、类型转换1、强制转换:Number(false)=>0;Number('1')=>1Number('zg')=>NaN记住转换规则:布尔值转换规则:1、undefinednullfalseNaN''、0、-0都转换为false;2、所有其他值都转换为true,包括所有对象;数字转换规则:1.true为1,false为02,null为0,undefined为NaN,symbol报错2.隐式转换(比较麻烦)4.这个普通函数:1.谁调用这个函数,这个就是谁被调用,没有对象Call,这就是window;2.以下情况优先级最高,this只会绑定c,不会做任何修改:varc=newfoo();c.a=3;console.log(c.a)3.使用call,bind,并申请改变this的方向,优先级仅次于新的箭头函数:箭头函数没有this,所以箭头函数中所有试图改变this方向的尝试都是无效的。箭头函数的this只依赖于定义时的环境。比如下面代码中的fn箭头函数就是在window环境下定义的。无论怎么调用,this都指向窗口。变量a=1;constfn=()=>{console.log(this.a);}constobj={fn,a:2}obj.fn();//1记住规则。例如这个问题:consta={b:2,foo:function(){console.log(this.b);}}函数b(foo){foo();}b(a.foo);//undefinedthis=>window,this.b=>undefined5.闭包定义:如果一个函数可以访问外部变量,那么这个函数就是一个闭包而不是返回函数。`让a=1;//fn是一个闭包函数fn(){console.log(a)}functionfn1(){leta=1;return()=>{console.log(a)}}constfn2=fn1();fn2();详情见:[闭包](https://juejin.cn/post/6947860760840110088#heading-18)`6.newnew操作符可以帮助构造一个实例并将其绑定到this上,执行步骤如下:1.创建一个新对象;2.将对象连接到构造函数原型并绑定this;3.执行构造函数代码;4.返回一个新的对象;一个例外:`functionTest(name){this.name=name;控制台日志(这个);测试{name:'yck'}return{age:26}}constt=newTest('yck');控制台日志(t);//{age:26}console.log(t.name)//'undefined'`7.全局范围;功能范围;块级范围;8.原型![图片](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c5f2308aa8424e7d9bcb5dfc9fe8c58c~tplv-k3u1fbpfcp-zoom-1.image?imageslim)上图总结:1.所有对象有一个属性__proto__指向一个对象,也就是原型;2、每个对象的原型都可以通过构造函数找到构造函数,构造函数也可以通过原型找到原型;3.所有函数都可以通过__proto__找到Function对象4.所有对象Objec都可以通过__proto__找到对象;5.对象之间通过__proto__连接起来,称为原型链。当前对象上不存在的属性,可以通过原型链逐层查找,直到最顶层的Object对象,然后是null9。继承类不是其他语言中的类,它本质上是一个函数;classPerson{}PersoninstanceofFunction//trueES5和ES6继承的区别:1.ES6继承子类需要调用super()获取子类,ES5的话是2.类声明不会通过apply的绑定方法提升,这与let一致。ES5以多种方式实现继承:functionSuper(){}Super.prototype.getNumber=function(){return1;}functionSub(){}Sub.prototype=Object.create(Super.prototype,{constructor:{value:Sub,a:2,}})lets=newSub();s.getNumber();10、深浅拷贝浅拷贝:两个对象的第一层引用不相同,即浅拷贝可以通过assign、Spread运算符等方式实现浅拷贝:```leta={age:1}letb=Object.assign({},a);a.年龄=2;console.log(b.age)//1b={...a}a.age=3console.log(b.age)//2```深拷贝:两个对象中的所有引用都是不同的最简单的深拷贝是使用JSON。parse(JSON.stringify(object)),但只支持JSON类型,无法处理循环引用问题11.Promise1。使用all实现并行需求2.Promise.all错误处理3.手写all实现```functionpromiseAll(promises){returnnewPromise((resolve,reject)=>{if(!Array.isArray(promises)){returnreject('argumentsmustbeArray')}})letcount=0,newValues=newArray(promises.length);for(leti=0;i{count++;newValues[i]=res;if(count===newValues.length){returnresolve(newValues)}},error=>reject(error))}}```4。Promise.race()比较谁最快,总是输出最快的执行```Promise.race([newPromise(function(resolve,reject){setTimeout(()=>resolve(1),1000)}),newPromise(function(resolve,reject){setTimeout(()=>resolve(2),100)}),newPromise(function(resolve,reject){setTimeout(()=>resolve(3),10)})]).then(value=>{console.log(value)//3})```12、与async、await、promise相比,优点是then的调用链可以处理的更清晰和accurately写出代码的缺点是滥用会导致性能问题,因为await会阻塞代码。如果后面的异步代码不依赖前者,但仍然需要等待前者完成,导致代码失去并发,此时应该使用Promise.allvara=0varb=async()=>{a=a+await10console.log('step2',a)//->10}b()a++console.log('step1',a)//->113.事件循环记住:js是单线程语言,同时只能执行一个任务。js中的异步就是延迟执行的同步代码。EventLoop的执行顺序如下:1.执行同步任务2.执行完所有同步代码且执行栈为空后,判断是否有微任务需要执行;3.执行完所有微任务,微任务队列为空4.是否有必要渲染页面5.执行一个宏任务console.log("scriptstart")setTimeout(()=>{console.log(setTimeout)},0)Promise.resolve().then(()=>{Promise.resolve().then(()=>{console.log('queueMicrotask')})console.log("promise")})console.log("scriptend")以上代码执行过程说明:1.console.log执行并打印;2、遇到setTimeout,将回调添加到宏任务中3、遇到Promise.resolve(),此时状态发生变化,所以将then回调添加到微任务队列中;4.遇到console.log时执行并打印,此时执行所有同步任务,分别打印'scriptstart'和'scriptend'。开始判断是否有微任务需要执行。5.微任务队列中有任务。开始执行.then()回调函数6.遇到queueMicrotask,将回调添加到microtask队列7.遇到console.log打印8.查看发现microtask队列中有任务,执行queueMicrotask回调9.遇到console.log打印此时发现microtask队列已经清空,判断是否需要UI渲染。10.执行宏任务,开始执行setTimeout回调。11.遇到console时执行并打印一个macrotask。判断14.模块化CommonJsmodule.exports={a:1}exports.a=1;基本实现varmodule={exports:{}}varexports=module.exportsvarload=function(module){vara=1;模块.exports=a;returnmodule.exports;}CommonJs和ESM的区别是:1.前者支持动态导入,即require('xx.js'),后者使用import();2、前者是同步导入,因为是在服务器端使用,文件都是本地的,同步导入即使主线程卡死也影响不大,而后者是在浏览器中使用,需要下载文件。如果也使用同步导入,会对渲染产生很大的影响。3.前者在导出时,复制值。即使导出的值发生变化,导入的值也不会发生变化,所以如果要更新值,必须重新导入。后者采用实时绑定的方式,导入和导出的值都指向同一个内存地址,所以导入值会随着导出值的变化而变化。15.垃圾收集16.笔迹测试分1.0.1+0.2!==0.3;因为JS使用IEEE754双精度(64位),任何使用IEEE754的语言都有这个问题。出现问题的原因是浮点数用二进制表示时是无穷大的。由于精度的问题,两个浮点数相加会导致stage失去精度,所以在转为十进制的时候就有问题了。解决方法如下:exportconstaddNum=(num1,num2)=>{letsq1,sq2,m;尝试{sq1=num1.toString().split('.')[1].length;}catch(e){sq1=0}try{sq2=num2.toString().split('.')[1].length;}catch(e){sq2=0}m=Math.pow(10,Math.max(sq1,sq2));return(Math.round(num1*m)+Math.round(num2*m))/m}2、防抖简易版:constdebounce=(func,wait=200)=>{lettimer=0;returnfunction(){if(timer)clearTimeout(timer);timer=setTimeout(()=>{func.apply(this,args)},wait)}}