一、4.12

1、说一说cookie sessionStorage localStorage 是什么,有什么区别?

Cookie、sessionStorage 和 localStorage 都是在浏览器端存储数据的方式,它们的主要区别在于存储的数据范围、有效期和访问权限等方面。

  1. Cookie

Cookie 是一种在浏览器和 Web 服务器之间传递的小数据片段,它通常用于存储用户的身份验证令牌、用户偏好设置、购物车信息等。Cookie 的最大缺点是它们的大小受限,一般只能存储少量数据(通常不超过 4KB),并且每次请求都会将 Cookie 发送到服务器,因此可能会影响性能。

Cookie 的优点是它们可以设置过期时间,从而控制数据的有效期,并且可以在浏览器和服务器之间共享。Cookie 还可以设置跨域属性,允许在多个域名之间共享数据。

  1. sessionStorage

sessionStorage 是 HTML5 提供的一种会话存储机制,它可以在浏览器关闭后仍然保留数据。sessionStorage 中存储的数据只在同一浏览器窗口或标签页中有效,如果用户打开多个窗口或标签页,那么每个窗口或标签页都有自己的 sessionStorage。

sessionStorage 可以存储较大量的数据(通常在 5MB 左右),并且数据只在同一会话期间有效。sessionStorage 的主要用途是存储临时数据,例如表单数据、用户操作记录等。

  1. localStorage

localStorage 也是 HTML5 提供的一种本地存储机制,它与 sessionStorage 的区别在于数据的有效期,localStorage 中存储的数据可以跨越多个浏览器窗口或标签页,并且在浏览器关闭后仍然保留。

localStorage 与 sessionStorage 一样,可以存储较大量的数据,通常在 5MB 左右。localStorage 的主要用途是存储用户偏好设置、主题样式等持久性数据。

总的来说,Cookie、sessionStorage 和 localStorage 都是在浏览器端存储数据的方式,它们的主要区别在于存储的数据范围、有效期和访问权限等方面。需要根据实际需求选择合适的存储方式。

2、说一说Vue2.0双向绑定的原理与缺陷?

1、Vue 2.0 的双向绑定原理是通过使用数据劫持和发布-订阅模式来实现的。

具体来说,当 Vue 将数据对象传递给组件实例化时,Vue 会遍历对象的每个属性,并使用 Object.defineProperty() 方法将其转换为 getter 和 setter。这样,当属性被读取或修改时,Vue 可以拦截并触发相应的更新。

在模板中,Vue 通过使用 v-model 指令来实现双向绑定。当用户在表单控件中输入数据时,Vue 会自动更新组件数据对象中对应的属性值。反之亦然,当组件数据对象中的属性值被修改时,Vue 会自动更新对应的表单控件。

尽管 Vue 2.0 的双向绑定机制在使用上非常方便,但它也存在一些缺陷。其中最大的问题是性能问题。由于 Vue 2.0 使用了数据劫持机制,对于大型数据集合或频繁的数据更新操作,这种机制可能会带来显著的性能损失。此外,Vue 2.0 的双向绑定机制也增加了代码的复杂性,使得调试和维护变得更加困难。

2、Vue2.0 的双向绑定是通过数据劫持和发布订阅模式实现的,具体的实现原理如下:

  1. 在 Vue 初始化时,会对数据对象进行递归遍历,把每一个属性转换成 getter/setter,并且在数据对象上定义一个观察者 Watcher 对象;
  2. 当数据发生变化时,setter 会被触发,setter 会通知所有观察者 Watcher 对象,观察者 Watcher 对象就会依次执行 update 方法,更新视图;
  3. 在模板编译时,如果遇到 v-model 指令,会在相应的元素上添加一个事件监听器,当输入框的值发生变化时,会触发这个事件监听器,通过调用 setter 方法更新数据。

