⏳昨天面试了一家公司,面试官人很好,而且他还对我的简历提出了一些建议,也帮我解答了一些问题。虽然没能一起工作,但我也不留遗憾。接下来和我一起看一看面试官的问题吧!
首先let
和const
是ES6新增的关键字。
let,var用来声明变量,可以只声明不赋值。
const用来声明常量,const一经过声明就必须赋值。
let,和const都是块级作用域,而var是函数作用域。
let和const没有变量提升功能,而var有变量提升。
最外层的作用域,也就是全局作用域,用var声明的变量,会作为window的一个属性。而用let和const声明的变量或常量并不会作为window的属性。
里面有多个请求,把这些请求发送到网络中是如何发送的,是同时发送的,还是有先后顺序?
闭包就是能够读取其他函数内部变量的函数
闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域
闭包的特性:
使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念
闭包 的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中
闭包的另一个用处,是封装对象的私有属性和私有方法
好处:能够实现封装和缓存等;
坏处:就是消耗内存、不正当使用会造成内存溢出的问题
使用闭包的注意点
我之前写过一个文章JavaScript原型链里面有这部分的内容。
这块我说的是js里的5中继承方法,包括作用域链继承,组合继承,组合寄生式继承,以及extend继承的这几种方法。我之前也写过一篇文章Js面试手写题第二天这块我记性不太好,没全部说出来。
function Father(){
this.name = '父亲'
this.age = 45
};
function Son(){};
Son.prototype = new Father();
function Father(){
this.name = '父亲'
this.age = 45
}
function Son(){
Father.call(this)
}
function Father(){
this.name = '父亲'
this.age = 19
}
function Son(){
Father.call(this,name);
}
Son.prototype = new Father()
Son.prototype.constructor = Son
这里注意实例化了两次father,所以一会提到的组合寄生式方法就出炉了。
function Father(){
this.name = '父亲'
this.age = 45
}
function Son(){
Father.call(this,name);
}
Son.prototype = Object.create(Father.prototype);
Son.prototype.constructor = Son;
class Father{
constructor(){
this.name = 'father'
this.age = 45
}
}
class Son extends Father{
constructor(){
super();
this.color = color;
}
}
我之前写的博客里有在文章末尾有提到
link
是html方式,而@import是Css方式lin
k最大限制支持并行加载,而@import过多嵌套导致串行下载,出现FOUC
(文档样式短暂失效)link
可以通过rel="alternate stylesheet"
指定候选样式link
的支持早于@import
,可以使用@import
对老样式隐藏样式@import
必须在样式规则之前,可以在css文件中引入其他文件link
优于@import
一张图,可以说的很清楚了。
按照原型图开发好固定尺寸后,根据分辨率进行方法和缩小
// 优点:不用考虑适配问题,按设计稿进行固定尺寸开发
function bodyScale() {
var devicewidth = document.documentElement.clientWidth;//获取当前分辨率下的可是区域宽度
var scale = devicewidth / 1366; // 分母——设计稿的尺寸
document.body.style.zoom = scale;//放大缩小相应倍数
}
bodyScale();
根据分别率的宽度,计算当前屏幕的分辨率宽与设计高宽成一定的比例。
Row 组件 提供 gutter
属性来指定每一栏之间的间隔,默认间隔为 0。
svg
绘制出来的每一个图形的元素都是独立的DOM
节点,能够方便的绑定事件或用来修改。canvas
输出的是一整幅画布svg
输出的图形是矢量图形,后期可以修改参数来自由放大缩小,不会失真和锯齿。而canvas
输出标量画布,就像一张图片一样,放大会失真或者锯齿之前基本没有过canvas
做过小作品。
答案是当然可以:根据坐标,根据每个图形在画布上不同的坐标来区分每个图形对应的事件。这就需要大量的判断以及对坐标的精确定位。canvas提供了isPointInPath(x,y)方法来判断坐标是否在当前路径上。
title
、description
、keywords
:搜索对着三项的权重逐个减小,title
值强调重点即可,重要关键词出现不要超过2次,而且要靠前,不同页面title
要有所不同;description
把页面内容高度概括,长度合适,不可过分堆砌关键词,不同页面description
有所不同;keywords
列举出重要关键词即可HTML
代码,符合W3C规范:语义化代码让搜索引擎容易理解网页HTML
代码放在最前:搜索引擎抓取HTML
顺序是从上到下,有的搜索引擎对抓取长度有限制,保证重要内容一定会被抓取js
输出:爬虫不会执行js获取内容iframe
:搜索引擎不会抓取iframe
中的内容alt
初始化就存在区别,vue3.0提供了一种可视化创建脚手架,可以方便的对插件进行管理和配置,同时两个版本的目录结构也有区别。
vue3.0的底层变化还是挺大的
proxy对于Object.defindprotoy的优势:
- definedproty只能监听某个属性,不能对全对象进行监听。
- 可以监听数组,不用再去单独的对数组做特异性操作,可以通过Proxy可以拦截所有对象类型数据的操作。
Object.defineProperty(obj, prop, descriptor)方法,接收三个参数,分别为obj(定义其上属性的对象)prop(定义或修改的属性)descriptor(具体的改变方法),就是用这个方法来定义一个值,当调用时我们使用了它里面的get方法,当我们给这个属性赋值时,又用到了它里面的set方法。
实现Vue双向绑定的原理是采用数据劫持结合发布者订阅者模式的方式,通过Object.definedProperty()来劫持各个属性的setter,getter,在数据变动的时候发布消息给订阅者,触发相应的监听回调,getter函数里面执行的任务是watcher订阅者,而setter函数执行的任务是发布者,双向数据绑定原理的实现就是如下几步。
使用了 es6 的 ProxyAPI 对数据代理,通过 reactive() 函数给每一个对象都包一层 Proxy,通过 Proxy 监听属性的变化,从而实现对数据的监控。
先将img标签中的src的路径设置为同一张图片(空白图片),将真正的图片路径保存在data-src属性中,通过scrollTop方法获取浏览器窗口顶部与文档顶部之间的距离,通过clientHeight方法获取可视区高度。对window.scoll触发时,执行事件载入data-src(对每个images标签DOM来求其offsetTop,如果images距离顶部的高度 >=可视区高度+窗口距离文档顶部的距离 )。
原文链接
通过安装vue-lazyload依赖
=>全局引入vue-lazyload依赖
=>配置依赖
npm install vue-lazyload --save
//main.js 文件
import VueLazyload from 'vue-lazyload' //引入依赖
Vue.use(VueLazyload)
// 配置项
Vue.use(VueLazyload, {
preLoad: 1.3, //表示lazyload的元素,距离页面底部距离的百分比.计算值为(preload - 1),默认值为1.3
error: 'dist/error.png', //加载失败后图片地址
loading: 'dist/loading.gif', //加载时图片地址
attempt: 1 // 图片加载失败后的重试次数,默认值为3
})
CDN的全称是
Content Delivery Network
,即内容分发网络。其通过将站点内容发布至遍布全球的海量加速节点,使其用户可就近获取所需内容,避免因网络拥堵、跨运营商、跨地域、跨境等因素带来的网络不稳定、访问延迟高等问题,有效提升下载速度、降低响应时间,提供流畅的用户体验。 因为CDN的这些特性,我们可以将体积较大的文件或是图片上传到CDN中,通过CDN来加载,减轻了服务器的请求压力,同时也可以通过CDN来获取、加载依赖。
单页面应用我们可以按需加载,路由懒加载优化。
{
path: '/personList', //path路径
name: 'personList', //组件名
component: r => require.ensure([], () => r(require('../components/personList')), 'person') //person类型的组件
},
{
path: '/personOrder',
name: 'personOrder',
component: r => require.ensure([], () => r(require('../components/personOrder')), 'person')//person类型的组件
}
export default new VueRouter({
routes: [
{
path: '/',
component: () => import('../components/Navigator')
}
]
})
这块的内容我竟然不记得,后来找到才发现自己用过。。。。
export default new VueRouter({
routes: [
{
path: '/',
component: () => import('../components/Navigator')
}
]
})
使用路由懒加载的写法,只会在进入当前这个路由时候才会走 component ,然后在运行import编译加载相应的组件。
注意import会返回一个Promise对象,可以链式调用。
vueAdmin
axios拦截器封装,这块下去找项目学一下,的确没怎么用到过。
动态的路由,和角色校验有关,不同不同的角色会获取到不同的路由,根据用户端角色,根据角色获取路径。从数据库中获取到他的path(字符串),路由路径持久化处理。
MVVM
模式是由经典的软件架构 MVC
衍生来的。当 View
(视图层)变化时,会自动更新到 ViewModel
(视图模型),反之亦然。View 和 ViewModel
之间通过双向绑定(data-binding
)建立联系。与 MVC 不同的是,它没有 Controller
层,而是演变为 ViewModel
。ViewModel
通过双向数据绑定把 View
层和 Model
层连接了起来,而 View
和 Model
之间的同步工作是由 Vue.js 完成的,我们不需要手动操作 DOM,只需要维护好数据状态。