文章目录
笔试题1. 实现一个深拷贝2. 扁平化数组3. 数组去重4. 实现一个闭包 一面1. 计算一个字符在字符串中出现的次数2. for of和for in 的区别3. let const 的区别4. filter使用方法5. 数组遍历有哪些方法6. vue2 vue3 响应式原理分析Vue 2 的响应式原理Vue 3 的响应式原理 7. vue3升级优化分析
笔试题
1. 实现一个深拷贝
function deepcopy(obj){ if(typeof obj!=='Object'||obj===null) return obj else { let newobj=Array.isArray(obj)? []:{} for(let key in obj) { if(obj.hasOwnProperty(key)) { newobj[key]=deepcopy(obj[key]) } } return newobj }}
2. 扁平化数组
指将嵌套的多维数组转换为一个一维数组
function flattenArray(arr){ let newArray=arr.reduce((acc,curr)=> { if(Array.isArray(curr)) { return acc.concat(flattenArray(curr)) } else return acc.concat(curr) },[]) return newArray}const nestedArray = [1, [2, [3, 4], 5], 6];const flattenedArray = flattenArray(nestedArray);console.log(flattenedArray); // 输出 [1, 2, 3, 4, 5, 6]
3. 数组去重
//方法1function removeRepeatArray(arr){ let newArray=arr.reduce((acc,curr)=> { if(!acc.includes(curr)) acc.push(curr) return acc },[]) return newArray}//方法2function removeRepeatArray(arr){ return Array.from(new Set(arr))}
4. 实现一个闭包
function closeFunc(){ let a=1 function hh() { a++ console.log(a) } return hh}const innerFunc = closeFunc(); // 调用 closeFunc,得到内部函数的引用innerFunc(); // 执行返回的内部函数 hh,输出 2innerFunc(); // 继续执行内部函数,输出 3
一面
1. 计算一个字符在字符串中出现的次数
//方法1function countString(char,str){ let count=0 for(let i=0;i<str.length;i++) { if(char===str.charAt(i)) count++ } return count}//方法2function countString(char,str){ const regex=new RegExp(char,'g') let arr =[] arr=str.match(regex) return arr.length}const char = 'a';const str = 'banana';const count = countString(char, str);console.log(count); // 输出 3
2. for of和for in 的区别
for...of
和 for...in
是 JavaScript 中两种不同的迭代循环语句,它们在使用上有一些区别。
for...of
循环:
用于遍历可迭代对象(例如数组、字符串、Set、Map、Generator 等)的值。
循环体内直接访问每个元素的值,而不是索引或键。
不适用于遍历普通对象(Plain Object)。
语法:
for (const value of iterable) { // 循环体}
示例:
const arr = [1, 2, 3];for (const num of arr) { console.log(num); // 输出 1, 2, 3}
for...in
循环:
用于遍历普通对象(Plain Object)的可枚举属性。
循环体内访问的是每个属性的键(属性名)。
也可以用于遍历数组或类数组对象,但可能会出现意外结果,因为它遍历的是对象的键而不是索引。
语法:
for (const key in object) { // 循环体}
示例:
//遍历对象const obj = { a: 1, b: 2, c: 3 };for (const key in obj) { console.log(key); // 输出 a, b, c}//也可以遍历数组(会有问题)const arr = [8, 5, 9];for (const index in arr) { console.log(index); // 输出 0, 1, 2}//但是会有问题。//问题如下Array.prototype.customMethod = function() { console.log('Custom method');};const arr = [8, 5, 9];for (const index in arr) { console.log(index); // 输出 0, 1, 2, "customMethod"}//解答:因为for...in 循环遍历了数组的原型链上的属性//解决Array.prototype.customMethod = function() { console.log('Custom method');};const arr = [8, 5, 9];for (const index in arr) { if(arr.hasOwnProperty(index)) //判断是否是自身的属性,而不是原型上的属性 { console.log(index); // 输出 0, 1, 2 }}
总结:
for...of
用于遍历可迭代对象的值。for...in
用于遍历对象的可枚举属性,也可用于遍历数组的键。在处理数组时,推荐使用 for...of
,而在处理对象时,推荐使用 for...in
。 3. let const 的区别
可变性:let
声明的变量是可变的(mutable),意味着你可以重新赋值给这个变量。const
声明的变量是不可变的(immutable),意味着一旦被赋值就不能再改变。 作用域: 无论是 let
还是 const
声明的变量都具有块级作用域,它们在定义它们的块中可见,并且在该块结束后将被销毁。 重复声明: 在同一个作用域内,let
允许你重新声明同名变量,而 const
则不允许。 初始化: let
声明的变量可以在声明后稍后初始化。const
声明的变量必须在声明时进行初始化,且一旦初始化后就不能再重新赋值。 全局对象属性: 用 let
或 const
声明的全局变量不会成为全局对象的属性(在浏览器中是 window
对象),而用 var
声明的全局变量会成为全局对象的属性。 4. filter使用方法
是 JavaScript 数组的一个高阶函数,用于筛选数组中满足条件的元素,返回一个新的数组。
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];let evenNumbers=numbers.filter((ele,index,Arry)=>{ console.log(ele,index,Arry) //ele 为当前元素值,index为索引,Arry为原数组 return ele%2===0})console.log(evenNumbers);
5. 数组遍历有哪些方法
for循环for offor in 需要使用hasProperty判断forEachmapreducefilter6. vue2 vue3 响应式原理分析
Vue 2 和 Vue 3 的响应式原理有所不同。下面分别对 Vue 2 和 Vue 3 的响应式原理进行简要分析。
Vue 2 的响应式原理
Vue 2 使用了基于 Object.defineProperty
的劫持(Object.defineProperty-based Observer)来实现响应式。
data
数据进行递归遍历,并通过 Object.defineProperty
将每个属性转化为 getter/setter。这样一来,当访问或修改这些属性时,Vue 2 就能够监听到,并触发相应的依赖追踪和更新操作。依赖追踪:Vue 2 通过在 getter 中收集依赖,在访问属性时将依赖关系建立起来。每个属性都有一个对应的依赖收集器(Dep),用于存储依赖关系。Watcher:在模板编译过程中,Vue 2 会解析模板中的表达式,并创建对应的 Watcher。Watcher 会在初始化时触发一次属性的 getter,从而建立起属性与 Watcher 之间的关联。当属性发生变化时,会通知相关的 Watcher 进行更新。派发更新:当属性发生变化时,会触发对应的 setter,setter 中会通知属性对应的依赖收集器(Dep)派发更新。Dep 会遍历所有相关的 Watcher,并调用 Watcher 的更新函数,进而更新视图。 Vue 3 的响应式原理
Vue 3 使用了基于 ES6 的 Proxy 对象来实现响应式。相比 Vue 2 的劫持方式,Vue 3 的响应式原理更加简洁高效。
Proxy 对象:Vue 3 在组件初始化时,创建了一个根级的响应式代理对象,该对象会代理组件的data
数据。Proxy 对象可以拦截对代理对象的访问和修改操作。依赖追踪:Vue 3 使用了一个全新的响应式引擎,利用了 JavaScript 语言自身的特性。在访问代理对象时,会收集依赖关系,并建立起属性与依赖之间的映射关系。Reactivity API:Vue 3 提供了一组 API(如 reactive
、ref
、computed
等)用于创建响应式数据,这些 API 在内部会使用 Proxy 对象来实现响应式。副作用追踪:Vue 3 使用了类似于 React Hooks 的方式,通过 effect
函数来追踪副作用。effect
函数会在组件渲染时执行,并自动追踪其中访问的响应式数据,并建立起响应式数据与副作用之间的关联。派发更新:当响应式数据发生变化时,会自动触发更新,重新执行相关的副作用函数,同时通知组件进行局部更新,以保持视图与数据的同步。 总的来说,Vue 2 和 Vue 3 都使用了不同的技术手段来实现响应式。Vue 2 使用了 Object.defineProperty
进行数据劫持,而 Vue 3 则利用了 ES6 的 Proxy 对象来实现响应式,使得代码更加简洁高效。
7. vue3升级优化分析
Vue 3 相对于 Vue 2 在性能和开发体验上都有一系列的优化和改进。以下是一些主要的升级优化分析:
更好的性能: 虚拟 DOM 重写:Vue 3 对虚拟 DOM 进行了重写,使其更加高效。新的虚拟 DOM 实现减少了许多不必要的操作,并提高了渲染性能。静态提升:Vue 3 在编译阶段能够识别出静态节点,并将其提升为常量,减少了运行时的开销。Tree-shaking 支持:Vue 3 支持更好的 Tree-shaking,使得打包工具能够更好地优化代码,减少打包体积。 更小的体积: 模块化构建:Vue 3 的代码更加模块化,可以按需加载,从而减少了整体的体积。Composition API 的模块化引入:Vue 3 的 Composition API 具有模块化的特性,使得开发者可以更加灵活地组织代码,从而减少了代码量。 更好的 TypeScript 支持: 全面支持 TypeScript:Vue 3 的代码基本上是用 TypeScript 编写的,因此对 TypeScript 的支持更加全面和友好。更好的类型推断:Vue 3 在编译时会生成更加准确的类型定义,使得开发时能够获得更好的类型推断和代码提示。 更灵活的组件设计: Composition API:Vue 3 引入了 Composition API,使得组件的逻辑可以更加灵活地组织,提高了代码的可维护性和可复用性。Teleport 和 Suspense:Vue 3 新增了 Teleport 和 Suspense 这两个特性,使得开发者能够更灵活地控制组件的渲染位置和加载状态。 更好的开发体验: 更快的开发速度:通过 Composition API 和 TypeScript 的支持,使得开发者能够更快地编写和调试代码。更好的错误提示:Vue 3 对错误提示进行了改进,使得开发者能够更容易地定位和解决问题。总的来说,Vue 3 在性能、体积、开发体验和灵活性等方面都有明显的优化和改进,是一个更加成熟和强大的框架。因此,对于使用 Vue 的项目来说,考虑升级到 Vue 3 是一个非常值得的选择。