Vue2.0 双向绑定的缺陷主要有以下几点:

  1. 性能问题:每个属性都要添加 getter 和 setter,会导致一定的性能损失,尤其是在处理大量数据时;
  2. 内存泄漏:由于观察者 Watcher 对象和数据对象之间的强引用,如果不及时销毁观察者 Watcher 对象,就会导致内存泄漏;
  3. 无法监听数组和对象的变化:由于 Vue2.0 只能通过数据劫持监听属性的变化,无法监听数组和对象的变化,需要通过额外的方法进行处理;
  4. 深层嵌套数据监听问题:由于 Vue2.0 只能监听到对象属性的变化,无法监听到深层嵌套数据的变化,需要通过递归或者使用第三方库进行处理。

3、v-if和v-show的区别

v-if和v-show是Vue.js中两个常用的指令,它们都可以用来控制DOM元素的显示和隐藏,但是它们的实现方式有所不同,具体如下:

  1. v-if指令是对DOM元素进行条件渲染,只有在指定条件为真时才会渲染DOM元素,并在条件为假时销毁DOM元素。这意味着如果条件为假,DOM元素不会被渲染到页面上,也不会占据任何页面资源。因此,v-if适用于不经常改变的条件性显示内容。

  2. v-show指令是基于CSS的display属性来控制DOM元素的显示和隐藏。当条件为真时,该元素会被显示出来,当条件为假时,该元素会被隐藏。这意味着如果条件为假,DOM元素仍然存在于页面上,只是被设置为不可见状态。因此,v-show适用于频繁切换的显示内容。

总的来说,如果需要频繁切换元素的显示和隐藏状态,应该使用v-show指令,因为它只是简单地切换CSS的display属性,可以避免频繁的DOM操作。而如果元素的显示和隐藏状态不太经常改变,或者需要在条件为假时完全清除DOM元素,应该使用v-if指令。

4、说一说提高前端性能优化手段

 

  1. 减少HTTP请求:减少页面中的HTTP请求可以大大提高页面的加载速度。可以通过合并CSS和JavaScript文件、使用CSS Sprites和图像压缩等技术来减少HTTP请求。

  2. 压缩文件:压缩CSS、JavaScript和HTML文件可以减少文件大小,提高页面加载速度。可以使用Gzip或Deflate等压缩算法来压缩文件。

  3. 使用缓存:使用浏览器缓存可以减少页面的加载时间。可以使用HTTP缓存策略来控制缓存,例如设置Expires头、Cache-Control头等。

  4. 延迟加载:将非关键资源(如图片、广告等)的加载延迟到页面其它内容加载完成后再进行,可以提高页面的加载速度。可以使用LazyLoad等插件来实现延迟加载。

  5. 最小化DOM操作:DOM操作是非常耗费性能的操作,应该尽量减少DOM操作的次数和复杂度。可以使用文档片段(DocumentFragment)来减少DOM操作次数,使用事件委托(Event Delegation)来减少DOM操作复杂度。

  6. 使用CDN:使用CDN可以加快资源的加载速度,提高页面的响应速度。可以使用公共CDN,如Google、百度、360等,也可以使用自己的CDN。

  7. 优化图片:图片是页面中占用带宽最大的资源,应该尽量减小图片的大小。可以使用图像压缩和格式转换等技术来优化图片。

  8. 使用异步加载:使用异步加载可以将页面的加载和执行分离,提高页面的响应速度。可以使用异步加载的JavaScript库、defer属性和async属性等技术来实现异步加载。

  9. 代码优化:优化JavaScript和CSS代码可以减少文件大小,提高页面加载速度。可以使用压缩工具、代码检查工具、代码精简工具等来优化代码。

综上所述,前端性能优化是一个综合性的问题需要从多个方面进行优化。通过上述手段的应用,可以显著提高页面的加载速度和响应速度,从而提升用户的体验。

5、mvvm是什么

MVVM是一种前端架构模式,它是Model-View-ViewModel的缩写。MVVM模式将前端应用程序分为三个部分:模型(Model)、视图(View)和视图模型(ViewModel),并通过数据绑定技术将这三个部分连接在一起。

