前端面试-- JavaScript篇

JavaScript

1.JS由哪三部分组成?
        ECMAScript:JS的核心内容,描述了语言的基础语法,比如var,for,数据类型(数组、字符串),
        文档对象模型(DOM):DOM把整个HTML页面规划为元素构成的文档
        浏览器对象模型(BOM):对浏览器窗口进行访问和操作
2.JS有哪些内置对象?
        String Boolean Number Array Object Function Math Date RegExp...
        Math
            abs() sqrt() max() min()
        Data
            new Data() getYear() 
        Array
        String
            concat() length  slice() split()
3.操作数组的方法有哪些?
push() pop() sort() splice() unshift() shift() reverse() concat() join() map() filter()
ervery() some() reduce() isArray() findIndex()

​ 哪些方法会改变原数组?

 push() pop() unshift() shift() sort() reverse() splice()
4.JS对数据类的检测方式有哪些?
        typeof()
        instanceof()
        constructor
        Object.prototype.toString.call()
5.说一下闭包,闭包有什么特点?

​ 什么是闭包?函数嵌套函数,内部函数被外部函数返回并保存下来时,就会产生闭包
​ 特点:可以重复利用变量,并且这个变量不会污染全局的一种机制;这个变量是一直保存再内存中,不会被垃圾回收机制回收
​ 缺点:闭包较多的时候,会消耗内存,导致页面的性能下降,在IE浏览器中才会导致内存泄漏
​ 使用场景:防抖,节流,函数嵌套函数避免全局污染的时候

6.前端的内存泄漏怎么理解?

​ JS里已经分配内存地址的对象,但是由于长时间没有释放或者没办法清除,造成长期占用内存的现象,会让内存资源大幅浪费,最终导致运行速度慢,甚至崩溃的情况。
​ 垃圾回收机制
​ 因素:一些为生命直接赋值的变量;一些未清空的定时器;过度的闭包;一些引用元素没有被清除。

7.事件委托是什么?

​ 又叫事件代理,原理就是利用了事件冒泡的机制来实现,也就是说把子元素的事件绑定到了父元素的身上
​ 如果子元素组织了事件冒泡,那么委托也就不成立
​ 组织事件冒泡:event.stopPropagation()
​ addEventListener(‘click’,函数名,true/false) 默认是false(事件冒泡),true(事件捕获)
​ 好处:提高性能,减少事件的绑定,也就减少了内存的占用。

8.基本数据类型和引用数据类型的区别?

​ 基本数据类型:String Number Boolean undefined null
​ 基本数据类型保存在栈内存当中,保存的就是一个具体的值
​ 引用数据类型(复杂数据类型):Object Function Array
​ 保存在堆内存当中,声明一个引用类型的变量,它保存的是引用类型数据的地址
​ 假如声明两个引用类型同时指向了一个地址的时候,修改其中一个那么另外一个也会改变

9.说一下原型链。

​ 原型就是一个普通对象,它是为构造函数的实例共享属性和方法;所有实例中引用的原型都是同一个对象
​ 使用prototype可以把方法挂在原型上,内存值保存一份
​ __proto__可以理解为指针,实例对象中的属性,指向了构造函数的原型(prototype)

10.new操作符具体做了什么?

​ 1.先创建一个空对象
​ 2.把空对象和构造函数通过原型链进行链接
​ 3.把构造函数的this绑定到新的空对象身上
​ 4.根据构建函数返回的类型判断,如果是值类型,则返回对象,如果是引用类型,就要返回这个引用类型

11.JS是如何实现继承的?

​ 1.原型链继承
​ 2.借用构造函数继承
​ 3.组合式继承
​ 4.ES6的class类继承

12.JS的设计原理是什么?

​ JS引擎 运行上下文 调用栈 事件循环 回调

13.JS中关于this指向的问题

