前端面试题第三天

node.jsES6的模块化 中如何实现模块化 node.js 遵循了 CommonJS 的模块化规范。其中:

导入其它模块使 用 require() 方法 模块对外共享成员使 用 module.exports 对象 模块化的好处: 大家都遵守同样的模块化规范写代码,降低了沟通的成本,极大方便了各个模块之间的相互调用,利人利己。

  1. 前端模块化规范的分类 在 ES6 模块化规范诞生之前,JavaScript 社区已经尝试并提出了AMD、CMD、CommonJS 等模块化规范。 但是,这些由社区提出的模块化标准,还是存在一定的差异性与局限性、并不是浏览器与服务器通用的模块化

标准,例如:

AMD 和 CMD 适用于 浏览器端 的 Javascript 模块化 CommonJS 适用于 服务器端 的 Javascript 模块化 太多的模块化规范给开发者增加了学习的难度与开发的成本。因此,大一统的ES6 模块化规范诞生了!

  1. 什么是 ES6 模块化规范 ES6 模块化规范是浏览器端与服务器端通用的模块化开发规范。它的出现极大的降低了前端开发者的模块化学 习成本,开发者不需再额外学习AMD、CMD 或 CommonJS 等模块化规范。

ES6 模块化规范中定义:

每个 js 文件都是一个独立的模块 导入其它模块成员使用 import 关键字 向外共享模块成员使 用 export 关键字

  1. 在 node.js 中体验 ES6 模块化

    node.js 中默认仅支持 CommonJS 模块化规范,若想基于node.js 体验与学习ES6 的模块化语法,可以按照 如下两个步骤进行配置:

① 确保安装了v14.15.1 或更高版本的node.js

② 在 package.json 的根节点中添加 "type": "module" 节点

  1. ES6 模块化的基本语法

    ES6 的模块化主要包含如下 3 种用法:

① 默认导出与默认导入

② 按需导出与按需导入

③ 直接导入并执行模块中的代码

5.1 默认导出 默认导出的语法: export default 默认导出的成员

let n1 = 10  // 定义模块私有成员   n1
let n2 = 20  // 定义模块私有成员 (外界访问部到 n2, 因为它没有被共享出去)
function show(){}  // 定义模块私有方法  show
​
export default {   // 使用export default 默认导出语法,向外共享n1 和 show 两个成员。
    n1,
    show
}

5.1默认导入

默认导入的语法:import 接收名称 from ’模块标识符‘

// 从01_m1.js   模块中导入 export default 向外共享的成员
// 并使用 m1 成员进行接收
import m1 from './01_m1.js'
//打印输出的结果为:
// {n1:10,show:[Function:show]}
console.log(m1)

5.1 默认导出的注意事项

每个模块中,只允许使用唯一的一次export default ,否则会报错!!

let n1 = 10     // 定义模块私有成员 n1
let n2 = 20    // 定义模块私有成员 n2 (外界访问部不到 n2, 因为它没有被共享出去)
function show(){ }   // 定义模块私有方法  show
​
export default {  // 
    n1,
    show 
}
// Syn
export default {
    n2
}

5.1默认导入的注意事项

默认导入时的接收名称可以任意名称,只要是合法的成员名称

// m1 是合法的名称
import m1 from './01_m1.js'
// 123m 不是合法的名称,因为成员名称不能以数字开头
import 123m from '/'

5.1默认导入的注意事项

如果只想单纯地执行某个模块中的代码,并不需要得到模块中向外共享的成员。此时,可以直接导入并执行模 块代码,示例代码如下:

//当前文件模块
​
for(let i = 0; i < 3; i++){
    c
}

vue后端管理系统权限官理实现路由完全后端返回菜单动态渲染

后台管理系统项目中的路由需要权限管理,不同的角色登录看到的页面是不一样的,所以路由应该是后端动态返回,然后前端拿到路由表进行处理后调router.addRoutes([]) 添加到前端静态路由表中形成完整路由表。

1.实现完整路由表

1.首先需要在router文件夹里新建一个路由配置项的文件routes.js,在里面定义一个静态无权限的路由,如登录页和总布局页面。

//初始静态路由,无权限
 
let routes = [
 
    {
 
        path: "/login",
 
        name: "Login",
 
        component: "Login",
 
    },
 
    {
 
        path: "/",
 
        redirect: "/index",
 
        name: "Layout",
 
        component: "Layout",
 
        children: [
 
            {
 
                path: "password",
 
                name: "Password",
 
                component: "my/Password",
 
                mata: {
 
                    bread: ["修改密码"],
 
                },
 
            },
 
        ],
 
    },
 
    {
 
        path: "*",
 
        component: "404",
 
    },
 
];