在MVVM模式中,模型表示应用程序的数据和业务逻辑,视图表示应用程序的用户界面,而视图模型则是连接模型和视图的桥梁,它负责处理视图的事件和数据,将模型数据绑定到视图上,并将用户输入反映到模型中。视图模型通常是由JavaScript编写的,它使用观察者模式来监听模型数据的变化,并通过数据绑定技术将变化传递到视图上,从而实现视图和模型之间的解耦。

MVVM模式的一个重要特点是数据双向绑定,即当模型中的数据发生变化时,会自动更新视图中的数据,而当用户在视图中输入数据时,会自动更新模型中的数据,从而实现了数据的同步更新,减少了手动操作的复杂性。

常见的MVVM框架包括AngularJS、Vue.js、KnockoutJS等。这些框架提供了丰富的工具和API,帮助开发者更轻松地实现MVVM模式,提高前端应用程序的开发效率和质量。

6、axios面试题

  1. 什么是Axios?
    Axios是一个基于Promise的HTTP客户端,用于浏览器和Node.js平台。它可以发送异步请求并处理响应数据,支持拦截器、取消请求、自动转换JSON数据等功能。

  2. Axios和其他HTTP客户端库的区别是什么?
    Axios相比其他HTTP客户端库,具有更简单、易用的API和更好的性能。它还可以在浏览器和Node.js平台上运行,支持拦截器、自动转换JSON数据等功能。

  3. 如何在Axios中设置请求头和响应头?
    可以使用config.headers属性来设置请求头,例如:

axios.get(url, {
  headers: {
    'Authorization': 'Bearer ' + token
  }
})

  

可以使用response.headers属性来获取响应头,例如:

axios.get(url)
  .then(response => {
    console.log(response.headers);
  });
  1. 如何实现Axios的请求超时?
    可以使用config.timeout属性来设置请求超时,例如:
axios.get(url, {
  timeout: 5000 // 5秒超时
})
  1. 如何在Axios中实现请求拦截器和响应拦截器?
    可以使用axios.interceptors.request.use()方法来实现请求拦截器,例如:
axios.interceptors.request.use(config => {
  // 在请求发送之前做些什么
  return config;
}, error => {
  // 对请求错误做些什么
  return Promise.reject(error);
});

可以使用axios.interceptors.response.use()方法来实现响应拦截器,例如:

axios.interceptors.response.use(response => {
  // 对响应数据做些什么
  return response;
}, error => {
  // 对响应错误做些什么
  return Promise.reject(error);
}); 

7、

8、

9、

10、

二、4.13

2.1、== 和 === 有什么区别

在大多数编程语言中,"==" 和 "===" 都是用于比较两个值是否相等的运算符,但它们之间有一些区别。

"==" 运算符执行弱类型比较,它会尝试将两个操作数转换为相同的类型,然后再进行比较。例如,在 JavaScript 中,"==" 运算符将数字字符串转换为数字,而将数字转换为数字字符串,然后将它们进行比较。这意味着如果两个值的类型不同,但它们的值相等,"==" 运算符也会返回 true。

"===" 运算符执行强类型比较,它会比较两个操作数的值和类型是否完全相同。例如,在 JavaScript 中,"===" 运算符将不会尝试将数字字符串转换为数字,而是直接比较它们的类型和值。这意味着如果两个值的类型不同,"===" 运算符会返回 false,即使它们的值相等。

因此,"===" 运算符比 "==" 运算符更严格,更准确地比较两个值。在编程中,应该根据需要选择使用哪种运算符,以确保比较得到正确的结果。

以下是一个使用 JavaScript 的例子,展示了 "==" 和 "===" 运算符的区别:

let num = 5;
let strNum = "5";

console.log(num == strNum); // true,因为 "==" 运算符会将 strNum 转换为数字类型,然后比较它们的值
console.log(num === strNum); // false,因为 "===" 运算符会比较 num 和 strNum 的类型和值,类型不同,所以返回 false

2.2、什么是网络存储?有什么区别

网络存储指的是将数据存储在网络上的一种技术。这种技术可以让用户通过网络访问和共享存储在网络中的数据,而无需在本地计算机上存储数据。

网络存储有多种形式,包括云存储、网络硬盘、NAS(网络附加存储)等。这些网络存储形式都有一个共同的特点,就是它们可以通过网络连接访问和共享存储在其中的数据。

