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次
以上是小编自己搜罗各种资源总结,仅供参考学习!持续跟新中。。。