​ 1. 全局对象中的this指向
​ 指向的是window
​ 2. 全局作用域或者普通函数中的this
​ 指向全局window
​ 3. this永远指向最后调用它的那个对象
​ 在不是箭头函数的情况下
​ 4. new 关键词改变了this的指向
​ 5. apply,call,bind
​ 可以改变this指向,不是箭头函数
​ 6. 箭头函数中的this
​ 它的指向在定义的时候就已经确定了
​ 箭头函数它没有this,看外层是否有函数,有就是外层函数的this,没有就是window
​ 7. 匿名函数中的this
​ 永远指向了window,匿名函数的执行环境具有全局性,因此this指向window

14.script标签里的async和defer有什么区别?

​ 当没有async和defer这两个属性的时候,
​ 浏览器会立刻加载并执行指定的脚本
​ 有async
​ 加载和渲染后面元素的过程将和script的加载和执行并行进行(异步)
​ 有defer
​ 加载和渲染后面元素的过程将和script的加载并行进行(异步),但是它的执行事件要等
​ 所有元素解析完成之后才会执行

15.setTimeout最小执行时间是多少?

​ HTML5规定的内容:
​ setTimeout最小执行时间是4ms
​ setInterval最小执行时间是10ms

16.ES6和ES5有什么区别?

​ JS的组成:ECMAScript BOM DOM
​ ES5:ECMAScript5,2009年ECMAScript的第五次修订,ECMAScript2009
​ ES6:ECMAScript6,2015年ECMAScript的第六次修订,ECMAScript2015,是JS的下一个版本标准

17.ES6的新特性有哪些?
		 1.新增块级作用域(let,const)
​            不存在变量提升
​            存在暂时性死区的问题
​            块级作用域的内容
​            不能在同一个作用域内重复声明
​        2.新增了定义类的语法糖(class)
​        3.新增了一种基本数据类型(symbol)
​        4.新增了解构赋值
​            从数组或者对象中取值,然后给变量赋值
​        5.新增了函数参数的默认值
​        6.给数组新增了API
​        7.对象和数组新增了扩展运算符
​        8.Promise
​            解决回调地狱的问题。
​            自身有all,reject,resolve,race方法
​            原型上有then,catch
​            把异步操作队列化
​            三种状态:pending初始状态,fulfilled操作成功,rejected操作失败
​            状态:pending -> fulfilled;pending -> rejected 一旦发生,状态就会凝固,不会再变
​            async  await
​                同步代码做异步的操作,两者必须搭配使用
​                async表明函数内有异步操作,调用函数会返回promise
​                await是组成async的表达式,结果是取决于它等待的内容,如果是promise那就是promise的结果,如果是普通函数就进行链式调用
​                await后的promise如果是reject状态,那么整个async函数都会中断,后面的代码不执行
    9.新增了模块化(import,export)
    10.新增了set和map数据结构
        set就是不重复
        map的key的类型不受限制
    11.新增了generator
    12.新增了箭头函数
        不能作为构造函数使用,不能用new
        箭头函数就没有原型
        箭头函数没有arguments
        箭头函数不能用call,apply,bind去改变this的执行
        this指向外层第一个函数的this
        H5标准的存储方式,,他是以键值对进行存储,可以快速读取,适合WEB场景
18.call,aply,bind三者有什么区别?

​ 都是改变this指向和函数的调用,call和apply的功能类似,只是传参的方法不同
​ call方法传的是一个参数列表
​ apply传递的是一个数组
​ bind传参后不会立刻执行,会返回一个改变了this指向的函数,这个函数还是可以传参的,bind()()
​ call方法的性能要比apply好一些,所以call用的更多一点

19.用递归的时候有没有遇到什么问题?

​ 如果一个函数内可以调用函数本身,那么这个就是递归函数
​ 函数内部调用自己
​ 特别注意:写递归必须要有退出条件return

20.如何实现一个深拷贝?

​ 深拷贝就是完全拷贝一份新的对象,会在堆内存中开辟新的空间,拷贝的对象被修改后,原对象不受影响
​ 主要针对的是引用数据类型
​ 1.扩展运算符
​ 2.JSON.parse(JSON.stringify())
​ 3.利用递归函数实现

