JS由那三部分组成?
ECMAScript是JavaScript的核心,定义了语言的基础特性,如变量、函数、数组、对象等。
DOM文档对象模型提供了可以让开发者操作网页上的元素和它们的行为。如点击按钮等。
BOM浏览器对象模型提供了与浏览器交互的方式。如打开新的窗口,或获取页面的大小等。
JS有哪些内置对象?
Object对象、Array数组、String字符串、Number数字、Boolean布尔对象、Date日期对象、
RegExp正则表达式、Function函数对象、Math数学对象、Promise对象用于异步编程,表示一个最终可能完成或失败的操作。
JS的数据类型有哪几种以及它们的区别?
Number:用于表示整数和浮点数(如:42、3.14159)。
BigInt:用于表示任意大的整数(如:9007199254740991n、0x7FFFFFFFFFFFFFFF n)。
String:用于表示文本数据(如:“Hello, World!”)。
Boolean:用于表示逻辑值(真或假)。
Null:用于表示一个空值。
Undefined:用于表示未定义的值。
Symbol:表示一个唯一且不可变的数据类型。
Object:用于表示复杂的数据结构(如:对象、数组、函数等)。
null和undefined的区别?
作者设计js时先设计了null,因为借鉴了java语言,null可以被隐式转化,因此undefind是为了填补null的缺点而提出的,null它表示‘无’的对象(空指针异常)null是一个空对象;undefined它表示‘无’的原始值,转为数值时为NaN,不会被隐式转化。例如:undefined+1打印结果为NaN,而null+1 打印结果为1,是因为null与数字类型相加,null被隐式转化为了0。
操作数组的方法有哪些,哪些改变数组,哪些不改变原数组?
改变原数组:
sort():对数组元素进行排序,改变原数组。
splice():增加、删除或替换元素,改变原数组。
push():向数组末尾添加一个或多个元素,改变原数组。
pop():删除并返回数组的最后一个元素,改变原数组。
shift():删除并返回数组的第一个元素,改变原数组。
unshift():向数组的开头添加一个或多个元素,改变原数组。
reverse():反转数组的元素顺序,改变原数组。
不改变原数组:
slice()返回一个新的数组对象,包含从开始到结束(不包括结束)的原数组的浅拷贝。
concat()返回一个新数组,包含连接两个或更多数组的结果。注意,这个操作不会改变原来的数组。
map()返回一个新数组,包含通过应用回调函数到每个元素而生成的。
filter()返回一个新数组,包含通过应用测试函数到每个元素并满足条件的元素。
reduce(),reduceRight() 从左/右开始遍历数组并累加结果,最后将所有值减少到一个单一的值。
every()每一个元素都满足条件,则返回true,否则返回false,一般适用于前端精准搜索。
some()只要有一个以上元素满足条件就返回true,否则返回false,退出循环,一般适用于前端模糊搜索。
数组去重的方法有哪些?处理多维数组最大值?
new set()方法去重。
循环数组+ indexof进行去重。
使用扩展运算符将多维数组转换为一维数组。
flat()用于将一个多维数组转换为一个一维数组,按照指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
JS对数据类的检测方法有哪些?
typeof 不能判断null,监测null返回object类型
instanceof 不能判断null和undefined
constructor不能判断null和undefined,其余都可以判断,但因为类的constructor可以随意更改,因此会存在判断不准确的问题
Object.prototype.toString.call()方法是最准确的检测类型的方法
隐式转化:+号只要一边是字符串,另一边也会转化为字符串,任何数字类型行和字符串相加结果都为字符串;除了+号,其他都会把数据转化为number类型。
显示转换:转化为数字类型 Number(str) ;只保留整数 parseInt(str) ;可以保留小数 parsefloat(str)。
防抖和节流是什么以及防抖函数和节流函数手写的思路?
防抖是单位之间内频繁触发,只执行最后一次触发事件,那手写一个防抖函数主要使用的是setTimeout来实现的,首先声明定时器变量,然后当鼠标每次滑动先判断是否有定时器,如果有先清除之前的定时器,如果没有定时器,则开启定时器并调用要执行的函数,将定时器保存在变量中。它使用的场景主要是输入框输入文本,在输入完成之后发起请求,而不是输入一个字符发一个请求。
节流是单位之间内频繁触发,只执行一次触发事件,那手写一个节流函数主要使用的也是setTimeout来实现的,首先声明一个定时器,然后当鼠标每次滑动都先判断是否有定时器,如果有定时器,则不开启新的定时器,执行定时器中的函数,当定时器函数执行完毕清除定时器,如果没有定时器则开启新的定时器,并存在变量中。它使用的场景主要是鼠标移动或页面缩放等。
箭头函数、普通函数、匿名函数的区别?
箭头函数不存在变量提升,没有arguments动态参数,在箭头函数中不会创建自己的this,并且会指向上一层作用域的this,箭头函数也不适用于构造函数,箭头函数不可以用作Generator函数。
普通函数具有自己的作用域,可以访问其外部的变量,并且有自己的this上下文,普通函数中的this谁调用,this就会指向谁。
匿名函数没有函数名称,匿名函数通常用于在需要函数作为参数或返回值的地方使用,例如回调函数、高阶函数等,匿名函数可以访问其外部的变量,即使这些变量在函数声明之前就已经存在。
let、val、const的区别?
var是ES5提出的,而let和const是ES6提出的,其中const声明的是常量,一旦声明必须赋值,不能使用null占位,声明后不能修改,如果声明的是复合类型数据,可以修改其属性,let和var声明的是变量,声明后可修改,声明时也可以不赋值,var允许重复声明变量,后边会覆盖前面的变量。let和const在同一作用域不允许重复声明变量,会报错。var声明的变量存在变量提升,将变量提升到当前作用域的顶部,值为undefined,而let和const不存在变量提升,那var不存在块级作用域,let和const存在块级作用。
说说JS变量提升?
var关键字、函数变量、函数表达式都会发生变量提升,对于var关键字声明的变量会将变量提升到当前作用域顶部,但是此时打印的值为undefined。对于普通函数,函数体内的变量提升,但不会提升函数体代码,因此在函数提升后如果尝试调用函数会报错,因为函数体还没有被定义。对于函数表达式,实质上就是变量提升,会将整个函数表达式提升到当前作用域的顶部,因此在函数表达式提升后,可以立即调用函数。
说一下闭包,闭包有什么特点?
一个函数访问了此函数的父级以上的作用域中的变量,即内层函数+外层函数的变量为闭包。
闭包的作用就是函数内部可以访问到函数父级作用域的变量,这样呢可以减少全局变量的定义,避免全局变量的污染。但是闭包涉及跨作用域的访问,会导致性能损失,因此涉及到跨作用域的变量需要定义为局部变量,减轻对性能的影响。而且在ie浏览器中,可能造成内存泄露;所以在变量使用后,给该变量赋值null用来清除变量。
前端的内存泄漏怎么理解?
因为在函数内部return了一个函数,在全局被使用,而全局作用域只有在页面关闭时才会销毁,按照标记清除法,fn是不会被销毁,所以会产生内存溢出或泄露的情况。
说说垃圾回收机制?
js内存的分配和回收都是自动完成的,那内存的生命周期分为三步首先进行内存分配,首先内存分配,在声明变量函数或对象时系统会自动分配内存;然后使用内存,读写内存使用变量和函数;最后内存回收,在变量使用完之后由垃圾回收器自动回收。全局变量一般会在关闭页面时回收,而局部变量的值通常会被自动回收,但在某些情况下可能需要手动管理内存,如闭包,因此会出现内存泄露的问题。
垃圾回收机制原理是通过扫描内存中的对象,判断哪些对象已经不再被程序使用,然后将这些对象所占用的内存空间释放出来。
垃圾回收机制算法:
引用计数法是看对象是否指向它的引用,并记录引用的次数,如果被引用了一次,则记录1次,多次会进行累加,如果减少引用就会进行减减操作,如果引用次数为0,则会释放内存并且给此对象赋值为null,但是它存在问题对象之间的相互引用,嵌套问题无法进行释放。
标记清除法是从全局出发,将不再使用的对象定义为无法达到的对象,从根部出发定时扫描内存中的对象,凡是能从根部到达的对象,是需要使用的,无法从根部出发访问不到的对象被标记为不再使用并进行回收,它解决了循环引用的问题,根部访问不到会被清除。
JS中常见字符串方法有哪些?
length:字符串长度
split:分隔符,字符串拆分成数组
substring:截取索引,结束索引号,用于字符串截取
startWidth:检测字符串,检测位置索引,是否以某字符开头
includes:判断一个字符串是否包含在另一个字符串中
toLouerCase:转化为小写
replace:替换字符串,正则匹配
toUpperCase:字母转化为大写
indexof:检测是否包含某个字符
match:查找字符串,正则匹配
JS中的宏任务和微任务?
JS是单线程语言,执行过程是先执行同步任务,然后再执行事件循环内容。消息队列是一个先进先出,并将各种消息存放在在栈中的队列。事件循环是指主线程反复从消息队列中取消息然后去执行的过程。事件循环任务分为微任务如promise.then和宏任务定时器setTimeout。执行宏任务的前提是先将所有微任务执行完之后,promise.then为微任务,而promise中的为同步任务。
JS的事件流和事件委托(事件代理)是什么?
事件流是事件完整执行的流动路径,从父元素到子元素称为捕获,然后从子元素到父元素称为冒泡。事件委托是把原本需要绑定在子元素上事件委托给它的父元素,让父元素来监听子元素的冒泡事件,并在子元素放生事件冒泡时找到子元素。而事件代理的原理是使用e.target触发事件冒泡的子元素,并根据e.target.tagName判断获取当前对象名称,这样可以减少事件的定义,减小内存消耗。那有了冒泡和捕获就会有阻止冒泡和捕获的方法,防止冒泡捕获e.stopPropagetion(),阻止默认行为e.preventDefault()。在鼠标移动事件中mouseover和mouseout会有冒泡效果,但mouseenter和mouseleave没有冒泡效果一般会推荐使用。
ES6的新特性有哪些?
新增了块级作用域(let、const)
提供了定义类的语法糖(class)
新增了一种基本数据类型(Symbol)
新增了变量的解构赋值
函数参数允许设置默认值
新增了箭头函数
数组新增了一些API,如isArray/from/of方法
数组实例新增了entries()、keys()和values()等方法
对象和数组新增了扩展运算符
ES6新增了模块化(import/export)
ES6新增了Set和Map数据结构
说一下原型和原型链?
原型可以解决对象的共享属性和共享方法,可以解决构造函数中内存浪费的问题。js规定每个构造函数都有一个prototype属性,指向另一个对象的原型对象,可将不变的方法直接定义在prototype上以便共享。那在构造函数和原型对象中的this都指向实例化对象。一般公共属性写在构造函数中,公共方法写在原型对象中。而constructor属性指向该原型对象的构造函数。
对象原型 __proto__并不是标准js属性,在控制台中[[prototype]] 就是 __proto__且为只读属性,用来表明当前对象指向原型对象prototype,实例对象中的对象原型指向原型对象prototype,对象原型里有constructor属性,它包含在实例对象中,指向它关联的构造函数。它的意义是为对象成员查找机制提供一个方向或者一条路线。
原型链是一个对象查找它的某个属性或方法,首先查找对象本身是否有该属性或方法,如果对象本身没有此方法那就去构造函数中去找,如果没有构造函数中没有那就去对象的原型中找,如果没有对象的原型中没有就去构造函数的原型中找,如果构造函数中的原型也没有去当前对象原型中的原型中查找,因为每一个对象中都会有对象原型属性,因此查找对象的原型对象,这样形成一条链为原型链,原型链最顶端为null。
new操作符实现了什么?
创建了一个空对象,将空对象的原型指向构造函数的原型,将空对象作为构造函数的上下文,改变this指向,对构造函数有返回值的处理判断,如果返回基本类型,则忽略返回值,如果是引用类型,则返回的是return的值,普通函数this指向的是window,而new之后函数指向对象。
判断变量是不是数组有哪些方法?
isArray、instanceof、原型对象、isPrototypeof、constructor这几种方法可判断变量是否为数组。
说说JS作用域、作用域链?
局部作用域只能在函数内部被访问,块级作用域或函数作用域,函数内部声明的变量,在函数外部无法被访问;函数的参数也是函数内部的局部变量;不同函数内部声明的变量无法相互访问。
全局作用域在全局中定义的变量,window对象动态添加属性默认为全局变量,函数中未使用关键字声明的变量为全局变量,一般情况下尽可能减少全局变量,防止全局变量污染。
作用域链的本质是变量查找机制,在函数被执行时,优先在当前函数作用域中查找变量,如果当前作用域找不到才会依次逐级查找父级作用域直到全局作用域。
规则:声明变量>普通函数>参数>变量提升
函数内部变量没有声明,直接赋值,可以当全局变量使用;函数内部形参可以为函数的局部变量,在能够访问到的情况下先在局部查找,局部没有在全局找,就近原则。
JS是如何实现继承的?
ES6方法继承新增了一个关键字 extend ,同时还给出了另外一个关键字 class,通过class 构造出一个类,通过 extend 可以使得一个类继承另外一个类的属性和方法。super关键字,子类必须在constructor方法中调用super方法。
原型链继承把实例的父类给子函数的原型,该实例是子类的实例,也是父类的实例,父类新增原型方法和属性,子类都能访问到,简单易于实现。但是因原型对象的属性是共享的,修改一个对象属性,其他对象的该属性也变了,创建子类实现例,无法向父类构造函数传递参数。
构造函数继承在子类中调用父类.call(),复制了一份父类的属性或者方法给子类,它解决了子类实例共享父类引用属性的问题,创建子类实例时,可以向父类构造函数传递参数。但无法实现复用,每一个子类实例都有一个新的run函数,如果实例对象多了,内存消耗过大。
组合继承是原型链和构造函数组合继承,不存在引用属性共享的问题;可传参数,且方法可复用。但子类原型上有一份多余的父类实例的属性。
JS中关于this指向的问题?
全局上下文:在全局上下文中,this指向全局对象。在浏览器中,全局对象是window。
函数调用:在函数被调用时,this通常指向调用该函数的对象。如果在函数内部没有使用new关键字创建新对象,那么this通常指向全局对象。
构造函数:当一个函数被用new关键字创建新对象时,this指向新创建的对象。
对象方法:当一个方法被一个对象调用时,this指向该对象。
事件处理器:当一个函数被用作事件处理程序时,this指向触发该事件的对象。
箭头函数:没有自己的this上下文,因此不能在箭头函数内部改变this的值。
call、apply、bind的区别?
三者都是改变函数体内this指向,那区别呢其中call和apply是立即会执行的,而bind返回的是函数,需要手动调用才可执行;apply第二个参数是数组,而bind和call的参数会有多个。那使用场景呢apply会在数字数组取最大值使用,因为它的第二个参数为数组Math.max.apply(),而bind会在给某个dom元素添加点击事件使用,因为此方法不会立即执行函数,并且可以改变this指向。
script标签里面的async和defer的区别?
async和html解析同步的,不是顺次执行js脚本,谁先加载完先执行谁。
defer是等html全部解析完成才会执行js代码,顺次执行脚本。
setTimeout、setInterval的区别以及最小执行时间是多少?
延时函数setTimeout只执行一次,间歇函数setInterval每隔一段时间执行一次
setTimeout和setInterval的最小执行时间都为4毫秒
扩展运算符在什么场景下用?
主要用于将可迭代的元素序列展开,插入到另一个序列或表达式中。
例:数组合并,函数传递多个参数时可以使用扩展运算符,类构造函数中可以使用扩展运算符将可迭代对象作为构造函数的参数,剩余部分插入到字符串中,与解构赋值结合使用从数组或对象中提取值。
用递归的时候有没有遇到什么问题?
栈溢出:递归函数会创建大量的临时函数调用,这些调用会占用内存栈。如果递归深度太深,可能会导致栈溢出错误。
重复计算:递归函数可能会重复计算相同的子问题,这可能导致效率低下。为了避免这种情况,可以使用一些优化技巧,如记忆化搜索或动态规划。
尾递归优化:在某些编程语言中,可以使用尾递归优化来避免栈溢出问题。但是,这需要编写特定的代码结构,并且不是所有的语言或编译器都支持这种优化。
递归终止条件设置不当:如果没有正确设置递归终止条件,递归函数可能会无限循环,导致程序崩溃。
深拷贝和浅拷贝的区别以及原理?
浅拷贝是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间,当内存销毁的时候,指向对象的指针,必须重新定义才能够使用。
深拷贝拷贝的是对象的具体内容,内存地址是自主分配的,拷贝结束之后两个对象虽然存的值是一样的,但是内存地址不一样,两个对象页互相不影响,互不干涉。
浅拷贝原理:es6中Object.assign()、扩展运算符、Array.prototype.slice都可进行浅拷贝,浅拷贝首先创建一个新对象,然后使用for in循环遍历此对象,利用hasOwnProperty来检测属性是否为对象的自有属性,如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型的内存地址,拷贝的就是内存地址。
深拷贝原理:递归、JSON.stringify()都可进行深拷贝,深拷贝会递归遍历此对象,检查每个属性和子对象是否是基本数据类型,如果是直接复制数据;如果不是则递归地继续遍历并创建新的对象。此过程会创建一个全新的对象,该对象在内存中有自己的地址,与原始对象无关。
ajax是什么?怎么实现的?
AJAX是一种在无需重新加载整个网页的情况下,与服务器交换数据并更新部分网页内容的技术。
实现AJAX的过程:
创建XMLHttpRequest对象是用于与服务器交换数据的对象。
建立与服务器通信的HTTP请求,并指定请求的URL、请求方法和请求头等信息。
通过调用XMLHttpRequest对象的send()方法,将请求发送到服务器。
处理服务器响应,使用XMLHttpRequest对象的onreadystatechange事件处理程序来接收服务器响应。当onreadystate属性的值发生变化时,事件处理程序会被触发,并根据不同的状态值执行相应的操作。
在onreadystatechange事件中根据服务器返回的数据,动态地更新网页的内容。
javascript 代码中的"use strict"是什么意思? 使用它区别是什么?
"use strict"是用于在严格模式下执行代码。
禁止变量提升,
禁止使用 with 语句,
禁止使用 delete 操作符删除变量、函数或函数参数,
禁止复制和增加字符串,
禁止八进制数字文字,
禁止使用 eval 函数创建变量或函数,
禁止使用 arguments.callee 和 arguments.caller。
promise的内部原理是什么?有几种状态?它的优缺点是什么?
promise是异步编程的一种解决方案,它有三种状态:pending(初始状态,既不是成功,也不是失败状态)、fulfilled(操作成功完成)、rejected(操作失败)。
promise可以将异步数据获取和业务逻辑进行分开,有利于代码复用,并且支持链式调用,可避免回调地狱。
promise的缺点是代码逻辑顺序与执行顺序不一致,不利于阅读与维护,并且一旦新建就会立即执行,无法中途取消。
promise和async await的区别是什么?
执行方式:Promise是异步编程的一种解决方案,是一个构造函数。async/await则是基于Promise实现的,用于简化Promise的链式操作,使异步代码看起来更像同步代码。
返回对象:Promise返回的是一个对象,需要通过then().catch()去处理数据和捕获异常。async/await则是返回一个Promise,也需要通过then().catch()去处理数据和捕获异常。
书写方式:Promise的书写方式是链式的,容易造成代码多层堆叠难以维护。async/await则是通过try{}.cathc{}进行捕获直接抛出异常,使代码看起来更简洁。
执行顺序:Promise.then()的方式返回就可能在请求还没返回时就先执行了外面的操作。async await则是遇到await就立即先返回结果然后再执行后面的操作。
浏览器的存储方式有哪些以及区别?
localStorage中的键值对是以字符串的形式存储,除非清除,否则长期有效。
sessionStorage数据在页面会话结束时会被清除。
IndexedDB是一个事务型的数据库系统,使用JavaScript对象而非列数固定的表格来储存数据,但使用较少。
Web SQL是一个存储大量数据的数据库,可以保存5MB的信息。
Cookie可以设置失效时间,没有设置的话,默认是关闭浏览器后失效。
存储方式的区别:
生命周期:cookie可设置失效时间,没有设置的话,默认是关闭浏览器后失效;localStorage除非被手动清除,否则将会永久保存;sessionStorage仅在当前网页会话下有效,关闭页面或浏览器后就会被清除。
存放数据大小:cookie大约可以保存4KB左右的数据;localStorage和sessionStorage可以保存5MB的信息。
http请求:cookie每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题;localStorage和sessionStorage仅在客户端(即浏览器)中保存,不参与和服务器的通信。
易用性:cookie需要自己封装,源生的Cookie接口不友好;localStorage和sessionStorage源生接口可以接受,亦可再次封装来对Object和Array有更好的支持。
应用场景:localStorage用于长期存储,sessionStorage用于会话期间数据的存储。
token存在哪里,token登录流程?
Token可以存储在LocalStorage或Cookie中。
Token登录流程:
客户端使用用户名和密码通过ajax向后端发送请求。
服务端收到请求后,验证用户名与密码。
验证成功后,服务端会签发一个Token,再把这个Token发送给客户端。
客户端收到Token后,会把它存储起来,比如放在Cookie里或者Local Storage里。
客户端每次向服务端请求资源的时候需要带着服务端签发的Token。
服务端收到请求后,先验证客户端请求里带着的Token,如果验证成功,就向客户端返回请求的数据。
对DOM和BOM的理解?
DOM文档对象模型,是js为操作html和css提供的api接口,html中的每个标签元素、属性、文本都能看做是一个dom节点,构成dom树。而dom树将html文档以树状结构直观的表现出来,直观体现了标签与标签之间的关系。dom对象是浏览器根据html标签生成的html对象,document对象为页面内最大的对象,提供方法和属性,用来访问和操作网页内容。
常用操作:
getElementById获取第一个元素;getElementsByName根据name 属性获取元素;getElementsByClassName获取页面所有类名一样的元素;getElementsByTagName获取页面所有div元素;querySelector(),querySelectorAll()获取dom元素;
获取/设置元素的属性值:getAttribute、setAttribute
创建节点:createElement、createTextNode、createAttribute
添加节点:appendChild、insertBefore
删除节点:removeChild
返回父节点:parentNode
返回所有子节点,只返回html:children
返回所有子节点,包含文本、html、属性节点:childNodes
下一个兄弟节点:nextSibling
上一个兄弟节点:previousSibling
BOM浏览器对象模型,包含DOM操作,window是一个全局对象,所有通过var定义在全局作用域中的变量,函数都会变成window对象的属性和方法。
location对象中:location.href() url地址,location.search获取url符号?后面部分携带的参数,location.hash获取url符号#后面部分携带的参数,location.reload()用来刷新当前页面传入参数true表示强制刷新。
navigator对象:记录浏览器相关信息,userAgent检测浏览器版本及平台。
history对象:管理历史对象记录,back()、go(-1) 后退; foward()、go(1) 前进。
svg格式了解多少?
svg用来定义用于网络的基于矢量的图形。
svg使用 XML 格式定义图形。
svg图像在放大或改变尺寸的情况下其图形质量不会有所损失。
svg与其他图像格式相比,svg可被非常方便地修改和编辑,可以任意放大图形显示,但绝不会以牺牲图像质量为代价,可在svg图像中保留可编辑和可搜寻的状态。
HTTP协议规定的响应头和请求头有什么?
响应头是响应报文中特有的,便于客户端提供信息:
Date:服务器响应的时间和日期。
Content-Length:响应内容的字节数。
Content-Type:响应内容的MIME类型。
Connection:指示是否保持网络连接状态。
Keep-Alive:指定在同一个连接中发送多个请求的持续时间。
ETag:标识特定版本的资源的特定内容。
Last-Modified:资源的最后修改时间。
Location:重定向接收到的请求的URL。
Set-Cookie:发送一个或多个cookie。
Status:HTTP状态码,例如200表示成功,404表示未找到等。
请求头是请求报文中特有的,它们为服务器提供了一些额外信息:
Host:请求的主机名和端口号。
User-Agent:发送请求的用户代理的信息。
Accept:客户端可接受的响应类型。
Accept-Language:客户端可接受的语言类型。
Referer:原始URL,即从哪个页面跳转过来的。
Authorization:用于HTTP访问认证的凭据。
From:发送请求的电子邮件地址。
Cookie:发送给服务器的cookie信息。
Connection:指示是否保持网络连接状态。
Keep-Alive:指定在同一个连接中发送多个请求的持续时间。
HTTP状态码了解哪些?
1xx:接收信息
2xx:请求成功
3xx:重定向
4xx:客户端错误
5xx:服务器错误
页面的其他事件有哪些了解以及移动端事件?
页面加载事件、页面滚动事件、页面尺寸事件
获取元素大小与位置:e.getBoundingClientRect() 返回元素的宽高以及相对视口的位置。
scrollLeft、scrollTop 被卷去的头部和左侧,配合页面使用,可读写。
clientWidth 、clientHeight获得元素宽和高,不包含边框,外边距,滚动条,只读属性。
offsetWidth 、offsetHeight获得元素宽和高,包含边框,内边距,滚动条,只读属性。
offsetLeft、offsetTop获取元素距离自己定位父级元素左上距离,获取元素位置使用,只读属性。
移动端事件:touchStart触摸到元素触发,touchMove元素滑动触发,touchEnd元素移开触发。
说一下什么是同源策略以及跨域处理?
同源策略是浏览器提供的一种安全功能,指协议、域名、端口号都相同。
跨域的根本原因是浏览器的同源策略不允许非同源的URL之间进行资源的交互。
跨域的方法有:JSONP、CORS、Nginx反向代理。
proxy跨域代理原理:
客户端向服务器发请求,代理服务器与客户端的域名、协议、端口号相同为同源,因此可以发送请求给代理服务器,然后请求数据通过代理服务器转发到真正的服务器获取数据,服务器与服务器之间没有域的限制,所以可将数据返回给代理服务器,然后代理服务器将数据转发给客户端。
解释一下什么是json?
JSON是一种轻量级、基于文本的、可读的格式,常用来数据传输。
JSON.stringify() 是一个函数,可以将一个对象或数组转换成JSON格式的字符串。
JSON.parse() 是一个函数,用于将一个JSON字符串转换成JS对象。
当数据没有请求过来的时候,该怎么做?
在数据加载之前,可以使用占位符如loading效果来显示一些默认信息,以避免界面空白或者加载失败的情况。
数据量较大考虑异步加载的方式,即当用户需要查看某些数据时,才进行加载。
数据是重复性请求的考虑使用缓存机制,将之前请求的数据存储在本地。
数据请求失败考虑使用错误处理机制,返回错误信息给用户提供更好的体验。
面向对象的理解?
把变量和函数封装起来,通过实例化对象在类外部可以访问属性和方法为面向对象编程。
面向对象三大特征:封装 把一种事物的方法和属性封装到对象中,继承 子对象可继承父对象的属性和方法,多态 同一个方法自定义和父定义的内容不同,它的优势是易维护、易复用、效率高、易扩展。
面向对象编程思想实现步骤:
定义类:首先,需要定义问题领域中的对象,并将其抽象为程序中的类。类是一个模板,用于创建具有相同属性和行为的对象。
创建对象:使用类创建对象,每个对象都有自己的属性和方法。
封装:封装是指将对象的属性和方法封装在类中,以隐藏对象的内部实现细节。这可以提高代码的可维护性和安全性。
继承:继承是指一个类可以继承另一个类的属性和方法。这可以促进代码的重复使用和扩展。
多态:多态是指一个接口可以代表不同类型的对象,从而实现不同行为的实现。
ES6中面向对象:class定义类,static静态属性,constructor方法通过new命令生成对象实例时,自动调用该方法,super父类构造函数,extends 继承关键字。
对日期对象的了解?
实例化new关键字
时间戳中getTime()必须实例化,+new Date()简单好用,Date.now()只能得到当前时间戳。
获取当前时间 const date = new Date()
获取指定时间 const date = new Date(‘2023-08-23’)
date.toLocaleString() 2023/8/6 18:20:00
date.toLocaleDateString() 2023/8/12
date.toLocaleTimeString() 18:20:00
前端性能优化手段有哪些?
加载优化:减少HTTP请求、缓存资源、压缩代码、无阻塞、首屏加载、按需加载、预加载、压缩图像、减少Cookie、避免重定向、异步加载第三方资源。
执行优化:CSS写在头部,JS写在尾部并异步、避免img、iframe等的src为空、尽量避免重置图像大小、图像尽量避免使用DataURL。
渲染优化:设置viewport、减少DOM节点、优化动画、优化高频事件、GPU加速。
样式优化:避免在HTML中书写style、避免CSS表达式、移除CSS空规则、正确使用display:display、不滥用float等。
脚本优化:减少重绘和回流、缓存DOM选择与计算、缓存.length的值、尽量使用事件代理、尽量使用id选择器、touch事件优化。
= = 和 = = = 区别
= = 用来比较值,类型不相同的比较会出现隐式转化,通常使用valueof在js后台自动调用,不会显示出来。
= = =比较的是值和类型,一般在项目开发中使用===,这样更严谨。
script标签的位置不同有何区别?
head标签内部当浏览器解析HTML,会按照代码在文件中的顺序进行加载,解析到script标签时,会先下载完所有script,再往下解析其他的HTML,会使网页内容呈现出滞后的问题,用户体验差。
body标签内部当浏览器会先解析完整个HTML页面,然后下载并解析js,这样用户体验会更好。
sort背后的原理是什么
v8引擎中,sort给出两种排序插入排序和快速排序,数量小于10的数组使用insertionSort,比10 大的数组使用快速排序。sort() 方法用于对数组的元素进行排序,并返回数组,默认排序顺序是根据unicode编码进行排序,因此如果数组中出现,如 1,11,111的时候将没法排序,这时需要使用函数进行封装。
Math内置属性方法
Math.PI // 3.1415926
Math.ceil(1.1) // 2 向上取整
Math.floor(1.1) // 向下取整
Math.round(1.4) // 四舍五入
Math.max(1,2,3,4) // 取最大值 4
Math.min(1,2,3,4) // 取最小值 1
Math.abs(-1) // 绝对值
Math.pow(4,2) // 4的2次方
Math.sqrt(16) //平方根
Math.random() // 左闭右开,随机数 Math.random() x (10+1)
Math.floor(Math.random() x (10+1)) // 向下取整
Math.floor(Math.random() x (m-n+1))+n // m~n之间的随机数
异常处理
throw抛出异常信息,程序会终止执行,后边跟的错误信息提示throw new Error(‘错误提示’),Error对象配合throw使用,可以设置更详细的错误信息。
try catch拦截错误信息,但不中断程序执行,如果需要中断可配合throw new Error(‘错误提示’)进行中断,其中finally无论程序是否正确,一定会执行finally中的代码。
常见控制台错误
Miss initializer in const declaration
const 声明时必须赋值
age is not defined
没有声明age
Identifier ‘age’ has already been declared
同一个变量不允许多次声明
Assignment to constant variable
常量不允许重复赋值
样式属性和自定义属性
样式属性:
通过style 操作 修改样式较少的案例,权重较高,写进行内样式
通过className操作 覆盖原来类名,多个类名操作会覆盖前边的
通过classList操作 不会覆盖以前类名 ,追加和删除不会影响之前的类名
自定义属性:data-id=‘1’ ,获取自定义属性的值 使用dataset,divs.dataset 可以获取自定义属性对象集合。
正则表达式
正则表达式可以验证表单、过滤敏感词、提取特定部分字符串。它的使用规则利用//来进行定义规则,regObj.test(‘hh’)用来检测字符串,regObj.exec(‘hh’)用来检测返回的是数组,如果找不到返回null。
边界符:^ 开始值 精确匹配第一个值必须正确,$ 结束值 精确匹配最后一个值必须正确。
量词:*
重复0次或更多次 >=0 ,+
重复1次或更多次 >=1,?
重复0次或1次 >=0 或<=1。{ n } 重复n次,{ n, } 重复n次或更多次,{ n,m } 重复n到m次。
字符类:[] 匹配字符集合,后面的字符只要包含其中任意一个true
预定义类:\d [0-9]
;\D [^0-9]
;\w [a-zA-Z0-9]
;\W [^a-zA-Z0-9]
;\s [\t\r\n\v\f]
空格,换行,制表符;\S [^\t\r\n\v\f]
非空格字符。
修饰符:i 正则匹配时字母不区分大小写,g 正则匹配所有满足正则的结果。
/^[a-zA-Z0-9]$/
小写字母开头,数字结尾,支持小写大写字母以及数字。
/^[1-9][0-9]{4,}$/
第一位数1~9之间,第二位数0~9之间,后四位0~9之间 QQ号。
/^[a-zA-Z0-9-_]{6,16}$/
支持英文、数字、下划线、短横线,并且6~16位长度。
/^\d{4}-\d{1,2}-\d{1,2}$/
日期格式。
构造函数和深入对象
创建对象:字面量创建对象、new Object()、构造函数创建对象。
目的:自定义构造函数可以快捷创建多个类似的对象,将公共属性抽取出来放在一个函数中。
new构造函数的步骤:创建新对象,构造函数中的this指向新对象,执行构造函数的代码,修改this添加属性,返回新对象。
object内置的构造函数:object.keys键返回的是数组;object.values值返回的是数组;object.assign对于对象浅拷贝。
Array内置的构造函数:forEach遍历数组不返回数组;filter过滤数组返回新数组;map迭代数组;reduce累计器返回累计处理的结果用于求和,它的执行过程如果没有初始值,数组第一个元素的值为上一次的值;如果有初始值,起始值为上一次的值。
Number内置的构造函数:toFixed()保留小数位的长度,默认不写为整数部分。
构造函数体现了面向对象的封装特性,构造函数实例创建彼此独立互不影响,构造函数中的this指向实例对象,构造函数中存在内存浪费的问题。
实例成员:通过构造函数创建的对象为实例对象,实例对象中的属性和方法为实例成员。给构造函数传入参数,可创建结构相同值不同的对象,构造函数创建实例对象彼此独立互不影响。
静态成员:构造函数的属性和方法为静态成员,静态成员只能构造函数来访问。