相比于传统的本地存储方式,网络存储有以下区别:

  1. 可以实现远程访问和共享:网络存储可以通过互联网实现数据的远程访问和共享,使得用户可以随时随地访问和共享存储在网络存储中的数据。

  2. 可以实现数据备份和容灾:网络存储可以将数据存储在多个地方,从而实现数据备份和容灾,保障数据的安全性和可靠性。

  3. 可以实现扩展性和灵活性:网络存储可以根据需要进行扩展和升级,从而满足数据存储的需求。

  4. 需要网络连接:网络存储需要网络连接才能访问和共享数据,因此对网络的稳定性和速度有一定的要求。

总的来说,网络存储可以提供更加便捷、安全、可靠和灵活的数据存储方式,但也需要注意网络的稳定性和速度等问题。

2.3、JavaScript的回调函数是什么

在 JavaScript 中,回调函数是指一个函数被作为参数传递给另一个函数,并在另一个函数执行完毕后被调用的函数。回调函数通常用于异步编程,例如处理定时器、事件处理函数、Ajax 请求等。

回调函数的使用可以避免阻塞代码的执行,因为它可以在另一个函数执行的同时进行其他的操作,并在需要时被调用。在 JavaScript 中,回调函数通常被定义为匿名函数或者命名函数。

以下是一个使用回调函数的例子,这个例子使用了 setTimeout 函数来模拟异步操作,并在异步操作完成后调用回调函数:

function doSomethingAsync(callback) {
  setTimeout(function() {
    console.log("异步操作完成!");
    callback();
  }, 1000);
}

function callback() {
  console.log("回调函数被调用了!");
}

doSomethingAsync(callback);

在上面的例子中,doSomethingAsync 函数接受一个回调函数作为参数,并在异步操作完成后调用回调函数。在调用 doSomethingAsync 函数时,我们将 callback 函数作为参数传递给它。

当异步操作完成后,setTimeout 函数会调用匿名函数,并在其中调用回调函数。因此,在执行 doSomethingAsync 函数时,我们会看到 "异步操作完成!" 和 "回调函数被调用了!" 这两个日志消息。

2.4、为什么要使用promises

在 JavaScript 中,Promises 是一种用于异步编程的解决方案,它可以更好地处理异步操作,提高代码的可读性和可维护性。以下是一些使用 Promises 的好处:

  1. 避免回调地狱:在传统的回调函数中,如果需要执行多个异步操作,代码会出现多层嵌套的回调函数,这被称为回调地狱。使用 Promises 可以避免回调地狱,使代码更加简洁和易于理解。

  2. 更好的错误处理:在传统的回调函数中,错误处理比较麻烦,容易出现错误处理不到位的情况。而在 Promises 中,可以通过 catch 方法捕获错误,并进行统一的处理。

  3. 支持链式调用:Promises 可以支持链式调用,使得代码更加简洁和易于理解。例如,可以通过 then 方法在多个异步操作之间传递数据。

  4. 更好的可读性:使用 Promises 可以使代码更加易于理解和可读性更高,因为 Promises 中的代码按照顺序排列,而不是嵌套在多个回调函数中。

总之,Promises 可以帮助开发人员更好地处理异步操作,提高代码的可读性和可维护性。虽然 Promises 的学习曲线可能比较陡峭,但是一旦掌握了 Promises 的使用方法,就可以更加轻松地处理异步操作。

2.5、JavaScript中的回调函数是什么

在 JavaScript 中,回调函数(Callback Function)是一种特殊的函数,它作为参数传递给另一个函数,并在该函数执行完成后被调用。回调函数通常被用来处理异步操作,例如读取文件、网络请求或定时器等。

以下是一个简单的回调函数的示例:

function fetchData(callback) {
  // 模拟异步操作
  setTimeout(function() {
    const data = { id: 1, name: 'John' };
    callback(data);
  }, 1000);
}

function processData(data) {
  console.log(data);
}

fetchData(processData);

