admin管理员组文章数量:1570358
一、HTML+CSS基础(16道)
-
display:none; 和visibility:hidden;
display:none; 彻底消失,释放空间。可能引发页面的reflow回流(重排)。 visibility:hidden; 就是隐藏,但是位置没释放,好比opacity:0; 不引发页面回流。
-
你做的页面在哪些浏览器内核中测试过
1、IE浏览器内核:Trident内核,也是俗称的IE内核;
2、Chrome浏览器内核:统称为Chromium内核或Chrome内核,以前是Webkit内核,现在是Blink内核;
3、Firefox浏览器内核:Gecko内核,俗称Firefox内核;
4、Safari浏览器内核:Webkit内核;
5、Opera浏览器内核:最初是自己的Presto内核,后来是Webkit,现在是Blink内核;
6、360浏览器、猎豹浏览器内核:IE+Chrome双内核;
7、搜狗、遨游、QQ浏览器内核:Trident(兼容模式)+Webkit(高速模式);8、百度浏览器、世界之窗内核:IE内核;
9、2345浏览器内核:以前是IE内核,现在也是IE+Chrome双内核; -
CSS 选择器权重如何计算
就近原则:直接选中的,一定比继承的权重大。
一样近,比权重:id是100,class是10,标签是1,总数权重一样谁写在下面听谁的。
行内 > 内嵌 = 外联 > 导入
!important能够提升权限,但是不能提升继承的
class=“a b c” 和挂载顺序无关,看写的顺序 -
web 前端开发,如何提高页面性能优化
数据懒加载:不显示的东西不加载,需要显示了才加载。小图标用精灵图,合并成一张
字库用gb2312不要utf-8,一个汉字少一个字节。
图片用base64
路由懒加载、组件不用不加载
使用gulp、grunt、webpack等工具压缩html、js、css代码 -
什么叫优雅降级和渐进渐强
优雅降级和渐进渐强 是浏览器兼容的两种方案。
优雅降级:
能力检测,如果能力有用新的;如果能力没有,用旧的。
渐进渐强:
低端浏览器仅实现基本功能,高级浏览器实现额外功能。
比如上传文件,低端浏览器就给它提供上传按钮,高端浏览器增加外部拖拽文件上传。 -
如何形成 BFC
BFC是块级格式化上下文。
理论上讲,页面上所有的盒子必须都装到BFC盒子中,页面渲染才快。BFC的形成:
① 有明确宽度、高度的盒子。
② overflow:hidden;
③ 定位的、浮动的
④ display :inline-block,
BFC的性质:
内部有浮动,能清除这些浮动,能为浮动元素撑高。 -
CSS 的盒模型
标准盒模型:box-sizing:content-box;由content+padding+border组成怪异盒模型:box-sizing:border-box;有content组成
-
如何垂直水平居中一个元素
.box{
display:flex;
justify‐content: center;
align‐items: center;
}
- css实现一个三角形
.box{
width:0;
height:0;
border:100px solid transparent;
border‐left‐color: red;
}
- 左边100px固定宽,右边自适应布局
.left{
float: left;
width: 100px;
}
.right{
margin‐left: 100px;
}
- 如何实现6px大小的字
font‐size:12px;
transform: scale(.5)
-
移动端1px边框问题
1、使用宽高加背景色
2、使用box-shadow
3、使用border-image -
对单位px、em、rem、vh、vw的理解
px物理像素,绝对值;em相对于父级的大小,相对值;rem相对于html的大小,相对值;vh相对于屏幕的高度,相对值;vw相对于屏幕的宽度,相对值
-
如何减少重绘和回流
通过className或cssText一次性修改样式, 而非一个一个改
离线模式: 克隆要操作的结点, 操作后再与原始结点交换, 类似于虚拟DOM 避免频繁直接访问计算后的样式, 而是先将信息保存下来
绝对布局的DOM, 不会造成大量reflow
div不要嵌套太深, 不要超过六层 -
css Hack
由于不同厂商的流览器或某浏览器的不同版本(如IE6
IE11,Firefox/Safari/Opera/Chrome等),对CSS的支持、解析不一样,导致在不同浏览器 的环境中呈现出不一致的页面展现效果。这时,我们为了获得统一的页面效果,就需要针对不同的浏览器或不同版本写特定的CSS样式,我们把这个针对不同的浏览器/不同版本写相应的CSS code的过程,叫做CSS hack!
CSS Hack大致有3种表现形式:CSS属性前缀法、选择器前缀法以及IE条件注释法
(即HTML头部引用if IE)Hack,实际项目中CSS Hack大部分是针对IE浏览器不同版本之 间的表现差异而引入的。
.lte IE 7{*property:value;}
.IE 7{+property:value;}
.IE 6{_property:value;}
html .class{}
+html .class{}
<!‐‐[if IE]>IE浏览器显示的内容 <![endif]‐‐>
-
谈谈你对html5的理解
html5是一个规范,标签更具有语义化,如(header、footer、nav、section、article 等),css3新增加了很多新特性,使得页面更美观(boxshadow、gradient、text
shadow、opacity等),动画过渡等新特性更节约页面性能(animation、transition、
transform、keyframes),JavaScript还提供了大量api,例如本地存储storage、离线缓存 application cache、地理定位geolocation、即时会话websocket、文件预览fileReader等。
二、JavaScript基础(18道)
-
call、apply和bind的区别?
这三个都是用来定义上下文的,call、apply会指定上下文并执行函数;而bind终身定死上下文但是不执行函数,并返回新的函数。
其中call和apply传入参数的形式有别,call是单独罗列,逗号隔开参数;apply是数 组。
函数.call(上下文对象,参数,参数,参数);
函数.apply(上下文对象,[参数,参数,参数]);
var obj = {
a: 10
}
function fun(b, c){
console.log(this.a + b + c);
}
fun.call(obj, 3, 4);
fun.apply(obj, [3, 4]);
fun = fun.bind(obj); // 返回新的函数
fun(3,4);
-
深浅克隆
浅克隆就是表层克隆,就是用for var k in或者for循环复制对象、数组的一层。如果它的某个属性值又是引用类型值,则仍然是内存中的同一个对象。
var obj = {a: 1, b: 2, c: [33,44,55]};
var mmm = {};
for(var k in obj){
mmm[k] = obj[k];
}
obj.c.push(666);
console.log(mmm);
//或者
var arr2 = [...arr1];
//或者
var obj2 = Object.assign({}, obj1);
深克隆,需要递归:
const deepclone = (o) => {
if(Array.isArray(o)){
var arr = [];
o.forEach(item => {
arr.push(deepclone(item));
});
return arr;
}else if(typeof o === "object"){
var oo = {};
for(var k in obj){
oo[k] = deepclone(obj[k]);
}
return oo;
}
return o;
}
//简单版
JSON.parse(JSON.stringify(object))
-
给数组拓展功能,去掉重复项
拓展功能就是内置构造函数的prototype。里面的this就是调用这个函数的数组、字符串。
// 第一种 利用set
Array.prototype.uniq = function(){
return [...new Set(this)];
};
// 第二种 利用splice
Array.prototype.uniq = function(){
for(var i=0; i<this.length; i++){
for(var j=i+1; j<this.length; j++){
if(this[i]==this[j]){ //第一个等同于第二个,splice方法删除第二个
this.splice(j,1);
j‐‐;
}
}
}
return this;
};
// 第三种 利用indexOf
Array.prototype.uniq = function(){
var array = [];
for (var i = 0; i < this.length; i++) {
if (array.indexOf(this[i]) === ‐1) {
array.push(this[i])
}
}
return array;
};
// 第四种 利用filter
Array.prototype.uniq = function(){
return this.filter(function(item, index, arr) {
//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
return this.indexOf(item, 0) === index;
});
};
-
什么是闭包?用途?
闭包就是函数能够记忆住当初定义时候的作用域,不管函数到哪里执行了,永远都能够记住那个作用域,并且会遮蔽新作用域的变量。可预测状态容器;实现模块化,实现变量的私有封装;可以实现迭代器。
闭包缺点:1.闭包有一个非常严重的问题,那就是内存浪费问题,这个内存浪费不仅仅因为它常驻内存,更重要的是,对闭包的使用不当的话会造成无效内存的产生;2.性能问题 使用闭包时,会涉及到跨作用域访问,每次访问都会导致性能损失。
因此在脚本中,最好小心使用闭包,它同时会涉及到内存和速度问题。不过我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响。
function ooo(){
var a = 0;
return fun(){
a++;
console.log(a);
}
}
- 如何实现继承?
// 原型链继承
function Person(){
this.name = 'xiaopao';
}
Person.prototype.getName = function(){
console.log(this.name);
}
function Child(){}
Child.prototype = new Person();
/*
缺点:
引用类型的属性被所有实例共享
在创建Child 的实例时, 不能向Person传参
*/
//借用构造函数继承(经典继承)
function Person(){
this.name = 'xiaopao';
this.colors = ['red', 'blue', 'green'];
}
Person.prototype.getName = function(){
console.log(this.name);
}
function Child(){
Person.call(this);
}
/*
优点:
1.避免了引用类型的属性被所有实例共享
2.可以在Child中向Parent传参
缺点:
1.只是子类的实例,不是父类的实例
2.方法都在构造函数中定义,每次创建实例都会创建一遍方法
*/
// 组合继承
// 组合 原型链继承 和 借用构造函数继承
// 背后的思路是:使用原型链实现对原型方法的继承,而通过借用构造函数来实现对实例 属性的继承。
function Parent(name){
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function(){
console.log(this.name);
}
function Child(name,age){
Parent.call(this,name);// 第二次调用 Parent()
this.age = age;
}
Child.prototype = new Parent(); // 第一次调用 Parent()
/*
优点:融合原型链继承和构造函数的优点,是JavaScript中最常用的继承模式
缺点:调用了两次父类构造函数
(组合继承最大的问题是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子 类型原型的时候,另一次是在子类型构造函数内部)
*/
// 原型式继承
function CreateObj(o){
function F(){}
F.prototype = o;
return new F();
}
var person = {
name: 'xiaopao',
friend: ['daisy','kelly']
}
var person1 = CreateObj(person);
// 缺点: 包含引用类型的属性值始终都会共享相应的值, 这点跟原型链继承一样
// 寄生式继承 可以理解为在原型式继承的基础上增加一些函数或属性
var ob = {
name: 'xiaopao',
friends: ['lulu','huahua']
}
function CreateObj(o){
function F(){}; // 创建一个构造函数F
F.prototype = o;
return new F();
}
// 上面CreateObj函数 在ECMAScript5 有了一新的规范写法,Object.create(ob) 效 果是一样的 , 看下面代码
var ob1 = CreateObj(ob);
var ob2 = Object.create(ob);
console.log(ob1.name); // xiaopao
console.log(ob2.name); // xiaopao
function CreateOb(o){
var newob = CreateObj(o); // 创建对象 或者用 var newob = Object.create(o b)
newob.sayName = function(){ // 增强对象
console.log(this.name);
}
return newob; // 指定对象
}
var p1 = CreateOb(ob);
p1.sayName(); // xiaopao
// 缺点:跟借用构造函数一样,每次创建对象都会创建一遍方法
// 寄生组合式继承
function Parent(name){
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.sayName = function(){
console.log(this.name);
}
function Child(name,age){
Parent.call(this,name);
this.age = age;
}
function CreateObj(o){
function F(){};
F.prototype = o;
return new F();
}
// Child.prototype = new Parent(); // 这里换成下面
function prototype(child,parent){
var prototype = CreateObj(parent.prototype);
prototype.constructor = child;
child.prototype = prototype;
}
prototype(Child,Parent);
var child1 = new Child('xiaopao', 18);
console.log(child1);
/*
优点: 这种方式的高效率体现它只调用了一次Parent构造函数,并且因此避免了再Parent.prototype上面创建不必要的,多余的属性。普遍认为寄生组合式继承是引用类型最理想的继承方式
*/
// es6 继承
class Child extends Parent{}
-
cookie、sessionStorage和localStorage的区别
-
ajax原理
1.创建XMLHttpRequest对象。
2.设置请求方式。open()
3.调用回调函数。onreadystatechange 4.发送请求。send() -
跨域和跨域的方法
跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。其 实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。同源策
略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR 等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地 址,也非同源。
方法1:跨域资源共享CORS跨域,就是服务端在HTTP返回头上加上“Access-Controll-Allow-Origin:*”。
“Access-Controll-Allow-METHODS:GET, POST”
DELETE、PATCH请求类型会发出OPTIONS预检请求。
方法2:代理跨域,webpack-dev-server里面的proxy配置项。config中的ProxyTable
方法3:JSONP,利用页面srcipt没有跨域限制的漏洞,用script的src引入它,然后页 面内定义回调函数,jQuery中$.ajax({dataType: JSONP})。
方法4: iframe跨域,配合window.name或者 location.hash或者document.domain 一起使用
方法5:nginx反向代理接口跨域,通过nginx配置一个代理服务器(域名与domain1 相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中
domain信息,方便当前域cookie写入,实现跨域登录 -
GET请求和POST请求的区别
GET在浏览器回退时是无害的,而POST会再次提交请求。
GET产生的URL地址可以被Bookmark,而POST不可以。
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求在URL中传送的参数是有长度限制的,而POST么有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。 GET参数通过URL传递,POST放在Request body中。 -
事件冒泡、事件捕获和事件委托
事件冒泡会从当前触发的事件目标一级一级往上传递,依次触发,直到document为
止。事件捕获会从document开始触发,一级一级往下传递,依次触发,直到真正事件目标为止。事件委托,通过监听一个父元素,来给不同的子元素绑定事件,减少监听次数,从而提升速度。 -
判断数据类型的方法
typeof检查基本类型:number、string、undefined、boolean,和function instanceof检查引用类型:array、object
判断null可以用===
万能方法:Object.prototype.toString.call(obj) === “[object 数据类型]” -
内存污染、内存泄漏、内存溢出的理解
内存泄露:一个变量如果不用了,会被程序自动回收。内存泄露:垃圾回收不了这个东西了,就是内存泄露。内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存。
内存溢出:系统会给每个对象分配内存也就是Heap size值,当对象所需要的内存大于了系统分配的内存,就会造成内存溢出
内存污染:变量命名产生冲突 -
怎样添加、移除、移动、复制、创建和查找节点
createElement 创建
appendChild末尾添加、insertBefore 前边插入
cloneNode(true) 克隆
removeChild() 移除
document.getElementById()
document.getElementsByTagName()
document.getElementsByClassName()document.getElementsByName()
document.querySelector()
document.querySelectorAll()
parentNode; // 父节点
childNodes; // 全部子节点
firstChild; // 第一个子节点
lastChile; // 最后一个子节点
previousSibling; // 上一个兄弟节点
nextSibling; // 下一个兄弟节点 -
谈谈垃圾回收机制
一般来说没有被引用的对象就是垃圾,就是要被清除, 有个例外如果几个对象引用形 成一个环,互相引用,但根访问不到它们,这几个对象也是垃圾,也要被清除。
垃圾回收的方法主要有两种:一种是标记清除,即用完之后的变量 赋值成null,另一种是引用计数,将使用完的对象的引用计数,如果为0则回收 -
AMD、CMD、ES6、CommonJS的区别
CommonJS:模块引用(require) 模块输出(exports) 模块标识(module)ES6:模块引用(import) 模块输出(export)
前者支持动态导入,也就是 require(${path}/xx.js),后者目前不支持。
前者是同步导入,因为用于服务端,文件都在本地,同步导入即使卡住主线程影响也不大。而后者是异步导入,因为用于浏览器,需要下载文件,如果也采用同步导入会对渲染有很大影响。
前者在导出时都是值拷贝,就算导出的值变了,导入的值也不会改变,所以如果想更新值,必须重新导入一次。但是后者采用实时绑定的方式,导入导出的值都 指向同一个内存地址,所以导入值会跟随导出值变化
AMD、CMD都使用define定义模块,require引入模块,区别在于AMD是前置依赖,CMD是就近依赖 -
构造函数中new操作符都做了什么
∙ 构造函数中没有显示的创建Object对象, 实际上后台自动创建了一个空对象
∙ 直接给this对象赋值属性和方法, this即指向创建的对象
∙ 没有return返回值, 后台自动返回了该对象
∙ 该对象继承构造函数的原型
// 模拟构造函数实现
var Book = function(name) {
this.name = name;
};
//正常用法
var java = new Book('Master Java');
//使用代码模拟,在非IE浏览器中测试,IE浏览器不支持
var python = {};
python.__proto__ = Book.prototype;
Book.call(python, 'Master Python');
-
event对象 - 两个常用方法、2个属性
event.stopPropagation() 阻止事件继续传播(问你应用场景,你就说悬浮层)
event.preventDefault() 阻止默认事件(问你应用场景,a标签阻止默认刷新页面,拖拽到页面的时候阻止浏览器默认的打开这个文件的默认事件)
这两个方法不兼容,一些浏览器中:
event.cancelBubbel = true; 阻止事件继续传播event.returnValue = false; 阻止默认事件
event.target //触发事件的最内层元素
event.keyCode //键盘,13回车,37左按钮
event.target属性不兼容,一些浏览器中:
event.srcElement //触发事件的最内层元素
三、ES6新特性(5道)
-
var、let、const区别
var声明变量存在变量提升,let和const不存在变量提升
let、const都是块级局部变量
const 的特性和 let 完全一样,不同的只是const声明时候必须赋值,赋值基本类型时只能进行一次赋值,即声明后不能再修改,赋值引用类型时,内存地址不能修改
同一作用域下let和const不能声明同名变量,而var可以 -
对Promise的理解
Promise是ES6新增的处理异步的东西,叫做“承诺”。
Promise的实例有三种状态:pending(进行中)、resolved(成功)、rejected(失败)
Promise对象有then方法,用来做resolved的事情。有catch方法,用来做rejected的事情。
Promise.all() 可以等所有请求都成功了在执行 Promise.race() 可以竞速执行请求
Promise解决了回调地狱的问题 -
箭头函数和普通函数的区别
1)箭头函数的this是定义时决定的,普通函数是看调用方法。2)箭头函数不能成为构造函数
3)箭头函数不能使用async/await
4)箭头函数不能加星 -
async和await的理解
Generator函数的语法糖,将*改成async,将yield换成await。
是对Generator函数的改进, 返回promise。
异步写法同步化,遇到await先返回,执行完异步再执行接下来的.内置执行器, 无需next() -
for in 和 for of区别
for in遍历数组会遍历到数组原型上的属性和方法, 更适合遍历对象 ∙ 使用for of可以成功遍历数组的值, 而不是索引, 不会遍历原型
四、Vue面试题(22道)
-
vue 生命周期
beforeCreate创建之前;无法获取响应数据
created创建之后
beforeMount挂载前
mounted挂载后
beforeUpdate数据更新之前
updated数据更新完成之后
beforeDestroy销毁之前
destroyed销毁之后
例如:
beforecreate : 可以在这加个loading事件
created :在这结束loading,还做一些初始数据的获取,实现函数自执行 mounted : 在这发起后端请求,拿回数据,配合路由钩子做一些事情
beforeDestroy: 你确认删除XX吗?
destroyed :当前组件已被删除,清空相关内容 -
vue组件传值方法
父传子:props
子传父: e m i t 同 级 传 : 子 传 给 公 有 的 父 级 , 再 由 父 级 传 给 其 它 组 件 , 或 者 e v e n t B u s , 通 过 实 例 化 一 个 v u e , 然 后 emit 同级传:子传给公有的父级,再由父级传给其它组件,或者eventBus,通过实例化一个vue,然后 emit同级传:子传给公有的父级,再由父级传给其它组件,或者eventBus,通过实例化一个vue,然后on、$emit进行传递
层级较多时:vuex -
vue页面通信方法
1、search传参 <router-link to="/地址?属性名=属性值"></router-link>
this.$route.query.属性名
2、动态路由 path:"/地址/变量名" <router-link to="/地址/数据值"></router-link>
this.$route.params.变量名
3、本地存储 setItem() getItem()
-
$set怎么用— 用来干嘛
如果在实例创建之后添加新的属性到实例上,它不会触发视图更新,这时可以使用$set 来强制更新视图
-
Vue中常用的修饰符有哪些?并简要说明它们的作用
Stop:阻止冒泡; prevent:阻止默认事件; once:只执行一次; capture:将事件流设为捕获方式; self:直对自身触发事件; enter:回车键;Up:上; down:下;left:左;right:右;
-
简要说明你对MVVM的理解
MVVM 是 Model-View-ViewModel 的缩写。 Model代表数据模型,也可以在
Model中定义数据修改和操作的业务逻辑。 View 代表UI 组件,它负责将数据模型转化成UI 展现出来。 ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步View 和 Model的对象,连接Model和View。 在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。 ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起 来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关 注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。 -
Watch和computed的区别
Watch只能监听data中的数据变化,computed不需要,watch可以进行异步操作,
computed不可以,computed不修改原始数据,通过return返回处理的数据,可以包含大量的逻辑运算 -
vue-router 基本使用步骤
第1步:引入vue.js 再引入vue‐router.js、 vue‐router需要引入在vue之后
<script src="vue.js"></script>
<script src="vue‐router.js"></script>
第2步:设置路由组件
let 组件配置变量 ={
template:"#模板id",
data(){
return{}
}
}
第3步:建立映射关系
let routes = [{
path:"/地址",
component:组件配置变量
}]
第4步:实例化路由对象
let router = new VueRouter({
routes,
linkActiveClass:"active",
mode:"hash/history"
})
第5步:挂载到Vue实例
new Vue({
el:"",
data:{},
router
})
第6步:书写router‐view
<div id="app">
<router‐view/>
</div>
第7步:使用router‐link 进行跳转
<router‐link to="/地址">
- 在Vue中使用axios时如何解决跨域问题
在config文件夹中的index.js中的Dev中填写
ProxyTable:{
'/api':{
Target:’代理服务器的目标地址’,
changeOrigin: true,
PathRewrite: {“^/api”:” ”}
}
}
- vue双向绑定原理
// vue2.0
Object.defineProperty(obj, key, {
// oldValue 需要执行时传递进来
set(newValue){
if(newValue === oldValue) return false;
oldValue = newValue;
// do something => notify();
},
get(){
return oldValue;
}
})
// vue3.0
var obj = new Proxy(obj, {
set: function (target, key, newVal, receive) {
if(newVal === target[key]) return false;
target[key] = newVal;
// do something => notify();
},
// target就是第一个参数obj, receive就是返回的obj(返回的proxy对象)
get: function (target, key, receive) {
// 返回该属性值
return target[key];
}
})
- Vue的动态路由
{
path: '/order/:id'
component: Order
}
组件中this.$route.params.id
-
v-if、v-show的区别
- v-show 只是简单的控制元素的 display 属性,而 v-if 才是条件渲染(条件为真,元 素将会被渲染,条件为假,元素会被销毁);
- v-show 有更高的首次渲染开销,而 v-if 的首次渲染开销要小的多;
- v-if 有更高的切换开销,v-show 切换开销小;
- v-if 有配套的 v-else-if 和 v-else,而 v-show 没有
- v-if 可以搭配 template 使用,而 v-show 不行
-
key的作用
key是为每个vnode指定唯一的id,在同级vnode的Diff过程中,可以根据key快速的进 行对比,来判断是否为相同节点,
利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快,指定key后,可以保证渲染的准确性(尽可能的复用 DOM 元素。) -
vue 单页面应用及其优缺点
答:优点:Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件,核心是一个响应的数据绑定系统。MVVM、数据驱动、组件化、轻量、简洁、高效、快速、模块友好。
只关心数据,不关心DOM。插件众多。维护状态方便。
缺点:不支持低版本的浏览器,最低只支持到IE9;不利于SEO的优化(如果要支持
SEO,建议通过服务端来进行渲染组件);第一次加载首页耗时相对长一些;不可以使用浏 览器的导航按钮需要自行实现前进、后退。 -
vue服务端渲染SSR的理解
更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。更快的内容到达时间,特别是对于缓慢的网络情况或运行缓慢的设备。通常 可以产生更好的用户体验。
开发条件所限。浏览器特定的代码,只能在某些生命周期钩子函数中使用;一些外部扩展库可能需要特殊处理,才能在服务器渲染应用程序中运行。
涉及构建设置和部署的更多要求。与可以部署在任何静态文件服务器上的完全静态单页面应用程序 (SPA) 不同,服务器渲染应用程序,需要处于 Node.js server 运行环境
更多的服务器端负载 -
Vue 开发中如何使用全局状态常量?你都用这个状态常量做什么
事情
比如最常见的全局状态常量就是process.env.NODE_ENV 它的值可能是:production、development
就是webpack.config.js中的mode。
{
mode: "",
entry: {},
output: {}
}
// 比如现在是开发模式,我就显示一个某某功能按钮。
<button v‐if="process.env.NODE_ENV === 'develpment'">
测试按钮
</button>
npm run serve 的时候看的见这个按钮
npm run build 的时候看不见这个按钮
- 为什么路由懒加载,如何路由懒加载
为给客户更好的客户体验,首屏组件加载速度更快一些,解决白屏问题。
可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,
减少首页加载用时。
const Foo = () => import('./Foo.vue')
-
hash路由和history路由的区别
1.hash路由在地址栏URL上有#,而history路由没有会好看一点
2.我们进行回车刷新操作,hash路由会加载到地址栏对应的页面,而history路由一般就404报错了(刷新是网络请求,没有后端准备时会报错)。
3.hash路由支持低版本的浏览器,而history路由是HTML5新增的API。
4.hash的特点在于它虽然出现在了URL中,但是不包括在http请求中,所以对于后端是没有一点影响的,所以改变hash不会重新加载页面,所以这也是单页面应用的必备。
5.history运用了浏览器的历史记录栈,之前有back,forward,go方法,之后在HTML5 中新增了pushState()和replaceState()方法(需要特定浏览器的支持),它们提供了对历史记录进行修改的功能,不过在进行修改时,虽然改变了当前的URL,但是浏览器不会马上向后端发送请求。 -
Vue-Router 中的标签和标签有什么区别
用跳转,能够记录到历史记录中,使用this.$router.back();而标签不记录到历史记录中。
并且router-link的to能够用name跳转,能够写params参数,特别方便。 -
vue深监听
watch中的deep属性设置true
-
r o u t e r 和 router和 router和route的区别
this. r o u t e r . p u s h ( n a m e : ′ ′ , p a r a m s : ′ ′ ) n a m e 和 p a r a m s 是 什 么 意 思 router.push({name:'',params:''})name和params是什么意思 router.push(name:′′,params:′′)name和params是什么意思router路由跳转, $route路由信息
name是路由名字,params是要传递的参数 -
vue中导航守卫都有哪些,都有什么参数
router.beforeEach、router.afterEach、beforeEnter、beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave
to:这是你要跳去的路由对象。
from:这是你要离开的路由对象。
next:是一个方法,它接受参数。这个方法必须调用要不就跳不过去了,你可以把它看做保安。必须给它打个招呼,要不然不让你过。
五、小程序面试题(5道)
-
简单描述下微信小程序的相关文件类型
微信小程序项目结构主要有四个文件类型
WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。内部主要是微信自己定义的一套组件
WXSS (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式
js 逻辑处理,网络请求
json 小程序设置,如页面注册,页面标题及tabBar
主要文件
app.json 必须要有这个文件,如果没有这个文件,项目无法运行,因为微信框架把这 个作为配置文件入口,整个小程序的全局配置。包括页面注册,网络设置,以及小程序的 window 背景色,配置导航条样式,配置默认标题,底部导航等
app.js 必须要有这个文件,没有也是会报错!但是这个文件创建一下就行 什么都不需要写以后我们可以在这个文件中监听并处理小程序的生命周期函数、声明全局变量
app.wxss 可选,全局样式 -
简述微信小程序原理
微信小程序采用 JavaScript、WXML、WXSS 三种技术进行开发,本质就是一个单页面 应用,所有的页面渲染和事件处理,都在一个页面内进行,但又可以通过微信客户端调用原生的各种接口微信的架构,是数据驱动的架构模式,它的 UI 和数据是分离的,所有的页面 更新,都需要通过对数据的更改来实现
小程序分为两个部分 webview 和 appService 。其中 webview 主要用来展现 UI ,appService 有来处理业务逻辑、数据及接口调用。它们在两个进程中运行,通过系统层 JSBridge 实现通信,实现 UI 的渲染、事件的处理 -
小程序的双向绑定和vue哪里不一样
小程序直接 this.data 的属性是不可以同步到视图的,必须调用:this.setData({
// 这里设置
}) -
小程序页面间有哪些传递数据的方法
1、使用全局变量实现数据传递,在 app.js 文件中定义全局变量 globalData, 将需要存 储的信息存放在里面
2、使用 wx.navigateTo 与 wx.redirectTo 的时候,可以将部分数据放在 url 里面,并 在新页面 onLoad 的时候接收
3、使用本地缓存 Storage -
小程序的生命周期函数
onLoad 页面加载时触发。一个页面只会调用一次,可以在 onLoad 的参数中获取打 开当前页面路径中的参数
onShow() 页面显示/切入前台时触发
onReady() 页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互
onHide() 页面隐藏/切入后台时触发。 如 navigateTo 或底部 tab 切换到其他页面,小程序切入后台等
onUnload() 页面卸载时触发。如 redirectTo 或 navigateBack 到其他页面时
六、编程题(27道)
- 手写promise
function myPromise(constructor) {
let self = this;
self.status = "pending"; //定义状态改变前的初始状态
self.value = undefined; //定义状态为resolved的时候的状态
self.reason = undefined; //定义状态为rejected的时候的状态
function resolve(value) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.value = value;
self.status = "resolved";
}
}
function reject(reason) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.reason = reason;
self.status = "rejected";
}
}
//捕获构造异常
try {
constructor(resolve, reject);
} catch (e) {
reject(e);
}
}
// 定义链式调用的then方法
myPromise.prototype.then = function (onFullfilled, onRejected) {
let self = this;
switch (self.status) {
case "resolved":
onFullfilled(self.value);
break;
case "rejected":
onRejected(self.reason);
break;
default:
}
};
- 封装ajax
function ajax(options){
options = options ||{}; //调用函数时如果options没有指定,就给它赋值{},一个空 的Object
options.type=(options.type || "GET").toUpperCase();/// 请求格式GET、POS T,默认为GET
options.dataType=options.dataType || "json"; //响应数据格式,默认json
var params=formatParams(options.data);//options.data请求的数据
var xhr;
//考虑兼容性
if(window.XMLHttpRequest){
xhr=new XMLHttpRequest();
}else if(window.ActiveObject){//兼容IE6以下版本
xhr=new ActiveXobject('Microsoft.XMLHTTP');
}
//启动并发送一个请求
if(options.type=="GET"){
xhr.open("GET",options.url+"?"+params,true);
xhr.send();
}else if(options.type=="POST"){
xhr.open("post",options.url,true);
//设置表单提交时的内容类型
//Content‐type数据请求的格式
xhr.setRequestHeader("Content‐type","application/x‐www‐form‐urlencoded");
xhr.send(params);
}
// 设置有效时间
setTimeout(function(){
if(xhr.readySate!=4){
xhr.abort();
}
},options.timeout)
// 接收
// options.success成功之后的回调函数 options.error失败后的回调函数
//xhr.responseText,xhr.responseXML 获得字符串形式的响应数据或者XML形式的响应数据
xhr.onreadystatechange=function(){
if(xhr.readyState==4){
var status=xhr.status;
if(status>=200&& status<300 || status==304){
options.success&&options.success(xhr.responseText,xhr.responseXML);
}else{
options.error&&options.error(status);
}
}
}
}
//格式化请求参数
function formatParams(data){
var arr=[];
for(var name in data){
arr.push(encodeURIComponent(name)+"="+encodeURIComponent(data[name]));
}
arr.push(("v="+Math.random()).replace(".",""));
return arr.join("&");
}
版权声明:本文标题:前端常见面试题 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dongtai/1727191888a1101516.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论