21.说一下事件循环。

​ JS是一个单线程的脚本语言
​ 主线程 执行栈 任务队列 宏任务 微任务
​ 主线程先执行同步任务,然后才去执行任务队列里的任务,如果在执行宏任务之前有微任务,那么要先执行微任务
​ 全部执行完之后等待主线程的调用,调用完之后再去任务队列中查看是否有异步任务,这样一个循环往复的过程就是事件循环!

22.ajax是什么?怎么实现的?

​ 创建交互式网页应用的网页开发技术
​ 在不重新加载整个网页的前提下,与服务器交换数据并更新部分内容
​ 通过XmlHttpRequest对象向服务器发送异步请求,然后从服务器拿到数据,最后通过JS操作DOM更新页面
​ 1.创建XmlHttpRequest对象 xmh
​ 2.通过xmh对象里的open()方法和服务器建立连接
​ 3.构建请求所需的数据,并通过xmh对象的send()发送给服务器
​ 4.通过xmh对象的onreadystate chansge事件监听服务器和你的通信状态
​ 5.接收并处理服务器响应的数据结果
​ 6.把处理的数据更新到HTML页面上

23.get和post有什么区别?

​ 1.get一般是获取数据,post一般是提交数据
​ 2.get参数会放在url上,所以安全性比较差,post是放在body中
​ 3.get请求刷新服务器或退回是没有影响的,post请求退回时会重新提交数据
​ 4.get请求时会被缓存,post请求不会被缓存
​ 5.get请求会被保存在浏览器历史记录中,post不会
​ 6.get请求只能进行url编码,post请求支持很多种

24.promise的内部原理是什么?它的优缺点是什么?

​ Promise对象,封装了一个异步操作并且还可以获取成功或失败的结果
​ Promise主要就是解决回调地狱的问题,之前如果异步任务比较多,同时他们之间有相互依赖的关系,
​ 就只能使用回调函数处理,这样就容易形成回调地狱,代码的可读性差,可维护性也很差
​ 有三种状态:pending初始状态 fulfilled成功状态 rejected失败状态
​ 状态改变只会有两种情况,
​ pending -> fulfilled; pending -> rejected 一旦发生,状态就会凝固,不会再变
​ 首先就是我们无法取消promise,一旦创建它就会立即执行,不能中途取消
​ 如果不设置回调,promise内部抛出的测u哦呜就无法反馈到外面
​ 若当前处于pending状态时,无法得知目前在哪个阶段。
​ 原理:
​ 构造一个Promise实例,实例需要传递函数的参数,这个函数有两个形参,分别都是函数类型,一个是resolve一个是reject
​ promise上还有then方法,这个方法就是来指定状态改变时的确定操作,resolve是执行第一个函数,reject是执行第二个函数

25.promise和async await的区别是什么?

​ 1.都是处理异步请求的方式
​ 2.promise是ES6,async await 是ES7的语法
​ 3.async await是基于promise实现的,他和promise都是非阻塞性的
​ 优缺点:
​ 1.promise是返回对象我们要用then,catch方法去处理和捕获异常,并且书写方式是链式,容易造成代码重叠,不好维护,async await 是通过tra catch进行捕获异常
​ 2.async await最大的优点就是能让代码看起来像同步一样,只要遇到await就会立刻返回结果,然后再执行后面的操作
​ promise.then()的方式返回,会出现请求还没返回,就执行了后面的操作

26.浏览器的存储方式有哪些?

​ 1.cookies
​ H5标准前的本地存储方式
​ 兼容性好,请求头自带cookie
​ 存储量小,资源浪费,使用麻烦(封装)
​ 2.localstorage
​ H5加入的以键值对为标准的方式
​ 操作方便,永久存储,兼容性较好
​ 保存值的类型被限定,浏览器在隐私模式下不可读取,不能被爬虫
​ 3.sessionstorage
​ 当前页面关闭后就会立刻清理,会话级别的存储方式
​ 4.indexedDB

