前端开发面试总结——JS部分

1. js有哪些数据类型?

  • js共8大数据类型:undefined、null、boolean、number、string、object、symbol、bigint,后面两个属于ES6新增
  • symbol代表创建后独一无二且不可变的数据类型,为了解决可能出现的全局变量冲突问题
  • bigint表示任意精度格式的整数,可以安全存储和操作大整数。
  • 又可分为原始数据类型和引用数据类型
  • 栈:原始数据类型(undefined、null、boolean、number、string)
  • 堆:引用数据类型(对象、数组、函数)

2. 数据类型检测的方式有哪些?

  • typeof:typeof []或{}或null返回object
  • instanceof:判断对象的类型,运行机制是判断在其原型链中能否找到该类型的原型
  • constructor: 构造函数
  • Object.prototype.toString.call()

3. null和undefined区别?

  • undefined不是关键字,而null是关键字
  • undefined和null被转化为布尔值时都为fales
  • undefined和null进行比较时==两者相等,===两者不相等
  • Number()进行类型转换时:undefined为NaN,null为0
  • undefined本质上是window的一个属性,而null是一个对象
  • null表示没有对象,即不应该有值,undefined表示缺少值,即应该有值,但是未赋值(变量提升时默认会赋值为undefined,函数参数未提供默认为undefined,函数的返回值默认为undefined)

4. instanceof操作符的实现原理及实现?

  • A instanceof B
  • instanceof是一个运算符,可以用来判断一个对象的类型,左侧是实例对象,右侧是构造函数
  • 具体原理就是利用了原型和原型链,判断时先拿到instanceof左侧对象的原型链,再拿到右侧构造函数的显式原型prototype,如果原型链中存在显式原型prototype,instanceof返回true,否则返回false

5. 为什么0.1+0.2 !== 0.3,如何解决?

在 0.1 + 0.2 进行计算的时候,实际上计算的是这两个数字在计算机里所存储的二进制。0.1 和 0.2 在进行二进制转换的时候会出现无限循环的情况。解决方案:

  • 可以将其转换为整数后在进行运算,运算后再转为对应的小数
  • 可以利用ES6中的极小数Number.EPSILON来进行判断

6. isNaN和Number. isNaN函数的区别?

  • isNaN函数会首先进行Number函数转换,如果转换后为number类型,则返回false,否则返回true
  • Number. isNaN函数是严格等于NaN,不需要任何转换,只有NaN才能为true,剩下的全部都是false

7. ==操作符的强制类型转换规则?

  • string和number相等比较,将string转换成number之后再比较
  • 其他类型和boolean相等比较,先将boolean值转换成number后,在比较
  • null和undefined相等比较,返回true,其他值和它两比较都返回false
  • NaN和NaN相等比较,返回fasle
  • 两个对象相等比较,先比较两边所指向对象的地址是否相同,相同则为true

8. Object.is()与比较操作符'===' '=='的区别?

  • 双等进行相等判断时,如果两边类型不一致,会强制类型转化后再比较
  • 三等进行相等判断时,如果两边类型不一致,不会做强制转换类型,直接返回false
  • Object.is()进行相等判断时,,一般情况下和三等的判断相同,但它会处理一些特殊情况,比如-0和+0不相等,两个NaN是相等的

9. new操作符的实现原理?

new操作符作用于创建一个给定构造函数的实例对象。

实现原理:新生成一个对象,链接到原型,绑定this,返回新对象(如果构造函数有自 己的return时,返回该值)

10. map和Object的区别?

  • 都是键值对的动态集合,支持增加和删除键值对
  • Object的键类型必须是string或者symbol,如果非string类型则会进行数据类型转换;Map的键类型是任意类型,包括对象数组函数等,不会进行数据类型转换
  • Object的key是无序的,不会按照添加顺序返回;Map的key是有序的,按照插入顺序返回
  • Object只能手动计算(Object.keys()或for in)size;Map直接通过size属性访问
  • Object可以通过JSON.stringify()进行序列化操作,但Map不可以