2. 用户登录之前只能进入登录页面,这里设置了一个全局前置守卫,

1.说一说cookie sessionStorage localStorage 区别? 从数据存储位置、生命周期、存储大小、写入方式、数据共享、发送请求时是否携带、应用场景这几个方面来回答。 1.存储位置:Cookie、SessionStorage、 LocalStorage都是浏览器的本地存储。 它们的共同点:都是存储在浏览器本地的,它们的区别:cookie是由服务器端写入的,而SessionStorage、 LocalStorage都是由前端写入的, 2.生命周期:cookie的生命周期是由服务器端在写入的时候就设置好的,LocalStorage是写入就一直存在,除非手动清除,SessionStorage是页面关闭的时候就会自动清除。 3.存储大小:cookie的存储空间比较小大概4KB,SessionStorage、LocalStorage存储空间比较大,大概5M。 4.数据共享:Cookie、SessionStorage、LocalStorage数据共享都遵循同源原则,SessionStorage还限制必须是同一个页面。 5.是否携带:在前端给后端发送请求的时候会自动携带Cookie中的数据,但是SessionStorage、LocalStorage不会 总结:由于它们的以上区别,所以它们的应用场景也不同,Cookie一般用于存储登录验证信息SessionID或者token,LocalStorage常用于存储不易变动的数据,减轻服务器的压力,SessionStorage可以用来检测用户是否是刷新进入页面,如音乐播放器恢复播放进度条的功能。

2.说一说JS数据类型有哪些,区别是什么? JS数据类型分为两类: 一类是基本数据类型,也叫简单数据类型,包含7种类型,分别是Number 、String、Boolean、BigInt、Symbol、Null、Undefined。 另一类是引用数据类型也叫复杂数据类型,通常用Object代表,普通对象,数组,正则,日期,Math数学函数都属于Object。 两大类的本质区别:基本数据类型和引用数据类型它们在内存中的存储方式不同。 基本数据类型是直接存储在栈内存中的简单数据段,占据空间小,属于被频繁使用的数据。 引用数据类型是存储在堆内存中,占据空间大。引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址,当解释器寻找引用值时,会检索其在栈中的地址,取得地址后从堆中获得实体。 加分回答: Symbol是ES6新出的一种数据类型,这种数据类型的特点就是没有重复的数据,可以作为object的key。 BigInt是ES10新出的一种数据类型,这种数据类型的特点就是数据涵盖的范围大,能够解决超出普通数据类型范围报错的问题。

3.说一说你对闭包的理解? 得分点: 变量背包、作用域链、局部变量不销毁、函数体外访问函数的内部变量、内存泄漏、内存溢出、形成块级作用域、柯里化、构造函数中定义特权方法、Vue中数据响应式Observer 标准回答: 一个函数和词法作用域的引用捆绑在一起,这样的组合就是闭包(closure)。一般就是一个函数A,return其内部的函数B,被return出去的B函数能够在外部访问A函数内部的变量,这时候就形成了一个B函数的变量背包,A函数执行结束后这个变量背包也不会被销毁,并且这个变量背包在A函数外部只能通过B函数访问。 闭包形成的原理:作用域链,当前作用域可以访问上级作用域中的变量 闭包解决的问题:能够让函数作用域中的变量在函数执行结束之后不被销毁,同时也能在函数外部可以访问函数内部的局部变量。 闭包带来的问题:由于垃圾回收器不会将闭包中变量销毁,于是就造成了内存泄露,内存泄露积累多了就容易导致内存溢出。 加分回答: 闭包的应用,能够模仿块级作用域,能够实现柯里化,在构造函数中定义特权方法、Vue中数据响应式Observer中使用闭包等。

4.说一说promise是什么与使用方法? 得分点: pendding、rejected、resolved、微任务、then、catch、Promise.resolve()、Promise.reject()、Promise.all() Promise.any()、Promise.race()

标准回答: Promise的作用:Promise是异步微任务,解决了异步多层嵌套回调的问题,让代码的可读性更高,更容易维护 Promise使用:Promise是ES6提供的一个构造函数,可以使用Promise构造函数new一个实例,Promise构造函数接收一个函数作为参数,这个函数有两个参数,分别是两个函数 resolve和reject resolve将Promise的状态由等待变为成功,将异步操作的结果作为参数传递过去; reject则将状态由等待转变为失败,在异步操作失败时调用,将异步操作报出的错误作为参数传递过去。 实例创建完成后,可以使用then方法分别指定成功或失败的回调函数,也可以使用catch捕获失败,then和catch最终返回的也是一个Promise,所以可以链式调用。