27.token存在sessionstorage还是loaclstorage?

​ token:验证身份的令牌,一般就是用户通过账号密码登录后,服务端把这些凭证通过加密等一系列操作后得到的字符串
​ 1.存loaclstorage里,后期每次请求接口都需要把它当作一个字段传给后台
​ 2.存cookie中,会自动发送,缺点就是不能跨域
​ 如果存在localstorage中,容易被XSS攻击,但是如果做好了对应的措施,那么是利大于弊
​ 如果存在cookie中会有CSRF攻击

28.token的登录流程。

​ 1.客户端用账号密码请求登录
​ 2.服务端收到请求后,需要去验证账号密码
​ 3.验证成功之后,服务端会签发一个token,把这个token发送给客户端
​ 4.客户端收到token后保存起来,可以放在cookie也可以是localstorage
​ 5.客户端每次向服务端发送请求资源的时候,都需要携带这个token
​ 6.服务端收到请求,接着去验证客户端里的token,验证成功才会返回客户端请求的数据

29.页面渲染的过程是怎样的?

​ DNS解析
​ 建立TCP连接
​ 发送HTTP请求
​ 服务器处理请求
​ 渲染页面
​ 浏览器会获取HTML和CSS的资源,然后把HTML解析成DOM树
​ 再把CSS解析成CSSOM
​ 把DOM和CSSOM合并为渲染树
​ 布局
​ 把渲染树的每个节点渲染到屏幕上(绘制)
​ 断开TCP连接

30.DOM树和渲染树有什么区别?

​ DOM树是和HTML标签一一对应的,包括head和隐藏元素
​ 渲染树是不包含head和隐藏元素

31.精灵图和base64的区别是什么?

​ 精灵图:把多张小图整合到一张大图上,利用定位的一些属性把小图显示在页面上,当访问页面可以减少请求,提高加载速度
​ base64:传输8Bit字节代码的编码方式,把原本二进制形式转为64个字符的单位,最后组成字符串
​ base64是会和html css一起下载到浏览器中,减少请求,减少跨域问题,但是一些低版本不支持,若base64体积比原图片大,不利于css的加载。

32.svg格式了解多少?

​ 基于XML语法格式的图像格式,可缩放矢量图,其他图像是基于像素的,SVG是属于对图像形状的描述,本质是文本文件,体积小,并且不管放大多少倍都不会失真
​ 1.SVG可直接插入页面中,成为DOM一部分,然后用JS或CSS进行操作

​ 2.SVG可作为文件被引入

​ 3.SVG可以转为base64引入页面

33.了解过JWT吗?

​ JSON Web Token 通过JSON形式作为在web应用中的令牌,可以在各方之间安全的把信息作为JSON对象传输
​ 信息传输、授权
​ JWT的认证流程
​ 1.前端把账号密码发送给后端的接口
​ 2.后端核对账号密码成功后,把用户id等其他信息作为JWT 负载,把它和头部分别进行base64编码拼接后签名,形成一个JWT(token)。
​ 3.前端每日请求时都会把JWT放在HTTP请求头的Authorization字段内
​ 4.后端检查是否存在,如果存在就验证JWT的有效性(签名是否正确,token是否过期)
​ 5.验证通过后后端使用JWT中包含的用户信息进行其他的操作,并返回对应结果
​ 简洁、包含性、因为Token是JSON加密的形式保存在客户端,所以JWT是跨语言的,原则上是任何web形式都支持。

34.npm的底层环境是什么?

​ node package manager,node的包管理和分发工具,已经成为分发node模块的标准,是JS的运行环境
​ npm的组成:网站、注册表、命令行工具

35.HTTP协议规定的协议头和请求头有什么?