在上述代码中,fetchData 函数模拟了一个异步操作,并接受一个回调函数作为参数。当异步操作完成后,fetchData 函数会调用回调函数,并将数据作为参数传递给它。在这个例子中,我们将 processData 函数作为回调函数传递给 fetchData 函数,当异步操作完成后,processData 函数会被调用,并将数据打印到控制台中。

回调函数是 JavaScript 中一种非常常见的编程模式,在处理异步操作时非常有用。同时,回调函数也有一些缺点,例如嵌套回调(Callback Hell)和难以处理错误等问题。因此,在现代 JavaScript 中,我们通常使用 Promise、async/await 等更高级的技术来处理异步操作。

2.6、typescript和JavaScript有何不同

TypeScript 和 JavaScript 是两种不同的编程语言,尽管它们非常相似,但它们之间有一些重要的区别:

  1. 类型系统:TypeScript 是一种带有静态类型检查的编程语言,而 JavaScript 是一种动态类型语言。在 TypeScript 中,可以使用类型注解来指定变量、函数和参数的类型,并且编译器会在编译时检查类型。这可以帮助开发人员在编写代码时更早地发现错误,并提高代码的可维护性和可读性。

  2. 扩展性:TypeScript 是 JavaScript 的超集,它可以使用 JavaScript 的所有功能,还可以添加新的功能,例如类、接口、枚举等。这使得 TypeScript 可以更好地支持大型应用程序的开发,并提供更好的代码组织和重用。

  3. 编译:TypeScript 需要先进行编译,将 TypeScript 代码转换为 JavaScript 代码,然后才能在浏览器或 Node.js 环境中运行。这可以帮助开发人员在编写代码时捕获错误,并将代码转换为可在任何浏览器或 Node.js 环境中运行的标准 JavaScript 代码。

  4. 生态系统:尽管 TypeScript 是一种相对较新的编程语言,但它已经有了强大的生态系统,并且有许多优秀的开源库和工具可供使用。TypeScript 支持 JavaScript 的所有库和工具,并且还有大量的 TypeScript 特定库和工具可供选择。

总之,TypeScript 和 JavaScript 之间的主要区别在于类型系统、扩展性、编译和生态系统。尽管在使用上有所不同,但它们都是非常有用的编程语言,可以用于开发各种类型的应用程序。

2.7、如何在TypeScript中定义和导出模块

在 TypeScript 中,可以使用关键字 export 来定义和导出模块。以下是一些示例:

  1. 导出单个变量或函数
// 定义
export const myVariable = 123;
export function myFunction() {
  console.log("Hello, world!");
}

// 导入
import { myVariable, myFunction } from "./myModule";
  1. 导出一个对象
// 定义
export const myObject = {
  name: "John",
  age: 30,
};

// 导入
import { myObject } from "./myModule";
  1. 导出一个类
// 定义
export class MyClass {
  greet() {
    console.log("Hello, world!");
  }
}

// 导入
import { MyClass } from "./myModule";
  1. 导出一个默认项
// 定义
export default function() {
  console.log("Hello, world!");
}

// 导入
import myFunction from "./myModule";

在上述示例中,我们使用 export 关键字来定义和导出模块,然后使用 import 关键字来导入模块。需要注意的是,当我们导出一个默认项时,可以使用 import 关键字来导入模块,而不需要使用大括号。

在 TypeScript 中,模块可以是单独的文件,也可以是命名空间。对于单独的文件,每个文件都是一个模块。对于命名空间,可以使用 namespace 关键字来定义,例如:

// 定义
namespace MyNamespace {
  export const myVariable = 123;
}

// 导入
import { MyNamespace } from "./myModule";

总之,使用 export 和 import 关键字可以帮助我们在 TypeScript 中定义和导出模块,使代码更加模块化和可读性更高。

2.8、说一说vue-router实现懒加载的方法

Vue Router 支持使用懒加载(Lazy Loading)来延迟加载路由组件,从而提高应用程序的性能。懒加载可以使得只有在用户访问到某个路由时才会加载相应的组件,而不是在应用程序启动时就加载所有的路由组件。