Promise的特点:

对象的状态不受外界影响(Promise对象代表一个异步操作,有三种状态)。 - pending(执行中) - Resolved(成功,又称Fulfilled) - rejected(拒绝) 其中pending为初始状态,fulfilled和rejected为结束状态(结束状态表示promise的生命周期已结束)。 一旦状态改变,就不会再变,任何时候都可以得到这个结果。 Promise对象的状态改变,只有两种可能(状态凝固了,就不会再变了,会一直保持这个结果): - 从Pending变为Resolved - 从Pending变为Rejected resolve 方法的参数是then中回调函数的参数,reject 方法中的参数是catch中的参数 then 方法和 catch方法 只要不报错,返回的都是一个fullfilled状态的promise 加分回答 :Promise的其他方法:

Promise.resolve() :返回的Promise对象状态为fulfilled,并且将该value传递给对应的then方法. Promise.reject():返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法。 Promise.all():返回一个新的promise对象,该promise对象在参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。 Promise.any():接收一个Promise对象的集合,当其中的一个 promise 成功,就返回那个成功的promise的值。 Promise.race():当参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。 5.说一说跨域是什么?如何解决跨域问题? 得分点: 同源限制、协议、域名、端口、CORS、node中间件、JSONP、postmessage

标准回答 跨域:当前页面中的某个接口请求的地址和当前页面的地址如果协议、域名、端口其中有一项不同,就说该接口跨域了。 跨域限制的原因:浏览器为了保证网页的安全,出的同源协议策略。 跨域报错信息:

跨域解决方案 cors:目前最常用的一种解决办法,通过设置后端允许跨域实现。 res.setHeader(‘Access-Control-Allow-Origin’, ‘*’); res.setHeader(“Access-Control-Allow-Methods”, “GET, PUT, OPTIONS,POST”); node中间件、nginx反向代理:跨域限制的时候浏览器不能跨域访问服务器,node中间件和nginx反向代理,都是让请求发给代理服务器,静态页面面和代理服务器是同源的,然后代理服务器再向后端服务器发请求,服务器和服务器之间不存在同源限制。 JSONP:利用的原理是script标签可以跨域请求资源,将回调函数作为参数拼接在url中。后端收到请求,调用该回调函数,并将数据作为参数返回去,注意设置响应头返回文档类型,应该设置成javascript。 postmessage:H5新增API,通过发送和接收API实现跨域通信。 加分回答 跨域场景:前后端分离式开发、调用第三方接口

想了解更多解决方案可以参考: 9种常见的前端跨域解决方案(详解)

6.说一说你是怎么理解BFC的? 得分点: 块级格式化上下文、独立的渲染区域、不会影响边界以外的元素、形成BFC条件、float、position、overflow、display

标准回答: BFC(Block Formatting Context)块级格式化上下文,是Web页面一块独立的渲染区域,内部元素的渲染不会影响边界以外的元素。 BFC布局规则:

内部盒子会在垂直方向,一个接一个地放置。 Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠。 每个盒子(块盒与行盒)的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。 BFC的区域不会与float box重叠。 BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。 计算BFC的高度时,浮动元素也参与计算。 BFC形成的条件:

根元素:body; 元素设置浮动:float 除 none 以外的值; 元素设置绝对定位:position(absolute、fixed); display值为:inline-block、table-cell、table-caption、flex 等; overflow值为:hidden、auto、scroll; BFC解决能的问题:

解决 margin 的重叠问题:由于 BFC 是一个独立的区域,内部的元素和外部的元素互不影响,将两个元素变为两个 BFC,就解决了 margin 重叠的问题。 解决高度塌陷的问题:在对子元素设置浮动后,父元素会发生高度塌陷,也就是父元素的高度变为 0。解决这个问题,只需要把父元素变成一个BFC。常用的办法是给父元素设置overflow:hidden。 创建自适应两栏布局:可以用来创建自适应两栏布局:左边的宽度固定,右边的宽度自适应。 7.说一说Vuex是什么,每个属性是干嘛的,如何使用 ? 得分点: state、mutations、getters、actions、module、store.commit、store.dispatch