​ 1.请求头信息:
​ Accept:浏览器告诉服务器所支持的数据类型
​ Host:浏览器告诉服务器我想访问服务器的哪台主机
​ Referer:浏览器告诉服务器我是从哪里来的(防盗链)
​ User-Agent:浏览器类型、版本信息
​ Date:浏览器告诉服务器我是什么时候访问的
​ Connection:连接方式
​ Cookie
​ X-Request-With:请求方式
​ 2.响应头信息:
​ Location:这个就是告诉浏览器你要去找谁
​ Server:告诉浏览器服务器的类型
​ Content-Type:告诉浏览器返回的数据类型
​ Refresh:控制了的定时刷新

36.说一下浏览器的缓存策略。

​ 强缓存(本地缓存)、协商缓存(弱缓存)
​ 强缓:不发起请求,直接使用缓存里的内容,浏览器把JS,CSS,image等存到内存中,下次用户访问直接从内存中取,提高性能
​ 协缓:需要像后台发请求,通过判断来决定是否使用协商缓存,如果请求内容没有变化,则返回304,浏览器就用缓存里的内容
​ 强缓存的触发:
​ HTTP1.0:时间戳响应标头
​ HTTP1.1:Cache-Control响应标头
​ 协商缓存触发:
​ HTTP1.0:请求头:if-modified-since 响应头:last-modified
​ HTTP1.1:请求头:if-none-match 响应头:Etag

37.说一下什么是“同源策略”?

​ http:// www. aaa.com:8080/index/vue.js
​ 协议 子域名 主域名 端口号 资源
​ 同源策略是浏览器的核心,如果没有这个策略就会遭受网络攻击
​ 主要指的就是协议+域名+端口号三者一致,若其中一个不一样则不是同源,会产生跨域
​ 三个允许跨域加载资源的标签:img link script
​ 跨域是可以发送请求,后端也会正常返回结果,只不过这个结果被浏览器拦截了!
​ JSONP
​ CORS
​ websocket
​ 反向代理

38.防抖和节流是什么?

​ 都是应对页面中频繁触发事件的优化方案
​ 防抖:避免事件重复触发
​ 使用场景:1.频繁和服务端交互 2.输入框的自动保存事件
​ 节流:把频繁触发的事件减少,每隔一段时间执行
​ 使用场景:scroll事件

39.解释一下什么是json?

​ JSON是一种纯字符串形式的数据,它本身不提供任何方法,适合在网络中进行传输
​ JSON数据存储在.json文件中,也可以把JSON数据以字符串的形式保存在数据库、Cookise中
​ JS提供了JSON.parse() JSON.stringify()
​ 什么时候使用json:定义接口;序列化;生成token;配置文件package.json

40.当数据没有请求过来的时候,该怎么做?

​ 可以在渲染数据的地方给一些默认的值
​ if判断语句

41.有没有做过无感登录?

​ 1.在相应其中拦截,判断token返回过期后,调用刷新token的接口
​ 2.后端返回过期时间,前端判断token的过期时间,去调用刷新token的接口
​ 3.写定时器,定时刷新token接口
​ 流程:
​ 1.登录成功后保存token 和 refresh_token
​ 2.在响应拦截器中对401状态码引入刷新token的api方法调用
​ 3.替换保存本地新的token
​ 4.把错误对象里的token替换
​ 5.再次发送未完成的请求
​ 6.如果refresh_token过期了,判断是否过期,过期了就清楚所有token重新登录

42.大文件上传是怎么做的?

​ 分片上传:
​ 1.把需要上传的文件按照一定的规则,分割成相同大小的数据块
​ 2.初始化一个分片上传任务,返回本次分片上传的唯一标识
​ 3.按照一定的规则把各个数据块上传
​ 4.发送完成后,服务端会判断数据上传的完整性,如果完整,那么就会把数据库合并成原始文件
​ 断点续传:
​ 服务端返回,从哪里开始 浏览器自己处理

