JavaScript最新面试题持续更新中

214 阅读14分钟

继承

主要分为

事件流

JS的DOM事件流

DOM里面触发事件的流程,目标,冒泡,捕获三个阶段

事件代理

就是把一个元素响应事件(clickkeydown......)的函数委托到另一个元素

事件委托

描述:把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,而不是目标元素

执行机制:当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数

优点:

  • 减少整个页面所需的内存,提升整体性能
  • 动态绑定,减少重复工作

缺点:如果把所有事件都用事件代理,可能会出现事件误判,即本不该被触发的事件被绑定上了事件

局限性:

  • focusblur这些事件没有事件冒泡机制,所以无法进行委托绑定事件
  • mousemovemouseout这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗高,因此也是不适合于事件委托的

函数

可以使用哪两种声明方式声明函数

区分

let test=function(){}           //函数表达式  
(function(){})()                //函数表达式 
setTimeout(function(){},1000)   //函数表达式 
function text(){}               //函数声明

不同处

| 特征 | 函数声明 | 函数表达式 | | -- | ---- | ----- | | | 预提升 | 会进行预提升 | 不会进行预提升 | | 访问范围 | 函数内部和函数父级作用域 | 函数内部 | | 函数名 | 不能没有 | 可以没有 |

Arguments是什么

是函数实参的集合,是一个伪数组。箭头函数没有arguments,箭头函数是用rest操作符(...)获取箭头函数所有实参的集合。

注:伪数组有类似数组特性,如具有length属性,按索引方式存储数据;但是不能使用数组方法,可使用Array.from(),Array.prototype.slice.call(),展开运算符等方法将伪数组转为数组

new执行流程

  • 创建一个空对象
  • 将对象与构建函数通过原型链连接起来
  • 将构建函数中的this指向新建的空对象
  • 执行构造函数内部代码
  • 根据构建函数返回类型作判断,如果是简单数据类型(string,number,boolean,undefined,null)则返回实例,如果是复杂数据类型的对象则返回对象

数组

数组方法

按类型区分

数组循环类方法:forEach map filter every some fill findIndex find reduce

数组拼接类方法:slice splice split push pop unshift shift concat join reserve sort

按是否改变原数组区分

原数组改变的方法有:splice split push pop unshift shift reverse sort

不改变原数组的方法有:forEach map filter every some fill findIndex find reduce slice concat join indexOf forEach 数组循环类及部分拼接类方法及去重

字符串方法:

  • concat():用于将一个或多个字符串拼接成一个新字符串

删:返回调用它们的字符串的一个子字符串,而且都接收一或两个参数

  • slice()
  • substr()
  • substring() 改:创建字符串的一个副本,再进行操作
  • trim()、trimLeft()、trimRight():删除前、后或前后所有空格符,再返回新的字符串
  • repeat():接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果
  • padStart()、padEnd():复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件
  • toLowerCase()、 toUpperCase():大小写转化 查:
  • chatAt():返回给定索引位置的字符,由传给方法的整数参数指定
  • indexOf():从字符串开头去搜索传入的字符串,并返回位置(如果没找到,则返回 -1 )
  • startWith():从字符串中搜索传入的字符串,并返回一个表示是否包含的布尔值
  • includes() 拆分字符串:
  • split():把字符串按照指定的分割符,拆分成数组中的每一项 针对正则表达式的方法:
  • match():接收一个参数,可以是一个正则表达式字符串,也可以是一个RegExp对象,返回数组
  • search():接收一个参数,可以是一个正则表达式字符串,也可以是一个RegExp对象,找到则返回匹配索引,否则返回 -1
  • replace():接收两个参数,第一个参数为匹配的内容,第二个参数为替换的元素(可用函数)

对象

js内置对象

Math、 Date 、Array、String等

this

this是什么

this是当前执行上下文(global、function 或 eval)的一个属性

this的指向

  • 在方法中,this 指的是所有者对象。

  • 单独的情况下,this 指的是全局对象。

  • 在函数中,this 指的是全局对象。

  • 在函数中,严格模式下,thisundefined。

  • 在事件中,this 指的是接收事件的元素。

  • 使用 call,apply,bind改变this指向 。

JS中改变this指向的上下文调用的三种方法

call,apply,bind

参数

     函数名.call(修改this,形参1,形参2...)
     
     函数名.apply(修改this, 数组/伪数组 )
     
     函数名.bind(修改this)

区别

     传参方式不同 : call是逐一传参, apply是数组/伪数组 传参方式不同
     
     执行机制不同 : call和apply立即执行函数, bind不会立即执行函数
     
       call和apply用一次,改一次
        
       bind修改一次,永久有效