11. 为什么要进行变量提升?

  • 解析和预编译过程中的声明提升可以提高性能,让函数可以在执行时预先为变量分配栈空间
  • 提高JS代码的容错性,使一些不规范的代码也可以正常运行

12. ES6模块与commonJS模块有什么异同?

  • commonJS输出的是一个值的拷贝,ES6输出的是值的引用
  • commonJS是运行时加载,ES6是编译时输出接口
  • commonJS的require是同步加载模块,ES6的import是异步加载,有独立模块依赖的解析阶段。

13. 类?

  • 定义:指用来创建对象的模板,而通过这个模板创建出的对象叫做实例。
  • 类关键字:extends(继承)static(静态方法)super(调用父类构造方法)
  • 父类的私有成员不会被子类继承public private
  • 类是在原型继承基础上构建的,每一个类都是一个函数

14. 如何判断一个对象是否属于某个类?

  • 对于Object对象,直接调用toString()就能返回[object object]
  • 对于其他对象,则需要用call、apply来调用才能返回正确的类型信息
  • Object.prototype.toString.call(1)                 // [object Number]
    Object.prototype.toString.call(true)              // [object Boolean]
    Object.prototype.toString.call(null)              // [object Null]
    Object.prototype.toString.call(undefined)            // [object Undefined]
    Object.prototype.toString.call(new Funtion())      // [object Function]
    Object.prototype.toString.call(new Date())          // [object Date]

    15. 事件循环?

  • JS是单线程,防止代码阻塞,同步代码给js引擎执行,异步代码交给宿主环境(浏览器/node)
  • 执行栈中先执行同步任务,执行完后查看微任务队列,有则执行微任务,执行完后执行宏任务队列
  • 同步任务:console.log(),promise本身同步,async,script标签
  • 微任务:promise.then/catch(),await后面的任务,process.nextTick(先)
  • 宏任务:定时器(先settimeout后setimmede)
  • 案例链接:CSDN

16. for in 和for of的区别?

  • for in是对key值遍历,对象是遍历对象的key值,数组是遍历数组的下标
  • for of是对数组遍历,对数组每个元素值的遍历

17. forEach和map有什么区别?

  • 两者都通常用于遍历数组
  • forEach返回undefined,用来遍历数组中的每一项,不改变原数组
  • map返回一个新数组,不改变原数组

18. 如果new一个箭头函数会怎样?

箭头函数是ES6中提出来的,他没有prototype,也没有自己的this指向,更不能使用arguments参数,所以不能new一个箭头函数。

19. let、const、var的区别?

 20. 箭头函数与普通函数的区别?

  • 箭头函数没有自己的this,其this始终指向创建时所在作用域指向的对象
  • 箭头函数不能new构造实例,没有prototype
  • 箭头函数不绑定arguments,可以使用ES6中的rest参数代替
  • 箭头函数不能使用call,bind,apply方法改变this指向

21. 常见的正则表达式有哪些?


var regex = /#([0-9a-fA-F]{6} | [0-9a-fA-F]{3})/g    //匹配16进制颜色值
var regex = / ^[0-9]{4} -(0[1-9] | 1[0-2])-(0[0-9] | [12][0-9] | 3[01])$/    //匹配日期
var regex = /^[1-9][0-9]{4,10}$/g    //匹配qq号
var regex = /^1[34578]\d{9}$/g    //匹配手机号
var regex = /^[a-zA-Z\$][a-zA-Z0-9_\$]{4,16}$/    //匹配用户名

22. proxy可以实现什么功能?

  • proxy是ES6新增的功能,可以自定义对象中的操作
  • 在vue3中通过proxy来替换原本的object.defineProperty来实现数据响应式。
  • let p = new Proxy(target, handler)
  • target代表需要添加代理的对象,handler用来自定义对象中的操作,如get、set