43.面试题:延迟加载JS有哪些方式?
延迟加载:async、defer
例如:<script defer type="text/javascript" src='script.js'></script>
defer : 等html全部解析完成,才会执行js代码,顺次执行js脚本。
async : async是和html解析同步的(一起的),不是顺次执行js脚本(谁先加载完谁先执行)
44.面试题︰JS数据类型有哪些?
基本类型: string、number、boolean、undefined、null、symbol
引用类型:object(function)
45.面试题:null和undefined的区别
1.作者在设计js的都是先设评的null(为什么设计了null∶最初设计js的时候借鉴了java的语言)
2. null会被隐式转换成e,很不容易发现错误
3.先有null后有undefined,出来undefined是为了填补之前的坑。
具体区别: 
JavaScript的最初版本是这样区分的: 
null是一个表示"无"的对象(空对象指针),转为数值时为0;
undefined是一个基本类型,转为数值时为NaN。
46.面试题:=有什么不同?
==: 比较的是值
string == number 	|| 	boolean || number ....都会隐式转换通过valueOf转换(valueOf()方法通常由JavaScript在后台自动调用,并不显式地出现在代码中。)
== ∶除了比较值,还比较类型
image-20250812002721561
47.事件队列(宏任务、微任务)
/*
  宏任务  宏任务队列
    setTimeout setInterval ajax DOM操作

  微任务  微任务队列
    Promise

  主任务>微任务>宏任务
*/
48.面试题︰JS作用域考题
1.除了函数外,js是没有块级作用域。
2.作用域链内部可以访问外部的变量,但是外部不能访问内部的变量。
注意:如果内部有,优先查找到内部,
如果内部没有就查找外部的。
3.注意声明变量是用var还是没有写(window . )
4.注意:js有变量提升的机制【变量悬挂声明】
5.优先级︰声明变量〉声明普通函数>参数>变量提升

面试的时候怎么看:

1.本层作用域有没有此变量【注意变量提升】
2.注意∶js除了函数外没有块级作用域
3.普通声明函数是不看写函数的时候顺序
49.面试题︰JS对象考题

JS对象注意点:

1.对象是通过new操作符构建出来的,所以对象之间不相等(除了引用外)。
2.对象注意:引用类型(通过赋值非new关键字得到的对象)
3.对象的key都是字符串类型;
4.对象如何找属性|方法;
先在对象本身找 ===> 构造函数中找 ===> 对象原型中找 ===> 构造函数原型中找 ===> 对象上一层原型查找

考题一:

[1,2,3] === [1,2,3]	//false	数组是对象,每一个new出来的对象都是独一无二的

考题二:

var a = [1,2,3];
var b = a;
//引用类型。改变a或b都会影响双方数值

考题三:

//如果写的不是字符串,是对象类型则为[object object]
var x = {}
var a = {
	key:1
};
var b = {
	key:2
};

x[a]=123	//x = {[object object]:123}
x[b]=456	//x = {[object object]:456}

console.log(x[a])//其实就是找x.[object object],为456

考题四:

function Foo(){
	getName = function(){//注意是全局的window.
        console.log(1)
        return this;
	}
}
Foo.getName = function(){console.log(2)}
Foo.prototype.getName = function(){console.log(3)}
var getName = function(){console.log(4)}
function getName(){
console.log (5)
}

Foo.getName();//2
getName();//4
Foo().getName(); //1
getName();//1
new Foo().getName();//3
//变量提升
var getName;
function Foo(){
	getName = function(){//注意是全局的window.
        console.log(1)
        return this;
	}
}
function getName(){
	console.log (5)
}

Foo.getName = function(){console.log(2)}
Foo.prototype.getName = function(){console.log(3)}
getName = function(){console.log(4)}


Foo.getName();//2
getName();//4
Foo().getName(); //1
getName();//1
new Foo().getName();//3

考题二

//头条考题
var o = {
    a: 10,
    b:{
    	fn:function(){
    		console.log( this.a );//undefined
            console.log( this );//this指向b对象
    	}
      }
    }
o.b.fn();

考题三

//头条考题
window.name ='ByteDance ';
function A(){
	this.name = 123;
}
A.prototype.getA = function(){
    console.log( this );
    return this.name + 1;
}

let a = new A();
let funcA = a.getA;

funcA();
//变量提升
let a;
let funcA;
function A(){
	this.name = 123;
}

