整理一下JavaScript中比较常见的一些面试题

164 阅读6分钟

这边记录一下前端中比较常见的面试题,会持续更新的!!!

JavaScript

1.介绍一下js的数据类型有哪些,值是如何存储的

  • JavaScript一共有8种数据类型,其中有7种基本数据类型:Undefined、Null、Boolean、Number、String、Symbol(es6新增,表示独一无二的值)和BigInt(es10新增), 1种引用数据类型-Object:里面包含 function、Array、Date等

2.V8引擎的原理

WechatIMG8.png 具体可参考官方文档 v8.dev/blog/turbof…

3. JS中数据类型的判断

4. js变量和函数声明的提升

  • 在js中变量和函数的声明会提升到最顶部执行\
  • 函数的提升高于变量的提升\
  • 函数内部如果用 var 声明了相同名称的外部变量,函数将不再向上寻找\
  • 匿名函数不会提升。

5.什么是闭包

一个普通的函数function,如果它可以访问外层作用于的自由变量,那么这个函数就是一个闭包;

从广义的角度来说:JavaScript中的函数都是闭包;

从狭义的角度来说:JavaScript中一个函数,如果访问了外层作用于的变量,那么它是一个闭包

6.this的理解

this的指向跟函数所处的位置是没有关系的,跟函数被调用的方式有关系的

绑定一:默认绑定: 独立的函数调用,我们可以理解成函数没有被绑定到某个对象上进行调用(优先级最低) 绑定二:隐式绑定:Object.fn(), Object会被js引擎隐式绑定到fn函数里面的this里面

绑定三:显示绑定:call和apply在调用函数的时候是可以明确绑定this的,这个我们称之为显示绑定

绑定四:new绑定:我们通过new关键字调用函数时候,这个时候this是指向构造函数创建出来的这个对象的

new绑定 > 显示绑定(apply/call/bind)> 隐式绑定(obj.fn()) > 默认绑定(独立函数的调用)

7.实现call、apply、bind

// call:
Function.prototype.FqCall = function(thisArg, ...argArray) {
  // 获取到当前函数
  var fn = this
  // 这里是处理传递过来需要绑定的this如果是undefined和null的时候需要绑定到window上,但是还有一种传了0的时候不应该绑定到window上
  thisArg = (thisArg !== undefined &&  !== null ) ? Object(thisArg) : window
  // 将这个函数添加到传入需要绑定的参数中
  thisArg.fn = fn
  // 利用隐式绑定调用这个函数,将this绑定到传入的参数中
  const result = thisArg.fn(...argArray)
  delete thisArg.fn
  // 将最终的结果进行返回
  return result
}

function foo(num1, num2, num3) {
  console.log('foo被调用了', this, num1, num2)
  return num1 + num2
}

const result = foo.FqCall({name: 'fang'}, 10, 20)
console.log(result) // 30

// apply:
Function.prototype.FqApply = function(thisArg, argArray) {
  // 1. 获取到需要执行的函数
  const fn = this
  // 处理需要绑定的this
  thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
  thisArg.fn = fn
  //这里是为了处理如果没有传递参数的情况,因为不传的情况argArray的值就是undefined,不能将undefined进行展开运算符
  const arr = argArray || []
  const result = thisArg.fn(...arr)
  delete thisArg.fn
  return result
}

function sum(num1, num2) {
  console.log('sum函数被调用了', this, num1, num2)
  return num1 + num2
}


const result = sum.FqApply({name: 'fang'}, [10, 20])
console.log(result)

function bar() {
  console.log('bar被执行了')
}
bar.FqApply({name: 'fang'})
// bind:
Function.prototype.FqBind = function(thisArg, ...argArray) {
  const fn = this
  thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
  return function proxyFn(...arrList) {
    thisArg.fn = fn
    // 参数合并,因为我们在调用系统的bind的时候参数其实是可以分开传递的
    const arr = [...argArray, ...arrList]
    const result = thisArg.fn(...arr)
    delete thisArg.fn
    return result
  }
}

function sum(num1, num2, num3, num4){
  console.log('sum函数被调用了:' , this, num1, num2, num3, num4)
  return num1 + num2 + num3 + num4
}

const result = sum.FqBind({name: 'sum'}, 10, 20)
console.log(result(30, 40))

8.理解JavaScript纯函数

确定的输入,一定会产生确定的输出;函数在执行过程中,不能产生副作用

const names = ['jack', 'tony', 'koby', 'james']
names.slice(1, 3) // ['tony', 'koby'] 它产生了确定的输出且不会改变原来的数组,这个方法就是个纯函数

names.splice(2) // ['tony', 'koby'] 虽然有了确定的输出 但是修改了原来的数组 这个就不是纯函数

9. == 和 ===的区别

  • ==是非严格意义上的相等 (值相等就相等)\
  • ===是严格意义上的相等,会比较两边的数据类型和值大小 (值和引用地址都相等才相等)

10. js数组和对象的遍历方式

  • for in
  • for
  • forEach
  • for-of

11. map与forEach的区别

  • forEach 方法,是最基本的方法,就是遍历与循环,默认有 3 个传参:分别是遍历的数组内
    容 item、数组索引 index、和当前遍历数组 Array
  • map 方法,基本用法与 forEach 一致,但是不同的,它会返回一个新的数组,所以 callback
    需要有 return 值,如果没有,会返回 undefined

12. 同源策略

  • 同源指的是域名、协议、端口号相同

13. 如何解决跨域

  • jsonp跨域
  • document.domain + iframe 跨域
  • nodejs中间件代理跨域
  • 后端在头部信息里面设置安全域名

14. 严格模式的限制

  • 变量必须声明后再使用
  • 函数的参数不能有同名属性,否则报错
  • 不能使用 with 语句
  • 禁止 this 指向全局对象

15. es6新增

可查看我写的另一篇文章,ES6至ES12新特性

16. let和const 的区别是什么?

  • let 命令不存在变量提升,如果在 let 前使用,会导致报错
  • 如果块区中存在 let 和 const 命令,就会形成封闭作用域
  • 不允许重复声明
  • const定义的是常量,不能修改,但是如果定义的是对象,可以修改对象内部的数据

17. 内存泄漏

  • 定义:程序中己动态分配的堆内存由于某种原因程序未释放或无法释放引发的各种问题。
  • js中可能出现的内存泄漏情况:结果:变慢,崩溃,延迟大等
  • js中可能出现的内存泄漏原因
  • 全局变量
    • dom 清空时,还存在引用
    • 定时器未清除
    • 子元素存在引起的内存泄露

18. script 引入方式?

  • html 静态 <script> 引入
  • js 动态插入 <script>
  • <script defer> : 异步加载,元素解析完成后执行
  • <script async> : 异步加载,但执行时会阻塞元素渲染

19. 数组(array)方法

数组的一些常用的操作可查看这篇文章

20. keep-live

keep-alive 组件在渲染的时候,会根据传入的 includeexclude 来匹配 keep-alive 包裹的命名组件,未匹配上就直接返回这个命名组件进行渲染,若匹配上就进行缓存操作:若缓存中已有这个组件,就替换其实例,并更新这个组件的 keykeys 中的位置;若缓存中没有这个组件,就把这个组件放入 keep-alive 组件的缓存 cache 中,并把这个组件的 key 放入 keys 中,由于在 mounted 的时候有对 includeexclude 进行监听,因此,后续这两个属性值发生变化时,会再次判断是否满足条件而进行组件销毁。