23. 对原型、原型链的理解?

  • 原型:函数都有prototype属性,称之为原型,也叫原型对象。原型可以放一些属性和方法,共享给实例对象使用,也可做继承。
  • 原型链:对象都有_proto_属性,这个属性指向它的原型对象,原型对象也是对象,也有_proto_属性,指向原型对象的原型对象,这样一层一层形成的连式结构称为原型链,最顶层找不到则返回null

 24. 对promise的理解,解决什么问题?

Promise是一种异步编程的解决方案,有三种状态:pending、resovled、rejected

特点:异步操作的结果决定当前是哪种状态,状态一旦改变,就无法再次改变状态。

作用:主要用来解决回调嵌套(回调地狱),执行多并发请求获取资源

25. 对async/await的理解,优势?

  • async的作用就是用于声明一个function是异步的,而await用于等待一个异步方法执行完成。
  • async/await是基于Promise实现的,他不能用于普通的函数。
  • async/await与Promise一样,是非阻塞的
  • async/await使得异步代码看起来像同步代码,代码简洁,避免嵌套
  • 在没有await的情况下执行async函数,它会立即执行,返回一个promise对象,不会阻塞后面的语句的执行
  • await的作用是等待一个async函数执行完成的返回值
  • async/await用try/catch可以同时处理同步和异步错误

26. 事件冒泡与事件捕获?

  • 事件冒泡:从触发事件的那个节点一直到document,是自下而上的去触发事件
  • 事件捕获:从document到触发事件的那个节点,是自上而下的去触发事件
  • 绑定事件方法(addEventListener)的第三个参数是控制事件触发顺序的,默认为false,即为事件冒泡,若为true则为事件捕获
  • 阻止事件冒泡方法:event.stopPropagation ()
  • 阻止事件默认行为:event.preventDefault()

27. 对闭包的理解?

  • 有权访问另一个函数作用域中变量的函数,意义是可间接访问到当前函数的局部变量
  • 产生闭包的条件:函数嵌套;内部函数引用外部函数的数据
  • 当js引擎需要查询一个变量的值时,先本地查找,查找不到则继续再上层范围查找
  • 闭包中的变量存储的位置是堆内存
  • 防抖和节流,react中都用到了闭包
  • 作用:使用函数内部变量在函数执行完后仍存活在内存中(延长局部变量的生命周期);让函数外部可以操作(读写)到函数内部的数据(函数/变量)

28. 对作用域、作用域链的理解?

  • 作用域:代码执行开辟栈内存。
  • 作用域就是代码的执行环境,全局执行环境就是全局作用域,函数的执行环境就是私有作用域,它们都是栈内存。
  • web浏览器中,全局执行环境为window对象,因此所有的全局变量和函数都是作为window对象的属性和方法创建的。
  • 在node环境中,全局执行环境时global对象。
  • 某个执行环境中所有的代码都执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之被销毁。(全局执行环境直到应用程序退出时,如关闭浏览器或网页,才会被销毁)
  • 作用域类型: 全局作用域、函数作用域和块级作用域
  • 作用域链:
    • 当代码在一个环境中执行时,会创建变量对象的一个作用域链
    • 作用域链的前端,始终都是当前执行的代码所在环境的变量对象
    • 作用域链中的下一个对象来自于外部环境,而在下一个变量对象则来自下一个外部环境,一直到全局执行环境
    • 全局执行环境的变量对象始终都是作用域链上的最后一个对象
    • 内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境的任何变量和函数。

29. 对执行上下文的理解?

执行上下文可以理解为当前代码的执行环境,同一个函数在不同的环境中执行,会因为访问数据的不同产生不一样的结果。

  • 全局执行上下文:程序首次运行时创建,在浏览器中创建一个全局对象window
  • 函数执行上下文:函数被调用时创建,每次调用都为该函数创建一个新的执行上下文
  • Eval函数执行上下文:运行eval函数时创建,少用