window.name ='ByteDance ';
A.prototype.getA = function(){
    console.log( this );//window
    return this.name + 1;//"ByteDance1"
}
a = new A();
funcA = a.getA;//funcA被赋值为getA函数

funcA();//window.funcA(),this指向window

考题四

var length =.10;
function fn(){
	return this.length + 1;
}
var obj = {
    length:5,
    test1:function(){
    	return fn();
	}
}
obj.test2 = fn;
console.log( obj.test1());
console.log( fn()===obj.test2());
console.log( obj .test1()=obj.test2());
//变量提升
var length;
var obj;
function fn(){
	return this.length + 1;
}

length =10;
obj = {
    length:5,
    test1:function(){
    	return fn();
	}
}
obj.test2 = fn;

console.log( obj.test1());//11
console.log( fn()===obj.test2());//false
console.log( obj.test1()=obj.test2());//false

注意:函数谁调用它,this就指向谁,如果没有改变this指向,那么this指向window

50.面试题︰JS数组去重

方式一:

new set()得到去重后的数据对象

Array.from()对象转换成数组

var arr1 = [1,2,3,2,4,1];

function unique(arr){
	//return [...new Set(arr)];
    return Array.from(new Set(arr))
}
console.log(unique( arr1));

方式二:indexOf

循环把下标只出现一次的参数放进新数组

function clear(arr) {
        let newArr = [];
        for (var i = 0; i < arr.length; i++) {
          if (newArr.indexOf(arr[i]) === -1) {
            newArr.push(arr[i]);
          }
        }
        return newArr;
      }
console.log( clear(arr2) );

方式三:sort

先排序。如果连续两个参数不相等,那就放进新数组里面返回出来

var arr3 = [1,2,3,2,4,1];

	function clear(arr) {
        let newArr = [];
        arr = arr.sort();
        for (var i = 0; i < arr.length; i++) {
          if (arr[i] !== arr[i - 1]) {
            newArr.push(arr[i]);
          }
        }
        return newArr;
      }

console.log( clear( arr3) );
51.闭包
1.闭包是什么
闭包是一个函数加上到创建函数的作用域的连接(函数嵌套),闭包“关闭”了函数的自由变量(变量不会销毁)2.闭包可以解决什么问题【闭包的优点】
2.1内部函数可以访问到外部函数的局部变量
2.2闭包可以解决的问题
使用闭包,i不会被销毁,会注入内存中,能够拿到对应的下标i
var lis = document.getElementsByTagName ('li');
for(var i=0;i<lis.length;i++){
    (function(i){
    lis[i].onclick = function(){
    	alert(i);
    	}
    })(i)
}
3.闭包的缺点
3.1 变量会驻留在内存中,造成内存损耗问题。
	解决︰把闭包的函数设置为null
	lis[i].onclick = null
3.2内存泄漏【ie】==>可说可不说,如果说一定要提到ie

52.面试题:JS判断变量是不是数组,你能写出哪些方法?

方式一: isArray

var arr = [ 1,2,3];
console.log( Array.isArray(arr));

方式二: instanceof

var arr = [1,2,3];
console.log( arr instanceof Array );

方式三∶原型prototype

var arr = [1,2,3];
console.log( Object.prototype.toString.call(arr));//[object Array]

方式四:isPrototypeOf()

var arr = [1,2,3];
console.log(Array.prototype.isPrototypeof(arr) )

方式五: constructor

var arr = [1,2,3];
console.log(arr.constructor.toString())//function Array() { [native code] }
53.找到字符串出现最多次的字符
	  let str = "aaabbbbbbbbbxxxcc";
      let obj = {};

//得到各个字符出现的次数
      for (let i = 0; i < str.length; i++) {
        if (obj[str[i]]) {
          obj[str[i]]++;
        } else {
          obj[str[i]] = 1;
        }
      }

//将次数单独放到数组里面
      let value = [];
      for (var key in obj) {
        value.push(obj[key]);
      }