简单使用及场景

数据类型

如何检测数据类型

1.typeof 数据: 检测数据类型

注:有两种数据类型无法检测 : null array

  1. 万能数据类型检测 : Object.prototype.toString.call( 数据 )

  2. object instanceof constructorinstanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

    注:可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型。返回布尔值

JS中的数据类型

基本类型

  • Number
  • String
  • Boolean
  • Undefined
  • null
  • symbol
  • BigInt

null和undefined区别

undefined在和null进行==比较时两者相等,全等于比较时两者不等

null表示没有对象,null 值表示指针指向一个空对象,经常用作函数的参数,或作为原型链的顶级对象。

undefined表示缺少值,没有指针

null+1和undefined+1的值

null+1=1

undefined+1=NaN+1=NaN

谈一谈symbol

Symbol (符号)是原始值,且符号实例是唯一、不可变的。符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险

使用方式let genericSymbol = Symbol()

谈一谈BigInt

用途:精确查询数字类型及多种数字类型转换

使用方法

  • 在整数的末尾追加n
  • BigInt()

复杂类型

  • Object
  • Array
  • Function

JS类型转换机制

  • 强制转换(显示转换)
    • Number(),parseInt(),parseFloat()
    • String(),toString()
    • Boolean()
  • 自动转换(隐式转换)
    • 比较运算(==!=><)、ifwhile需要布尔值地方
    • 算术运算(+-*/%

==和===

  • ==:JavaScript中存在隐式转换。等于操作符(==)在比较中会先进行类型转换,再确定操作数是否相等
  • ===:操作符(===)只有两个操作数在不转换的前提下相等才返回 true。即类型相同,值也需相同
null==undefinedtrue

null===undefinedfalse

Promise

状态

promise对象仅有三种状态

  • pending(等待态)
  • fulfilled(成功态)
  • rejected(失败态)

简单描述

是ES6新增的一个特性,用的时候一般要new一下,做为一个构造函数来使用,里面有一些参数,成功时resolve 会触发.Then,失败时reject会触发.catch,主要解决的是回调地狱的问题,不过一般使用的时候呢不会直接是用promise,她虽然能解决回调地狱 但是不能简化代码,使用promise会使代码变得复杂,所以就需要结合async await来配合promise使用,这样既能解决回调地狱,又能简化代码。

流程

image.png

方法

  • all()
  • race()
  • allSettled()
  • resolve()
  • reject()
  • try()

Promise.all()

Promise.all()方法用数组将多个 Promise实例包装成一个新的 Promise实例,数组中若有一个实例为失败态,Promise.all()则直接返回该失败态

深拷贝和浅拷贝

浅拷贝和深拷贝如何实现

浅拷贝

  • Object.assign
  • Array.prototype.slice()Array.prototype.concat()
  • 使用...拓展运算符

深拷贝

  • _.cloneDeep():lodash库的方法,_为所有方法
  • jQuery.extend():通过$使用Jquery的方法
  • JSON.stringify():JSON.parse(JSON.stringify(obj))
  • 手写循环递归

深拷贝和浅拷贝的区别

  • 浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址
  • 深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址

闭包

什么是闭包

闭包是指有权访问另一个函数作用域中变量的函数

闭包作用

  • 创建私有变量
  • 延长变量的生命周期

闭包使用场景

  • 使用回调函数
  • 使用函数作为参数
  • 自执行函数
  • 防抖节流
  • 循环赋值
  • return回一个函数

闭包的缺陷

闭包会减缓处理速度和提高内存消耗,容易导致内存泄漏

JS事件循环

JS单线程

在 JavaScript 中我们听到最多的词可能就是所谓的“单线程”,所以导致了在 JS 中所谓的异步并行模型和许多后台语言是不同的。简而言之,虽然 JavaScript 是在单线程中去执行所有的操作,但它会基于事件循环(EventLoop)的过程去实现所谓的“异步”,从而给我们造成多线程的感觉。

Event Loop

JavaScript中,任务被分为两种,一种宏任务(MacroTask)也叫Task,一种叫微任务(MicroTask

宏任务

script全部代码、setTimeoutsetIntervalsetImmediate

微任务

Process.nextTick(Node独有)Promise

浏览器中的Event Loop

Javascript 有一个 main thread 主线程和 call-stack 调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。

JS调用栈

JS调用栈采用的是后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。

同步任务和异步任务

Javascript单线程任务被分为同步任务异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。

作用域链

什么是作用域链

作用域,即变量(变量作用域又称上下文)和函数生效(能被访问)的区域或集合

换句话说,作用域决定了代码区块中变量和其他资源的可见性

作用域链都包括什么

我们一般将作用域分成:

  • 全局作用域:任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问
  • 函数作用域:函数作用域也叫局部作用域,如果一个变量是在函数内部声明的它就在一个函数作用域下面。这些变量只能在函数内部访问,不能在函数以外去访问
  • 块级作用域:ES6引入了letconst关键字,和var关键字不同,在大括号中使用letconst声明的变量存在于块级作用域中。在大括号之外不能访问这些变量

JS原型,原型链

什么是原型

doSomething.prototype 就是原型,它是一个对象,我们也称它为原型对象。,每个对象拥有一个原型对象

image.png

什么是原型链

原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种逐级查找的过程被称为原型链

image.png

ajax

是什么

AJAX全称(Async Javascript and XML)

即异步的JavaScript 和XML,是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页

Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面

实现过程

  • 创建 Ajax的核心对象 XMLHttpRequest对象
  • 通过 XMLHttpRequest 对象的 open() 方法与服务端建立连接
  • 构建请求所需的数据内容,并通过XMLHttpRequest 对象的 send() 方法发送给服务器端
  • 通过 XMLHttpRequest 对象提供的 onreadystatechange 事件监听服务器端你的通信状态
  • 接受并处理服务端向客户端响应的数据结果
  • 将处理结果更新到 HTML页面中

JS本地存储方式

方式

javaScript本地缓存的方法我们主要讲述以下三种:

  • cookie
  • sessionStorage
  • localStorage
  • indexedDB(了解)

indexedDB(了解)

indexedDB是一种低级API,用于客户端存储大量结构化数据(包括, 文件/ blobs)。该API使用索引来实现对该数据的高性能搜索

虽然 Web Storage对于存储较少量的数据很有用,但对于存储更大量的结构化数据来说,这种方法不太有用。IndexedDB提供了一个解决方案

优点:

  • 储存量理论上没有上限
  • 所有操作都是异步的,相比 LocalStorage 同步操作性能更高,尤其是数据量较大时
  • 原生支持储存JS的对象
  • 是个正经的数据库,意味着数据库能干的事它都能干

缺点:

  • 操作非常繁琐
  • 本身有一定门槛

关于indexedDB的使用基本使用步骤如下:

  • 打开数据库并且开始一个事务
  • 创建一个 object store
  • 构建一个请求来执行一些数据库操作,像增加或提取数据等。
  • 通过监听正确类型的 DOM 事件以等待操作完成。
  • 在操作结果上进行一些操作(可以在 request对象中找到)

关于使用indexedDB的使用会比较繁琐,大家可以通过使用Godb.js库进行缓存,最大化的降低操作难度

区别

关于cookiesessionStorage(会话缓存)、localStorage三者的区别主要如下:

  • 存储大小:cookie数据大小不能超过4ksessionStoragelocalStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大
  • 有效时间:localStorage存储持久数据,浏览器关闭后数据不丢失除非主动删除数据; sessionStorage数据在当前浏览器窗口关闭后自动删除;cookie设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
  • 数据与服务器之间的交互方式,cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端; sessionStoragelocalStorage不会自动把数据发给服务器,仅在本地保存

应用场景

在了解了上述的前端的缓存方式后,我们可以看看针对不对场景的使用选择:

  • 标记用户与跟踪用户行为的情况,推荐使用cookie
  • 适合长期保存在本地的数据(令牌),推荐使用localStorage
  • 敏感账号一次性登录,推荐使用sessionStorage
  • 存储大量数据的情况、在线文档(富文本编辑器)保存编辑历史的情况,推荐使用indexedDB

强缓存和协商缓存

检测缓存是否过期若没过期则直接使用缓存(强缓存),若过期则需要发送http请求(协商缓存)

防抖和节流

目的:

优化高频率执行代码,减少指定事件调用频率

防抖:

描述:触发事件后指定时间后才执行函数,如果在指定时间内又触发了事件,则会重新计算函数执行时间(执行最后一次函数)

使用场景:

  • 搜索框输入功能。只需用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测
  • 窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。

节流:

描述:触发事件后指定时间后才执行函数,若连续触发事件但是在指定时间内只执行一次函数。(执行第一个函数)

使用场景:

  • 滚动加载,加载更多或滚到底部监听
  • 搜索框搜索功能

防抖和节流

仅用于自学,若有发现错误之处,请提出谢谢