30. 对this的理解?

  • 全局环境下 <script></script>,this指向window对象
  • 局部环境下:

        在全局作用域下直接调用函数,this指向window

        对象函数调用,哪个对象调用就只指向哪个对象

        new实例化对象,构造函数中的this指向实例对象

  • 箭头函数中的this:箭头函数没有自己的this,默认指向在定义它时所处的父级作用域
  • 改变this指向方法:call,apply,bind

31. call、apply和bind的区别?

  • 三者都是动态的修改当前函数内部环境对象this的指向
  • 执行方式不同:call apply是改变后页面加载之后就立即执行,是同步代码,bind是异步代码,改变后不会立即执行,而是返回一个新的函数。
  • 传参方式不同:call bind传参是逐个传入,不能用剩余参数方式传参,apply可以用数组传参,能用剩余参数方式传参
  • 修改this性质不同:call apply只是临时修改一次,当调用原函数的时候它的指向还是原来的指向,bind是永久性修改函数this指向,修改的不是原函数,而是返回一个修改过后新的函数,此函数的this永久改变

32. 深/浅拷贝?

浅拷贝:只拷贝一层,引用类型的深层次还是共享内存地址

  • Object.assign(): 改变原对象
  • 扩展运算符:不改变原数组,但改变原对象
  • Array.concat():不改变原数组
  • Array.slice():不改变原数组

深拷贝:开辟一个新的地址存储,完成独立的双胞胎

  • _.cloneDeep(): 先const _ = require(‘lodash’)
  • JSON.parse(JSON.stringify() ) : 将对象转成字符串
  • 递归方法

JSON.stringify()弊端

  • json语法支持数字、字符串、布尔值、null四种
  • json语法不支持underfined、函数和symbol
  • NaN和Infinity格式的数值及null都会被当做null
  • RegExp、Error对象返回空
  • Date日期值会被当做字符串处理
  • map、set仅会序列化可枚举的属性

33. 数组常用方法?

join()    //将数组变成字符串
push() pop() unshift() shift()      //数组增删
reverse()    //翻转数组
sort()    //数组排序
concat()    //数组拼接
slice(start,end)    //数组截取
splice()    //数组增删
splice(start,num)    //从下标start开始,删除num个(删)
splice(start,num,item)    //从下标start开始,删除num个,并添加item
splice(start,0,item)   //从下标start开始,删除0个,并添加item(增)
indexOf()     //数组查找
forEach()     //遍历数组,等同于for循环,无返回值
arr.forEach(function(item,index,arr){  })
map()     //映射,遍历数组,有返回值
arr.map(function(item,index,arr){return xx})
filter()    //过滤,有返回值
arr.filter (function(item,index){ return xx })
some()     //判断数组中有没有符合条件的项,有就返回true
arr.some (function(item){ return xx })
every()     //判断数组中所有项是否都满足,全部满足就返回true 
arr.every (function(item){ return xx })
find()     //找到符合条件的项,并返回第一项
findIndex()     //找到符合条件的项的下标,并返回第一个
reduce()     //求和计算,扁平化数组,对象数组叠加计算

34. 字符串常用方法?

string.length    //字符串长度
slice(start,end)    //截取字符串
substr(start,end)    //截取字符串
substring(start,end)    //截取字符串(不可为负数)
split()    //将字符串分割成数组
indexOf()    //字符串查找,返回字符首次出现位置
lastIndexOf()    //字符串末尾查找,返回字符首次出现位置
replace(a, b)    //字符串替换
charAt()    //根据下标查字符
toLowerCase()    //将字符串转成小写
toUpperCase()    //将字符串转成大写
for (let str of string) { }     //字符串遍历
includes()    //字符串中查找是否含有某字符,返回布尔值
repeat()    //将字符串重复n次

以上是小编自己搜罗各种资源总结,仅供参考学习!持续跟新中。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值