//得到次数最大值
      let maxValue = Math.max(...value);

//找到最大value值对应的key
      let maxKey = {};
      for (var key in obj) {
        if (obj[key] === maxValue) {
          console.log(key + "出现字数最多,共" + maxValue + "次");
        }
      }
54.面试题:new操作符具体做了什么
1.创建了一个空的对象
2.将空对象的原型,指向于构造函数的原型
 Foo().prototype === new Foo().__proto__
3.将空对象作为构造函数的上下文(改变this指向)
4.对构造函数有返回值的处理判断
return 1、基本类型,会忽略 2、引用类型(对象、数组),会进行返回
55.面试题:原型链
1.原型可以解决什么问题
对象共享属性和共享方法
2.谁有原型
函数拥有: prototype	对象拥有:__proto__
3.对象查找属性或者方法的顺序
先在对象本身查找-->构造函数中查找-->对象的原型-->构造函数的原型中-->当前原型的原型
4.原型链
    4.1 是什么?就是把原型串联起来
    4.2原型链的最顶端是null
56.js继承有哪些方式

方式一:ES6

class Parent{
    constructor(){
        this.age = 18;
    }
}
class Child extends Parent{
    constructor(){
        super();
        this.name ='张三';}
}

let o1 = new Child();
console.log( o1,o1.name,o1.age );

方式二:原型链继承

function Parent(){
	this.age = 20;
}
function Child(){
	this.name =‘张三'
}
Child.prototype = new Parent();

let o2 = new Child();
console.log( o2,o2.name,o2.age );

方式三∶借用构造函数继承

function Parent(){
	this.age = 22;
}
function Child(){
	this.name = ‘张三';
    Parent.call(this);
}

let o3 = new Child();
console.log( o3,o3.name,o3.age );

方式四:组合式继承

function Parent(){
    this.age = 100;
}
function Child(){
    Parent.call(this);
    this.name = ‘张三'
}
Child.prototype = new Parent();

let o4 = new Child();
console.log( o4,o4.name,o4.age );
57.面试题:说一下call、apply、bind区别

共同点:功能一致

可以改变this指向
语法:函数.cal1()、函数.apply()、函数.bind()

区别:

1.call、apply可以立即执行。bind不会立即执行,因为bind返回的是一个函数需要加入()执行。
bind只能在赋值和声明中的时候添加,并且后期执行时使用call和apply改变this都是无效的
call和apply是在执行的时候添加
2.参数不同:
apply第二个参数是数组。call和bind有多个参数需要挨个写。

场景:

1.用apply的情况
var arr1 = [1,2,4,5,7,3,321];
console.log( Math.max.apply( null, arr1) )
58.面试题:深拷贝和浅拷贝

共同点:复制
1.浅拷贝︰只复制引用,而未复制真正的值(没有新建),指向同一个地址,一个变会改变另一个对象的值。

var arr1 = [ 'a' , 'b ' , 'c ' , 'd ' ];
var arr2 = arr1;

var obj1 = {a:1,b:2}
var obj2 = Object.assign(obj1);

2.深拷贝∶是复制真正的值―(不同引用)

var obj3 = {
    a: 1,
    b: 2
}
var obj4 = JSON. parse (JSON.stringify(obj3));
59.面试题:localStorage、sessionStorage、cookie的区别

公共点:

在客户端存放数据
区别:
**

1.数据存放有效期
sessionStorage :仅在当前浏览器窗口关闭之前有效。【关闭浏览器就没了】
localstorage:始终有效,窗口或者浏览器关闭也一直保存,所以叫持久化存储。
cookie:只在设置的cookie过期时间之前有效,即使窗口或者浏览器关闭也有效。

2. localStorage、sessionStorage不可以设置过期时间
   cookie有过期时间,可以设置过期(把时间调整到之前的时间,就过期了)
3.存储大小的限制
   cookie存储量不能超过4k
   localstorage、sessionStorage不能超过5M
   
   ****根据不同的浏览器存储的大小是不同的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值