标准回答 : Vuex是集中管理项目公共数据的。Vuex 有state、mutations 、getters、actions、module属性。

state 属性用来存储公共管理的数据。 mutations 属性定义改变state中数据的方法, 注意:不要在mutation中的方法中写异步方法ajax,那样数据就不可跟踪了。 getters 属性可以认为是定义 store 的计算属性。就像计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。 action属性类似于mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态。Action 可以包含任意异步操作。 moudle属性是将store分割成模块。每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块,从上至下进行同样方式的分割 使用方法:

state:直接以对象方式添加属性 mutations :通过store.commit调用 action:通过 store.dispatch方法触发 getters:直接通过store.getters.调用 加分回答:可以使用辅助函数mapState、mapMutations、mapAction、mapGetters一次性获取每个属性下对应的多个方法。 VueX在大型项目中比较常用,非关系组件传递数据比较方便。

8.说一说JavaScript有几种方法判断变量的类型? 得分点: typeof、instanceof、Object.prototype.toString.call()(对象原型链判断方法)、 constructor (用于引用数据类型)

标准回答: JavaScript有4种方法判断变量的类型,分别是typeof、instanceof、Object.prototype.toString.call()(对象原型链判断方法)、 constructor (用于引用数据类型) typeof:常用于判断基本数据类型,对于引用数据类型除了function返回’function‘,其余全部返回’object’。 instanceof:主要用于区分引用数据类型,检测方法是检测的类型在当前实例的原型链上,用其检测出来的结果都是true,不太适合用于简单数据类型的检测,检测过程繁琐且对于简单数据类型中的undefined, null, symbol检测不出来。 constructor:用于检测引用数据类型,检测方法是获取实例的构造函数判断和某个类是否相同,如果相同就说明该数据是符合那个数据类型的,这种方法不会把原型链上的其他类也加入进来,避免了原型链的干扰。 Object.prototype.toString.call(): 适用于所有类型的判断检测,检测方法是Object.prototype.toString.call(数据) 返回的是该数据类型的字符串。

这四种判断数据类型的方法中,各种数据类型都能检测且检测精准的就是Object.prototype.toString.call()这种方法。

加分回答 instanceof的实现原理:验证当前类的原型prototype是否会出现在实例的原型链proto上,只要在它的原型链上,则结果都为true。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,找到返回true,未找到返回false。 Object.prototype.toString.call()原理:Object.prototype.toString 表示一个返回对象类型的字符串,call()方法可以改变this的指向,那么把Object.prototype.toString()方法指向不同的数据类型上面,返回不同的结果

  1. 说一说样式优先级的规则是什么? 得分点: !important、行内样式、嵌入样式、外链样式、id选择器、类选择器、标签选择器、复合选择器、通配符、继承样式

标准回答 CSS样式的优先级应该分成五大类

第一类!important,无论引入方式是什么,选择器是什么,它的优先级都是最高的。 第二类引入方式,行内样式的优先级要高于嵌入和外链,嵌入和外链如果使用的选择器相同就看他们在页面中插入的顺序,在后面插入的会覆盖前面的。 第三类选择器,选择器优先级:id选择器>(类选择器 | 伪类选择器 | 属性选择器 )> (后代选择器 | 伪元素选择器 )> (子选择器 | 相邻选择器) > 通配符选择器 。 第四类继承样式,是所有样式中优先级比较低的。 第五类浏览器默认样式优先级最低。 10.说一说Vue2.0 双向绑定的原理与缺陷? 得分点: Object.defineProperty、getter、setter

标准回答: Vue响应式指的是:组件的data发生变化,立刻触发视图的更新 原理: Vue 采用数据劫持结合发布者-订阅者模式的方式来实现数据的响应式,通过Object.defineProperty来劫持数据的setter,getter,在数据变动时发布消息给订阅者,订阅者收到消息后进行相应的处理。 通过原生js提供的监听数据的API,当数据发生变化的时候,在回调函数中修改dom 核心API:Object.defineProperty 作用: 用来定义对象属性 特点: 默认情况下定义的数据的属性不能修改 描述属性和存取属性不能同时使用,使用会报错 响应式原理: 获取属性值会触发getter方法 设置属性值会触发setter方法 在setter方法中调用修改dom的方法 加分回答 Object.defineProperty的缺点 :

一次性递归到底开销很大,如果数据很大,大量的递归导致调用栈溢出 不能监听对象的新增属性和删除属性 无法正确的监听数组的方法,当监听的下标对应的数据发生改变时

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值