同程旅行前端面试题牛客统计
统计一下牛客上的同程旅行前端面试八股文
$route 和 $router的区别是什么
$route 和 $router 是两个在 Vue.js 框架中使用的变量,它们的区别如下:
- $router: 是 Vue Router 实例,是Vue.js的路由器,用于创建路由映射、监听URL变化并展示对应的组件等。通过 $router 可以实现跳转到指定路由、获取当前路由等操作。
- $route: 是当前路由对应的路由信息对象,包含当前 URL 解析得到的信息,如当前的路径、参数、查询参数等等。通过 $route 可以获取当前路由信息并在组件内部使用。
综上所述,$router 是 Vue.js 路由器对象,用于创建和管理路由,而 $route 是当前路由的信息对象,用于访问和操作当前路由信息
js里面的数据类型有哪些,有哪些判断方法,各有什么优缺点
JavaScript中的数据类型分为两类:原始数据类型和引用数据类型。原始数据类型包括字符串(String)、数字(Number)、布尔(Boolean)、空(null)、未定义(undefined)、Symbol(Symbol),引用数据类型包括对象(Object)和函数(Function)
在es2020又加入了bigint
instanceof
判断引用数据类型typeof
判断基本数据类型,对于引用数据类型全部判断为object
Object.prototype.toString.call()
js里的this指向和this指向的优先级
JavaScript 中的 this 关键字指向当前函数的执行上下文,它的指向是动态的,取决于函数的调用方式和上下文。JavaScript 中的 this 指向的优先级可以按照以下顺序排列:
- new 绑定:如果一个函数是通过 new 操作符调用的,则 this 指向新创建的对象。
- 显式绑定:如果在函数调用时使用了 call()、apply() 或 bind() 方法,则 this 指向被显式绑定的对象。
- 隐式绑定:如果一个函数是作为对象的方法调用的,则 this 指向该对象。
- 默认绑定:如果一个函数是独立调用的(不是作为对象的方法、也没有使用 call()、apply() 或 bind() 方法),则 this 指向全局对象(在浏览器中是 window 对象,在 Node.js 环境中是 global 对象)。
需要注意的是,在严格模式下,默认绑定的 this 指向 undefined,而不是全局对象
浏览器缓存策略
浏览器缓存策略是指浏览器在请求资源时如何利用缓存,避免重复请求相同的资源,从而提高网页的性能和用户体验。常见的浏览器缓存策略包括以下几种:
- 强缓存:浏览器在请求资源时,先检查本地缓存是否存在该资源的缓存副本,并根据缓存规则判断是否可用。如果可用,则直接使用本地缓存,不会向服务器发送请求。如果不可用,则向服务器发送请求。
- 协商缓存:如果强缓存失效,浏览器会向服务器发送请求,并带上上次请求时服务器返回的缓存标识(如 Last-Modified 或 ETag 等)。服务器根据缓存标识判断资源是否已经发生变化。如果没有变化,则返回 304 Not Modified 响应,浏览器直接使用本地缓存。如果资源已
js里的闭包以及闭包的运用场景
闭包是指在函数内部定义的函数,这个内部函数可以访问外部函数的变量和参数,即使外部函数已经执行完毕,内部函数仍然可以访问这些变量和参数。闭包是 JavaScript 中一个非常重要的概念,它可以帮助我们实现一些高级的功能和设计模式。
闭包通常用于以下场景:
- 封装变量和方法:使用闭包可以封装变量和方法,使其不被外部访问和修改,从而保护代码的安全性。
- 实现模块化:使用闭包可以创建私有作用域,将相关的变量和方法封装在一起,形成模块化的代码结构。
- 记忆函数状态:使用闭包可以记忆函数的状态,即使函数多次调用,也可以保留上一次调用时的状态。
- 延迟执行:使用闭包可以实现函数的延迟执行,将函数放到队列中,等待异步操作完成后再执行。
- 解决循环绑定问题:使用闭包可以解决循环绑定问题,即在循环中创建事件监听函数时,需要访问循环变量的值,但由于 JavaScript 中的作用域链特性,会导致所有事件监听函数都访问同一个变量值的问题
new发生的事
使用
new
操作符时,主要做了以下几件事情:
- 创建一个新的对象:
new
操作符会创建一个新的对象,并将其赋值给this
变量。- 继承构造函数的原型:
new
操作符会将新对象的__proto__
属性指向构造函数的原型对象,从而实现继承。- 执行构造函数:
new
操作符会执行构造函数,并将this
指向新创建的对象。构造函数可以通过this
来操作新对象的属性和方法。- 返回新对象:如果构造函数没有返回值或返回值不是对象,则返回新创建的对象;如果构造函数返回一个对象,则返回该对象
浏览器同源策略
同源策略是浏览器的一项安全策略,它指的是不同源的文档(来源包括协议、主机名和端口号)之间不能相互访问对方的内容,只有在相同源的文档之间才允许相互访问。
同源策略的作用是防止恶意网站通过跨域访问其他网站的敏感信息,从而保障了用户的隐私安全。例如,如果某个网站可以跨域访问其他网站的 cookie,那么它就可以盗取其他网站的用户登录信息,从而实现恶意用途。
同源策略对于以下内容进行限制:
- Cookie、LocalStorage 和 IndexDB 等存储机制的读取。
- DOM 节点的读写操作。
- AJAX 请求的发送和接收。
- iframe 的访问。
除了同源策略之外,浏览器还提供了一些跨域访问的方式,比如 JSONP、CORS 和 WebSocket 等,这些方式可以让不同源的文档之间进行安全的通信。
需要注意的是,同源策略只是浏览器的安全策略,对于服务器端的安全问题并没有太大的帮助,因此在实际开发中,需要同时考虑浏览器端和服务器端的安全问题
一个域下的js可以访问另一个域下的cookie、localStorage吗
根据浏览器的同源策略,一个域下的 JavaScript 无法访问另一个域下的 Cookie、LocalStorage 等存储机制,除非这两个域符合同源规则。
同源规则包括协议、主机名和端口号三部分,只有当两个文档在这三部分完全相同的情况下,才被认为是同源,才可以互相访问各自的 Cookie、LocalStorage 等存储机制。
例如,如果一个网站的域名是
https://www.example.com
,那么它无法访问https://www.other.com
的 Cookie、LocalStorage 等存储机制。即使两个网站的 IP 地址相同,也不能互相访问 Cookie、LocalStorage 等存储机制,因为同源策略是基于域名而不是 IP 地址的
es6的模块化和commonJs模块有什么区别
- 语法不同:ES6 的模块化采用了
import
和export
语法,而 CommonJS 模块则使用require
和module.exports
语法。- 加载方式不同:ES6 的模块化使用异步加载方式,需要在模块中显式地使用
import()
方法异步加载模块,而 CommonJS 模块则使用同步加载方式,在程序运行时同步地加载模块。- 变量绑定方式不同:ES6 的模块化采用了静态绑定方式,即在编译阶段就已经确定了导出和导入的变量,而 CommonJS 模块则采用了动态绑定方式,即在运行时才能确定导出和导入的变量。
- 作用域不同:ES6 的模块化采用了严格的模块作用域,即每个模块内部的变量和函数只能在该模块内部访问,而 CommonJS 模块则采用了非严格的模块作用域,即每个模块内部的变量和函数都是对全局作用域的污染。
- 导入和导出方式不同:ES6 的模块化允许将多个变量或函数导出为一个对象,也可以通过
export default
导出一个默认值,而 CommonJS 模块则只能导出一个对象或函数。需要注意的是,ES6 的模块化还需要浏览器或 Node.js 等运行环境的支持,而 CommonJS 模块则是 Node.js 原生支持的模块化规范
vue组件通信
- 父子组件之间通信:父组件可以通过 props 属性将数据传递给子组件,子组件则可以通过 $emit 方法触发自定义事件将数据传递给父组件。
- 兄弟组件之间通信:在 Vue 中,兄弟组件之间的通信需要通过它们共同的父组件来实现。可以通过父组件作为中介,将数据传递给兄弟组件,也可以使用一个全局事件总线来实现。
- 祖先和后代组件之间通信:可以通过在祖先组件上使用 $on 监听事件,然后在后代组件上使用 $emit 触发事件来实现。
- 使用 Vuex 管理组件间的状态:Vuex 是一个专门为 Vue.js 应用程序开发的状态管理模式。它可以帮助我们管理组件之间的共享状态,并提供了一些方便的 API 来实现组件间的通信。
- 使用事件总线:可以使用 Vue 实例作为事件总线,通过 $emit 和 $on 方法来实现组件间的通信
事件循环
事件循环(Event Loop)是 JavaScript 运行时的一种机制,用于协调和处理异步任务。JavaScript 是单线程执行的,但是它可以使用回调函数、Promise、async/await 等方式来处理异步任务。事件循环机制是将这些异步任务分配到合适的时机去执行,确保程序的正常运行。
事件循环机制的核心是一个事件队列(Event Queue),任务分为两种类型:宏任务(Macro Task)和微任务(Micro Task)。
- 宏任务:包括 script(整体代码)、setTimeout、setInterval、setImmediate、I/O、UI 渲染等任务。
- 微任务:Promise、process.nextTick、Object.observe(已废弃)、MutationObserver 等任务。
事件循环的执行过程如下:
- 执行整体代码(script),并将其中所有的宏任务和微任务按照顺序加入到事件队列中。
- 从事件队列中取出一个宏任务执行,如果这个宏任务中有微任务,也会将所有微任务执行完毕后才继续执行下一个宏任务。
- 如果在执行宏任务或微任务的过程中,又产生了新的宏任务或微任务,也会按照顺序加入到事件队列中。
- 当前宏任务执行完毕后,会检查是否有未执行的微任务,如果有则按照顺序执行所有微任务,直到微任务队列为空。
- 然后继续从事件队列中取出下一个宏任务执行,重复上述过程,直到事件队列为空
路由守卫
路由守卫是指在用户访问或离开某个路由时,能够触发的一些钩子函数。在 Vue.js 中,路由守卫分为全局守卫和路由独享的守卫。
全局守卫:
- beforeEach(to, from, next):在进入路由之前调用,可以在此方法中进行用户权限验证等操作。
- afterEach(to, from):在离开路由之后调用,可以在此方法中进行页面埋点等操作。
- beforeResolve(to, from, next):在路由解析之前调用,可以在此方法中进行加载动画等操作。
路由独享守卫:
- beforeEnter(to, from, next):在进入路由之前调用,可以在此方法中进行路由参数验证等操作。
组件内守卫:
- beforeRouteEnter(to, from, next):在进入路由之前调用,但是此时该组件还没有被创建,无法访问 this 对象。
- beforeRouteUpdate(to, from, next):在当前路由改变,但是该组件被复用时调用。
- beforeRouteLeave(to, from, next):在离开当前路由时调用,可以在此方法中进行数据保存等操作
vuex适用场景
Vuex 是一个专门为 Vue.js 应用程序开发的状态管理模式。它解决了组件之间共享状态的问题,使得状态的变化可以被预测和追踪。Vuex 适用于以下场景:
- 多个组件需要共享同一个状态数据,例如购物车中商品数量的变化需要在多个组件中同步。
- 组件之间需要频繁的传递数据,例如多级组件之间的数据传递。
- 需要对状态进行复杂的逻辑处理和变化,例如购物车中商品数量的增减、价格的计算等。
- 需要对状态进行统一的管理和维护,方便调试和维护
webpack中的loader和plugin
- Loader:Webpack将所有的文件都视为模块,但是Webpack原生是只能解析JavaScript文件的,如果要处理其他类型的文件,就需要使用Loader进行转换。Loader可以将文件从不同的语言(如TypeScript)转换为JavaScript,或将非JavaScript代码(如CSS、图片)转换为Webpack能够处理的模块。Webpack Loader使得开发者可以使用各种各样的文件类型,并将它们转换为应用程序的一部分。常见的Loader有babel-loader(将ES6代码转换为ES5)、css-loader(处理CSS文件)、file-loader(处理图片等静态资源)等。
- Plugin:Plugin是Webpack的另一个重要概念,可以用于解决Loader无法解决的问题。Plugin可以用于执行范围更广的任务,包括打包优化、资源管理、注入环境变量等。Plugin可以拦截Webpack的编译过程,在编译过程中执行一些额外的操作。Webpack自带了一些常用的Plugin,比如UglifyJsPlugin(用于压缩JavaScript代码)、ExtractTextPlugin(将CSS提取到单独的文件中)、HtmlWebpackPlugin(用于生成HTML文件并自动引入打包后的资源)等。开发者也可以编写自己的Plugin,以实现特定的需求
HTML5新增
- 语义化标签:HTML5引入了很多新的语义化标签,例如
<header>
、<footer>
、<nav>
、<article>
、<section>
等,这些标签可以更好地描述网页的内容结构,提高了网页的可访问性和可读性。- 表单控件:HTML5新增了一些表单控件,例如日期选择器、颜色选择器、搜索框等,这些控件可以提高用户的体验和效率。
- 视频和音频:HTML5引入了
<video>
和<audio>
标签,可以在网页中直接播放视频和音频,不需要依赖Flash等插件。- Canvas:HTML5的Canvas元素可以在网页中实现各种图形和动画效果,可以替代Flash等插件。
- Web Storage:HTML5的Web Storage API提供了一种在浏览器中存储数据的方式,包括localStorage和sessionStorage两种存储方式。
- Web Workers:HTML5的Web Workers API允许在后台运行JavaScript脚本,可以提高网页的性能和响应速度。
- Geolocation:HTML5的Geolocation API可以获取用户的地理位置信息,可以用于实现各种地理位置相关的应用。
- Web Sockets:HTML5的Web Sockets API可以实现双向通信,可以用于实现实时应用程序,例如聊天应用、在线游戏等
meta标签
Meta标签是HTML文档头部的一种特殊标签,用于提供一些关于HTML文档的元数据信息。常见的meta标签有以下几种:
<meta charset="编码方式">
:用于指定文档的字符编码方式,一般设置为UTF-8。<meta name="viewport" content="设置参数">
:用于设置网页在移动端的视口,包括宽度、缩放比例等。<meta name="keywords" content="关键词列表">
:用于设置网页的关键词,便于搜索引擎识别网页的主题。<meta name="description" content="网页描述">
:用于设置网页的描述信息,便于搜索引擎显示网页的摘要。<meta http-equiv="refresh" content="秒数;URL=跳转网址">
:用于设置网页自动刷新或跳转到另一个网址。<meta name="robots" content="设置参数">
:用于设置搜索引擎蜘蛛的访问权限,包括允许访问、禁止访问等。<meta name="author" content="作者名">
:用于设置网页的作者信息。<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
:用于告诉IE浏览器使用最新的渲染模式。通过设置不同的meta标签,可以提高网页的SEO效果、用户体验和性能等方面
边距折叠
边距折叠是指在某些情况下,相邻的两个元素的外边距会发生合并的现象,使得它们的外边距取最大值而不是简单地相加。边距折叠会对网页的布局产生一定的影响,因此在网页设计中需要注意。
边距折叠通常出现在以下几种情况:
- 相邻的兄弟元素的上下外边距会发生合并。
- 父元素的上下外边距与第一个或最后一个子元素的上下外边距会发生合并。
- 空元素的上下外边距会发生合并。
边距折叠的原因是由于CSS规范中定义的外边距合并规则。当两个相邻的元素的上下外边距相遇时,它们会合并成一个外边距,高度等于两个外边距中的较大值。这种合并方式可以减少不必要的外边距空间,但也会导致布局出现意外的结果。
为了避免边距折叠,可以使用一些技巧,例如:
- 为元素添加padding或border,可以阻止外边距的合并。
- 为元素设置浮动或绝对定位,也可以阻止外边距的合并。
- 为父元素添加overflow:hidden属性,可以防止子元素的外边距与父元素的外边距合并。
- 为相邻元素之间添加空白字符或注释,可以避免它们的外边距合并。
- 使用CSS3的Flexbox或Grid布局,可以更加精细地控制元素的外边距
相对定位和绝对定位的区别
- 相对定位(Relative Positioning):相对定位是相对于元素本身原本应该所在的位置进行定位,元素仍保留原有的空间占用,并不会影响到其他元素的布局。通常使用
position: relative;
进行设置。- 绝对定位(Absolute Positioning):绝对定位是相对于其父级元素(若没有则相对于body)进行定位,元素脱离文档流,不再保留原有的空间占用,可能会影响到其他元素的布局。通常使用
position: absolute;
进行设置。相对定位和绝对定位最大的区别就是是否会脱离文档流,以及相对位置的参照点不同,因此它们的使用场景也不同。相对定位通常用于微调元素的位置,而绝对定位通常用于实现浮动窗口、导航菜单等需要脱离文档流的布局
onload和onready
onload
和onready
是两个常见的事件,它们都是在网页加载完成后触发执行。不过它们的触发时机和作用范围有所不同。
onload
事件是在整个页面以及所有的资源(如图片、音频等)都已经加载完毕后触发。可以用来执行一些需要等待页面所有资源加载完成后才能进行的操作,比如初始化某些组件、向后端请求数据等。
onready
事件是指当DOM树构建完成后就会触发,此时可能图片还没有加载完毕,不过DOM节点已经可以操作。可以用来执行一些不需要等待页面所有资源加载完成的操作,比如初始化一些DOM节点、执行一些页面样式操作等。需要注意的是,
onready
事件并不是HTML标准中定义的事件,而是jQuery库中提供的一个函数,用于封装DOMContentLoaded
事件的执行。在使用纯JS的时候,可以使用DOMContentLoaded
事件来替代onready
事件
defer和async
defer
和async
都是用来控制脚本的加载和执行时机的属性。
defer
属性用于告诉浏览器延迟脚本的执行,即在文档解析完成后再执行脚本。这样可以使得页面的渲染不会被脚本的执行所阻塞,提高页面的加载速度。同时,多个使用defer
属性的脚本会按照它们在页面中出现的顺序依次执行。
async
属性用于告诉浏览器脚本可以异步加载和执行,即在脚本下载完成后立即执行脚本,而不会等待页面的解析。这种方式可以提高页面的渲染速度,但是可能会导致脚本的执行顺序不确定,因为多个async
属性的脚本是并行加载和执行的,可能会出现先下载后执行的情况。需要注意的是,
defer
和async
属性只对外部脚本文件有效,不对内部脚本和行内脚本生效。同时,如果同时使用defer
和async
属性,defer
会覆盖async
,即使两个属性都存在,也会按照defer
的方式执行脚本
ESM和CJS
ESM (ES6 Module)和CJS (CommonJS)是两种不同的模块系统。
ESM是ES6引入的模块系统,它支持静态编译,模块的导入和导出只能发生在模块的顶层,通过
import
和export
关键字实现。ESM 的模块在加载时进行解析,不允许在模块内部动态加载其他模块。CJS是Node.js最初引入的模块系统,它支持动态编译,模块的导入和导出可以发生在任何位置,通过
require
和module.exports
实现。CJS 的模块在运行时加载,允许在模块内部动态加载其他模块。ESM与CJS之间的主要区别有:
- 加载方式不同:ESM采用静态加载,即在编译时确定依赖关系;CJS采用动态加载,在运行时确定依赖关系。
- 导出方式不同:ESM通过
export
关键字导出模块,支持导出变量、函数和类等;CJS通过module.exports
导出模块,支持导出任何类型的数据。- 导入方式不同:ESM通过
import
关键字导入模块,可以导入具名导出和默认导出;CJS通过require
关键字导入模块,只能导入整个模块对象。- 兼容性不同:ESM需要浏览器和Node.js环境支持ES6,而CJS在Node.js环境下具有广泛的兼容性,也可以通过工具转换成其他格式的模块系统
为什么 Vue2 中无法监听数组变化,如何解决
在 Vue2 中,当使用
Object.defineProperty
监听对象属性变化时,无法监听数组的变化。这是因为在 JavaScript 中,数组是通过索引来访问元素的,而Object.defineProperty
只能对对象的属性进行劫持,因此对于数组的监听需要采用其他方法。
cookie sessionStorage loaclStorage:
存储容量:
Cookie:每个 Cookie 的存储容量一般为 4KB 左右。
sessionStorage 和 localStorage:每个域名下的 sessionStorage 和 localStorage 的存储容量通常为 5MB 左右。
数据存储时间:
Cookie:可以设置过期时间,可以在不同的页面间共享。
sessionStorage:存储在 sessionStorage 中的数据在页面会话结束时会被删除,即当用户关闭浏览器窗口时会被清空。如果用户在同一浏览器窗口中打开多个页面,则每个页面会话都会独立存储。因此,同一浏览器窗口中不同页面间无法共享 sessionStorage 中的数据。
localStorage:存储在 localStorage 中的数据不会过期,除非用户手动删除或者清空浏览器缓存。与 sessionStorage 不同的是,同一浏览器窗口中不同页面间可以共享 localStorage 中的数据。
数据传输:
Cookie:每次请求都会携带 Cookie 数据,如果 Cookie 数据过大会影响页面加载速度。
sessionStorage 和 localStorage:数据存储在客户端,不会随着每次请求被传输,因此对页面加载速度影响较小。
数据安全:
Cookie:存储在客户端,容易被窃取或篡改,因此不适合存储敏感数据。
sessionStorage 和 localStorage:存储在客户端,但可以通过设置 HTTP-only、secure 等属性增加数据的安全性,适合存储敏感数据。
综上所述,Cookie、sessionStorage 和 localStorage 各有优缺点,需要根据实际需求进行选择。例如,如果需要存储用户登录信息等敏感数据,应该选择 sessionStorage 或 localStorage,并设置相关属性以增加数据安全性;如果需要在不同页面间共享数据,可以选择使用 Cookie 或者 localStorage 等
Vue2 的 mixin 有什么作用
在 Vue2 中,mixin 是一种混入机制,可以在多个组件中共享一些公共的逻辑或方法。具体来说,mixin 是一个对象,里面可以包含一些组件选项,如
data
、methods
、created
等。当组件使用mixins
选项引入一个 mixin 时,该组件会将 mixin 对象中的选项与自身选项合并,从而实现对该 mixin 中选项的共享。mixin 的主要作用有:
- 多个组件之间可以共享一些公共的逻辑或方法,从而避免代码重复。
- 可以将通用的业务逻辑和功能封装成 mixin,提高代码复用性和可维护性。
- mixin 可以通过
Vue.mixin
全局注册,从而让多个组件都能使用该 mixin。需要注意的是,使用 mixin 可能会带来一些副作用,如可能会造成命名冲突、引起意外的数据变化等,因此在使用 mixin 时需要小心谨慎。此外,在 Vue3 中,mixin 已经被 Composition API 所取代,更加灵活和易用
react hooks和 vue composition的区别
React Hooks 和 Vue Composition API 都是用来管理组件状态的工具,它们的本质都是为了解决类组件在状态管理方面的一些缺点,使函数式组件也能像类组件一样方便地处理状态。
以下是 React Hooks 和 Vue Composition API 的区别:
- 语法不同:React Hooks 使用
useState
、useEffect
等 Hook 函数来管理组件状态和副作用,而 Vue Composition API 使用ref
、reactive
、watchEffect
等函数来管理组件状态和副作用。- Hooks 可以定义多个,而 Composition API 只有一个:React Hooks 可以定义多个 Hook,每个 Hook 对应一个状态和一些处理该状态的逻辑。而 Vue Composition API 中只有一个
setup
函数,用于定义组件状态和逻辑。- Hooks 没有严格的依赖收集机制,而 Composition API 的依赖收集机制更严格:在 React Hooks 中,需要手动指定依赖项,如果依赖项不正确会导致一些问题,比如性能问题或状态不更新等。而在 Vue Composition API 中,通过使用
ref
、reactive
等函数创建的响应式对象,会自动进行依赖收集,确保状态更新时组件能够正确渲染。- Hooks 可以在函数式组件和自定义 Hook 中使用,而 Composition API 只能在函数式组件中使用:React Hooks 可以在函数式组件中使用,也可以在自定义 Hook 中使用。而 Vue Composition API 只能在函数式组件中使用。
总的来说,React Hooks 和 Vue Composition API 都是用来管理组件状态的工具,它们在语法和依赖收集机制上有一些区别,但都可以有效地解决函数式组件在状态管理方面的一些问题