1、js数据类型有哪些?怎么判断?toString方法判断类型怎么提取实际类型
JavaScript 数据类型包括七种基本数据类型和一种复杂数据类型。基本数据类型包括 Undefined、Null、Boolean、Number、String、Symbol(ES6 新增)和 BigInt(ES10 新增)。复杂数据类型指的是对象(Object),包括普通对象、数组、函数等等。
可以使用 typeof 运算符来判断一个值的类型,它会返回一个字符串,表示该值的类型。例如:
typeof 42 // "number"
typeof 'hello' // "string"
typeof true // "boolean"
typeof undefined // "undefined"
typeof null // "object"
typeof [] // "object"
typeof {} // "object"
typeof function() {} // "function"
使用 toString 方法也可以判断一个值的类型,只不过需要注意 toString 方法是 Object 的原型方法,需要通过 call 或 apply 调用才能让其他类型的值使用该方法。例如:
Object.prototype.toString.call(42) // "[object Number]"
Object.prototype.toString.call('hello') // "[object String]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call([]) // "[object Array]"
Object.prototype.toString.call({}) // "[object Object]"
Object.prototype.toString.call(function() {}) // "[object Function]"
要提取出实际类型,可以使用正则表达式匹配字符串中的具体类型名称,例如:
function getType(value) {
return Object.prototype.toString.call(value).match(/\[object\s(.*)\]/)[1]
}
getType(42) // "Number"
getType('hello') // "String"
getType(true) // "Boolean"
getType(undefined) // "Undefined"
getType(null) // "Null"
getType([]) // "Array"
getType({}) // "Object"
getType(function() {}) // "Function"
2、说下垃圾回收机制,结合垃圾回收机制和函数堆栈说下闭包变量为啥不会被回收?
JavaScript 中的垃圾回收机制指的是自动管理内存的过程。JavaScript 中的垃圾收集器会定期扫描内存,找出不再使用的变量并将其释放,以便让系统可以重用这些内存。
函数堆栈指的是函数调用时的执行上下文栈,每当一个函数被调用时,会将其执行上下文压入栈中,当函数执行完毕后,会将其执行上下文从栈中弹出。
闭包是指能够访问自由变量(在函数中定义,但是不是函数参数也不是局部变量的变量)的函数。由于闭包引用了自由变量,因此垃圾回收机制无法释放这些变量的内存,除非闭包被销毁。
3、箭头函数和普通函数的区别?它们的this有什么区别?
箭头函数和普通函数的区别在于箭头函数没有自己的 this、arguments、super、new.target 绑定,这些值会沿着作用域链向上查找。箭头函数还有一些其他特性,比如不能通过 new 关键字调用,不能使用 yield 关键字等。
普通函数的 this 值是在函数被调用时动态绑定的,它可以根据函数的调用方式来确定。在函数内部,可以通过 this 关键字来引用该函数被调用时的上下文对象。如果在函数中使用了 call、apply 或 bind 方法,则可以手动修改 this 的值。
箭头函数的 this 值与定义时的上下文对象有关,而不是调用时的上下文对象。如果箭头函数被定义在一个对象的方法中,那么它的 this 值会绑定到该对象上。如果箭头函数被定义在全局作用域中,那么它的 this 值会绑定到全局对象(例如 window)上。
4、说下事件循环机制,分别讲下Promise和async/await是怎么解决回调地狱的?
JavaScript 是单线程执行的,因此在进行异步操作时,需要使用事件循环机制来处理回调函数。事件循环机制包括宏任务和微任务两种类型的任务队列,它们的执行顺序是不同的。每次执行完一个宏任务后,会立即处理所有微任务,然后再执行下一个宏任务。Promise 和 async/await 都是用来解决回调地狱的问题的。
在 Promise 中,可以通过 then 方法来处理异步操作的结果,then 方法的回调函数会被放入微任务队列中。在处理完当前宏任务后,JavaScript 引擎会立即执行微任务队列中的所有回调函数,以便尽快地处理异步操作的结果。
在 async/await 中,可以使用 async 关键字定义一个异步函数,该函数会返回一个 Promise 对象。在异步函数中可以使用 await 关键字来等待异步操作的结果,await 表达式会暂停异步函数的执行,并等待 Promise 对象的状态变为 resolved 后再继续执行。与 Promise 一样,异步函数中的代码也是通过微任务来处理的。
5、vue2和vue3有哪些区别?响应式有什么区别?讲下proxy对象
Vue2 和 Vue3 的最大区别是 Vue3 中使用了 Composition API,可以更灵活地组织组件代码。Vue3 中的响应式系统也进行了优化,使用了 Proxy 对象来实现数据监听。Vue3 还引入了静态模板提升和标记和补丁(PatchFlag)等新特性来提高性能。
在 Vue2 中,响应式系统使用的是 Object.defineProperty 来实现数据监听,但是这种方法有一些缺陷,比如无法监听新增属性,而且对于数组的监听也比较麻烦。Vue3 中使用 Proxy 对象来实现数据监听,可以监听对象的新增属性,而且对于数组的监听也更加方便。
Proxy 对象是 JavaScript 中的一个内置对象,可以用来拦截对象的操作,比如读取、赋值、删除等操作。在 Vue3 中,可以使用 Proxy 对象来拦截对象的读取和赋值操作,以便实现数据监听和双向绑定。
6、说下虚拟DOM和diff算法,key的作用
虚拟 DOM 是指使用 JavaScript 对象来描述真实 DOM 中的节点,通过对比前后两次虚拟 DOM 的差异,可以最小化地更新真实 DOM,提高页面渲染效率。Diff 算法是用来比较前后两个虚拟 DOM 的差异的算法,它会通过递归遍历虚拟 DOM 的节点,找出节点的差异,然后对差异进行相应的操作,例如添加、删除、更新等。
key 是在使用虚拟 DOM 进行更新时,用来确定哪些节点是相同的,哪些节点是不同的。当更新虚拟 DOM 时,Diff 算法会比较前后两个虚拟 DOM 的节点,如果两个节点的 key 值相同,则认为它们是相同的节点,可以直接进行更新操作;如果 key 值不同,则认为它们是不同的节点,需要进行删除、添加、更新等操作。