以下是实现懒加载的两种方法:

  1. 使用动态导入

Vue Router 支持使用动态导入来实现懒加载。在路由配置中,可以将组件配置为一个返回 import() 函数的函数,这个函数会在路由被访问时调用,并动态加载组件。例如:

const Foo = () => import('./Foo.vue')
const Bar = () => import('./Bar.vue')

const router = new VueRouter({
  routes: [
    { path: '/foo', component: Foo },
    { path: '/bar', component: Bar }
  ]
})

在上述代码中,Foo 和 Bar 组件都是使用 import() 函数来动态加载的。

  1. 使用异步组件

Vue Router 还支持使用异步组件来实现懒加载。异步组件是指组件的定义是一个返回 Promise 的函数,这个函数会在组件被渲染时调用,并动态加载组件。例如:

const Foo = () => ({
  component: import('./Foo.vue'),
  loading: LoadingComponent,
  error: ErrorComponent,
  delay: 200,
  timeout: 10000
})

const router = new VueRouter({
  routes: [
    { path: '/foo', component: Foo }
  ]
})

在上述代码中,Foo 组件被定义为一个返回 Promise 的函数,同时还提供了 loadingerrordelay 和 timeout 等选项,用于指定加载组件时的 loading 状态、错误处理、延迟和超时等。这些选项都是可选的,可以根据具体需要进行配置。

总之,无论是使用动态导入还是异步组件,Vue Router 都提供了很好的支持,可以帮助我们实现懒加载,提高应用程序的性能。

2.9、说一说get请求和post请求的区别

在 HTTP 协议中,GET 和 POST 是两种最常见的请求方法。它们之间的主要区别如下:

  1. GET 请求会将请求参数追加到 URL 中,而 POST 请求会将请求参数放在请求体中。因此,在 URL 中可以看到 GET 请求的请求参数,而 POST 请求的请求参数则不会出现在 URL 中。

  2. GET 请求提交的数据量有限,一般不超过 2KB。而 POST 请求提交的数据量可以很大,一般不受限制。因此,在传输大量数据时,应该使用 POST 请求。

  3. GET 请求是幂等的,也就是说,多次请求同一个 URL,得到的结果是相同的。而 POST 请求是非幂等的,不同的请求可能会返回不同的结果。

  4. GET 请求不应用于修改数据的操作,因为它会将数据暴露在 URL 中,容易被攻击者窃取。而 POST 请求可以用于修改数据,因为它将数据放在请求体中,相对安全。

  5. GET 请求可以被缓存,而 POST 请求不能。因为 GET 请求的参数是包含在 URL 中的,可以被浏览器缓存。而 POST 请求的参数是包含在请求体中的,不能被缓存。

总之,GET 和 POST 请求各有优缺点,应根据具体的需求来选择合适的请求方法。通常情况下,GET 请求用于查询数据,而 POST 请求用于修改数据。

2.10、 Computed和Watch的区别

对于Computed:
●它支持缓存,只有依赖的数据发生了变化,才会重新计算
●不支持异步,当Computed中有异步操作时,无法监听数据的变化
computed的值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data声明过,或者
父组件传递过来的props中的数据进行计算的。
●如果一个属性是由其他属性计算而来的,这个属性依赖其他的属性,-般会使用computed
如果computed属性的属性值是函数,那么默认使用get方法,函数的返回值就是属性的属性值;在computed
中,属性有一个get方法和一一个set方法,当数据发生变化时,会调用set方法。
对于Watch:
●它不支持缓存,数据变化时,它就会触发相应的操作
●支持异步监听
监听的函数接收两个参数,第一个参数是最新的值,第二个是变化之前的值
●当一个属性发生变化时,就需要执行相应的操作
. 监听数据必须是data中声明的或者父组件传递过来的props中的数据, 当发生变化时,会触发其他操作,函数
有两个的参数:
。immediate: 组件加载立即触发回调函数
。deep:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。需要注
意的是,deep无法监听到数组和对象内部的变化。
当想要执行异步或者昂贵的操作以响应不断的变化时,就需要使用watch。