前端面试题分享

前端基础:

1.讲讲对web标准以及w3c的理解与认识

web能够简单分为:结构、表现、行为。三部分独立开来使其模块化
w3c是对web作出规范,使代码更严谨,作出来的网页更易使用,维护。

w3c作出的规范可分为以下:
结构上:(标签规范对页面的搜索权重有很大关系,写的越规范网站在搜索排名越靠前)javascript

  •   标签闭合、标签小写、不乱嵌套

表现、行为上:php

  •  使用外链的css和js脚本,提升页面渲染效率。
  •   少使用行内样式,类名要作到见名知意

2.说明ajax请求的时候post和get的区别

发送机制css

一、get请求会将参数跟在URL后面进行参数传递,而post请求则是做为http消息的实体内容发送给web服务器;
二、get提交的数据限制是1024字节,这种显示是来自特定浏览器和服务器对它的限制。如ie的URL长度限制是2083字节,火狐理论上没有长度限制。注意这个限制是URL 的整个长度,而不是参数的长度。
三、get方式请求的数据会被浏览器缓存起来。由于其余人能够从浏览器的历史记录中读取到这些数据,好比:帐号或者密码等。在某种状况下,get方式会带来严重的安全问题,而post相对来讲能够避免这些问题。html

在服务端的区别前端

一、客户端请求使用get时,服务端使用Request.QueryString来获取,而客户端使用post请求时,服务端使用Request.Form来获取。
二、post用于建立资源,资源的内容会被编入http请示的内容中,例如,处理定货表单等。
三、当请求无反作用时(如进行搜索),使用get方法,当请求有反作用时(如添加数据),则用post方法。vue

3.如何对网站的文件和资源进行优化,主流的解决方案包括哪些?

1. 文件合并
2. 文件最小化/文件压缩
3. 使用 CDN 托管
4. 缓存的使用(多个域名来提供缓存)
5. 其余java

4.闭包是什么?有什么特性?对页面有什么影响?

“官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(一般是一个函数),于是这些变量也是该表达式的一部分。webpack

通俗的讲:就是函数a的内部函数b,被函数a外部的一个变量引用的时候,就建立了一个闭包。web

闭包的特性:面试

①.封闭性:外界没法访问闭包内部的数据,若是在闭包内声明变量,外界是没法访问的,除非闭包主动向外界提供访问接口;
②.持久性:通常的函数,调用完毕以后,系统自动注销函数,而对于闭包来讲,在外部函数被调用以后,闭包结构依然保存在
系统中,闭包中的数据依然存在,从而实现对数据的持久使用。

优势:

① 减小全局变量。

② 减小传递函数的参数量

③ 封装;

   缺点:
 使用闭包会占有内存资源,过多的使用闭包会致使内存溢出等.

5.https页面下直接请求http会遇到什么问题?

在https页面下的带有相对路径的请求都会与页面的协议保持一致。若是想在https页面下发送http的请求,若是只把连接写死成为http的绝对路径是不够的,这样会致使http的请求与总页面https的请求的session不一致。

为何呢?缘由是https的请求中服务器发回的cookie是标记为"secure"的,而http的请求时非"secure","因为在服务器端secure"的cookie不会兼容非"secure"的,因此当http的请求携带着同一jsessionid的cookie到达服务器时,服务器拒绝非"secure",进而返回的结果是一个新的非"secure"的cookie,因而两个session就不一样了。

 怎么解决呢?由缘由分析可知,两个session不一样,更具体说是cookie的状态不一样。那么办法是,在接收到第一个https请求的响应后 到 发送下面的http请求以前,将cookie去"secure"状态,可是又要保证jsessionid不变。具体操做能够新建一个cookie(新建的是非"secure"状态),而后赋予同一个jessionid,而后加入response中。

6.js继承的方式及其优缺点

推荐文章:传送门

人家讲得已经很清楚了,案例跟优缺点都整理出来了,推荐阅读

7.解释ajax的工做原理

一、建立ajax对象(XMLHttpRequest/ActiveXObject(Microsoft.XMLHttp))

二、打开连接 open(请求方式,'请求路径',同步/异步)

三、发送 send()

四、当ajax对象完成第四步(onreadystatechange)数据接收完成,判断对象状态码(readystate) 4  HTTP响应彻底接收  在判断http响应状态(status)200-300之间或者304(缓存)执行回调函数 获取的数据转成字符串格式(responseText)

具体代码参考网上...

JS部分:

1.打印如下执行结果

console.log('script start');
setTimeout(() => {
    console.log('setTimeout');
},0)
Promise.resolve().then(function() {
    console.log('promise1');
}).then(function() {
    console.log('promise2');
});
console.log('script end')

考察的是代码执行顺序问题,定时器和主程序属于宏任务,Promise中then的回调属于微任务,在每一个宏任务里面都会先执行完微任务再去执行下一个宏任务。
本题执行逻辑应该是主线程中console.log('script start');碰到定时器,把这个宏任务扔事件队列里面,继续向下,碰到Promise.then异步任务,继续扔队列里面,执行console.log('script end');再去执行当前宏任务里面的微任务,即Promise.then回调函数,最后执行第二个宏任务定时器.

执行结果:
script start
script end
promise1
promise2
setTimeout

2.打印如下执行结果

const promise = new Promise((resolve,reject) => {
    console.log(1);
    resolve();
    console.log(2);
});
promise.then(()=>{
    console.log(3);
});
console.log(4);

Promise 构造函数是同步执行的,promise.then 中的函数是异步执行的。因此

执行结果:
1
2
4
3

3.打印如下执行结果

var funcs = [];
for(var i=0;i<10;i++) {
    funcs.push(function() {
        console.log(i);
    });
}
funcs.forEach(function(func) {
    func();
});

基础题,匿名函数中的 i 值只有在函数调用执行的时候才会去寻找对应变量的,for循环结束后执行func()时,此时i变量已经变为10(最后有个i++),因此循环打印了十次10,想依次打印0-9的话可使用当即执行函数解决或者使用ES6的块级做用域let声明变量i.
image.png

4.解释0.1 + 0.2 !== 0.3

js中number类型的数字都是采用64位的双精度浮点数进行存储的,其中1个符号位(0正1负),11个指数位,52个尾数位。0.1用二进制表示以下:
0.000110011001100110011001100110011001100110011001100110011...
如上能够看出0.1二进制表示时尾数是超过52位的, 因此52位以后的会被舍去,这就有了浮点数存储的精度丢失问题。
image.png

5.写出下列执行结果:

setTimeout(()=>{
    console.log('b')
    new Promise((resolve,reject)=>{
        console.log('c');
        resolve()
    }).then(res => {
        console.log('f')
    })
},0);
new Promise((resolve,reject) => {
    console.log('d')
    resolve()
}).then(res => {
    console.log('a')
    setTimeout(()=>{
        console.log('e')
    },0)
})

原理同第一题,答案为:dabcfe

6.写出如下程序运行结果:

let test1 = () => {
    console.log(this);
};
function test2() {
    console.log(this);
};
class t {
    test() {
        console.log(this);
    }
}
let test3 = t.prototype.test;

test1.call(null);
test2.call(null);
test3.call(null);

先给出正确答案:

/// window  ; window ; null  (非严格模式),
/// window  ; null   ; null   (严格模式)

当call或apply的第一个参数为null || undefined时 this指向window ||global

call方法的参数,应该是一个对象。若是参数为空、null和undefined,则默认传入全局对象

类和模块的内部,默认就是严格模式,因此不须要使用use strict指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。考虑到将来全部的代码,其实都是运行在模块之中,因此 ES6 实际上把整个语言升级到了严格模式。

顺便解释一下call的用法,apply相似,参数不一样而已:

call方法

语法:call(thisobj,[argq,arg2])

定义:调用一个对象的一个方法,以另外一个对象替换当前对象

说明:

call方法能够用来代替一个对象调用一个方法,call方法能够将一个函数的对象上下文从初始化改成新的对象,也就是括号里面的本来的对象改成call()前面的对象、即用thisobj代替call前面的东西,最终用thisobj这个对象去执行call前面的方法。

若是没有提供 thisObj 参数,那么 Global 对象被用做 thisObj。 

其实call才是函数调用最原始的方式,如今咱们使用的直接myFunc(args)调用函数的方式其实就是call调用的语法糖

7.使用js实现随机选取10–100之间的10个数字,存入一个数组,并排序

let iArray = []; 
function getRandom(istart, iend){
    var iChoice =iend - istart + 1;
    return  Math.floor(Math.random() * iChoice + istart);
}
/*Math.random()就是获取 0-1 之间的随机数(永远获取不到 1)*/
for(let i=0; i<10; i++){
let result= getRandom(10,100);
iArray.push(result);
}
iArray.sort(function(a,b){
 return a>b;
}); 
console.log(iArray);

8.输出如下运行结果:

let foo=1;
function bar(){
    foo=10;
    return;
    functionfoo(){}
}

bar();
console.log(foo); //1
为何是1而不是10先分析一下每步流程:
第一步:varfoo=1;全局变量foo被初始化赋值成1。
第二步:执行bar();方法。
第三步:bar()方法里,函数声明functionfoo(){}优先处理,这里JavaScript解析语法时(在运行以前)函数优先于一切。因此foo被初始化赋值为function(){};
第四步:执行foo=10;这里制造了一个假象,认为没有用var声明指向的是外层foo=1;。其实不是。而是先在自身函数体里找有没有foo声明,找到以前声明的functionfoo(){};赋值成10,只是局部变量的值改写。
第五步:输出foo,这时找的是全局变量varfoo=1;输出1。

CSS部分:

1.分别写出box的高度

<style>
    .box {
        line-height: 24px;
        background-color: lightblue;
    }
    .box span {
        line-height: 48px;
        border: 1px solid;
    }
</style>
<div class="box">
    <span>content...</span>
</div>

考察的是inline box模型,它的工做就是包裹每行文字,一个没有设置height属性的div的高度就是由一个一个line boxes的高度堆积而成的,撑开div高度的是line-height不是文字内容.MDN 文档中对line-height的描述以下:

line-height CSS 属性用于设置多行元素的空间量, 好比文本。对于块级元素, 它指定元素行盒(line boxes)的最小高度。 对于非替代的inline元素, 它用于计算行盒(line box)的高度。
适用元素 all elements. It also applies to ::first-letter and ::first-line.
如上面最终显示 .box 容器 height = 48px;
1.
将<span>标签里的内容 改成<span>content ... <br> content ... </span> 后,
.box 的height = 96px(48px*2)。
2.
将<span>标签里的内容 改成content ... <br><span> content ... </span> 后,
.box 的height = 48 + 24 = 72px。

2.css实现0.5像素的边框

半像素边框固然不是简单地把1px改成0.5px,浏览器中最小的像素单位为1像素,是不能识别0.5个像素,

1.设置目标元素做为定位参照
box{position:relative}

2.给目标元素添加一个伪元素before或者after,并设置绝对定位
.box:before{content:""; position:absolute;}

3.给伪元素添加1px边框
border:1px solid #000;

4.设置伪元素的宽高为目标元素的2倍
width:200%; height:200%;

5.缩小0.5倍(缩放到原来大小)
transform-origin: 0 0;
transform:scale(0.5,0.5);

6.把border 边框在线框内绘制
box-sizing:border-box;

image.png

Vue框架部分:

1.vue组件中的data为何必须是个函数

简单地说,对象是引用数据类型,那你每次导入这个组件的时候,其实引用的是同一个内存地址,componentA改变了引用这块地址的数据后,componentB中的这块地址对应的数据也会被改变。
那是由于在js中,函数的{}才有独立的做用域,对象的{},if(){}是不构成做用域的.
函数里面,每调用一次函数就会建立一个新的函数做用域,他们之间是互相独立的,这样的话,无论你同时引入同一个组件多少次,他们之间的组件属性都是独立的,互不干扰。

2.解释vue的响应式原理

vue的响应式核心是Object.defineProperty实现的.

Object.defineProperty(obj, key, {
    set:function(){},
    get:function(){}
})

被Object.defineProperty绑定过的数据会被监听到,改变这个对象的时候会触发get和set事件,这也是vue的model层和view层通讯的基础,其实vue中的Observer就是基于Object.defineProperty来实现的。
Observer是数据的观察者,与model层直接通讯,当数据更改时,它会通知dep(专门管理数据监听依赖的东西),dep会收集到它所须要的依赖,当get的时候,收集订阅者(这里的订阅者实际上是观察者模式下的订阅者,简单地说,就是它须要知道具体get什么订阅者,什么是观察者模式和发布订阅者设计模式,具体网上不少相关资料解释),把他添加到依赖,好比,watch和computed都依赖一个data进行监听或者计算,那么dep会将这两个不一样的依赖收集。当set的时候会发布更新,通知watcher更新view层。
一个属性可能有多个依赖,每一个响应式数据都有一个Dep来管理它的依赖。
每个依赖又是依靠一个中介的角色来通知变化从而更新视图的,所以watcher能通知变化去执行各自的代码,固然它也能区分本身所属的依赖,好比本身是属于data仍是watch仍是computed.
放两张网上的图能够更明了的说明他们之间的关系,也能够看看大佬们的文章,讲的更仔细,想学会这种设计模式仍是要撸源码,应付面试已经够了。
image.png
原图连接

image.png
原图连接

3.解释v-model的原理

v-model本质上就是一个语法糖,实现原理其实就是上面说过的数据绑定加上底层的input事件监听,经过v-bind绑定一个数据传给子组件,子组件里面的model默认用value属性接受,而后子组件监听数据发生变化,emit触发父组件的input事件,经过触发事件来进行传值,实现了父子组件数据的双向绑定。

4.设计模式-发布订阅者模式

定义了一种一对多的依赖关系,即当一个对象的状态发生改变的时候,全部依赖他的对象都会获得通知。

观察者模式是由具体目标(发布者/被观察者)调度的,而发布/订阅模式是由独立的调度中心进行调度,因此观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会(至关于一个中介的角色,一个全局的Event,发布者不须要知道具体要通知谁,订阅者也不须要知道具体是谁通知的);能够说发布订阅模式是观察者模式进一步解耦,在实际中被大量运用的一种模式。

5.vue.js如何作单元测试?

单元测试:按空间切割,对每一个组件进行测试

好比,我要测试日期输入框,那么我编写的测试用例应该包括如下部分:

  • 默认日期是否为当天
  • 当用户选择日期范围,data是否会作相应改变
  • ...

E2E测试:按时间切割,对每一个流程进行测试

好比,我要测试搜索功能,那么我编写的测试用例应该模拟如下步骤:

  • 打开主页
  • 点击菜单跳转到详情页
  • 输入搜索条件
  • 点击搜索
  • 查看搜索结果是否与预期一致
vue init webpack test

6.vue v-on绑定多个方法

1.v-on绑定多个方法:
<p v-on="{click:dbClick,mousemove:MouseClick}"></p>

2.一个事件绑定多个函数:
<p @click="one(),two()">点击</p>

7.举例vue中经常使用的修饰符

.lazy:

v-modeil不用多说,输入框改变,这个数据就会改变,lazy这个修饰符会在光标离开input框才会更新数据:

<input type="text" v-model.lazy="value">

.trim:

输入框过滤首尾的空格:

<input type="text" v-model.trim="value">

.number:

先输入数字就会限制输入只能是数字,先字符串就至关于没有加number,注意,不是输入框不能输入字符串,是这个数据是数字:

<input type="text" v-model.number="value">

.stop:

阻止事件冒泡,至关于调用了event.stopPropagation()方法。这个应该不须要解释:

<button @click.stop="test">test</button>

.prevent:

阻止默认行为,至关于调用了event.preventDefault()方法,好比表单的提交、a标签的跳转就是默认事件:

<a @click.prevent="test">test</a>

.self:

只有元素自己触发时才触发方法,就是只有点击元素自己才会触发。好比一个div里面有个按钮,div和按钮都有事件,咱们点击按钮,div绑定的方法也会触发,若是div的click加上self,只有点击到div的时候才会触发,变相的算是阻止冒泡:

<div @click.self="test"></div>

.once:

只能用一次,不管点击几回,执行一次以后都不会再执行:

<div @click.once="test"></div>

.capture:

事件的完整机制是捕获-目标-冒泡,事件触发是目标往外冒泡,好比:

<div @click="test(1)">  <button @click="test(2)">test</button></div>

顺序是2 1,capture的做用就是让这个顺序相反:

<div @click.capture="test(1)">  <button @click="test(2)">test</button></div>

先1 后2。

.passive:

其实我不怎么理解,官网解释说能够提高移动端的性能,查了查,大概解释就是每次滚动都会有一个默认事件触发,加了这个就是告诉浏览器,不须要查询,不须要触发这个默认事件preventDefault:

<!-- 滚动事件的默认行为 (即滚动行为) 将会当即触发 --> 

<!-- 而不会等待 `onScroll` 完成 -->

 <!-- 这其中包含 `event.preventDefault()` 的状况 -->

<div v-on:scroll.passive="onScroll">...</div>

.native:

组件绑定当前组件的事件是不会触发的,须要用native才能触发:

<My-component @click="shout(3)"></My-component>

鼠标.left、.reight、.middle:

就是鼠标点击的时候就触发:

<button @click.right="test">test</button>

.keyCode:

监听按键的指令,具体能够查看vue的键码对应表:

<input type="text" @keyup.enter="test(1)">

<button @click.enter="test(1)">test</button>

注意,只有你点击过一次或者聚焦到这个输入框才能使用键盘触发。

.exact:

系统修饰键,只有按着这个键而后用鼠标点击才会触发,官网解释:

<!-- 即便 Alt 或 Shift 被一同按下时也会触发 -->

 <button @click.ctrl="onClick">A</button>

<!-- 有且只有 Ctrl 被按下的时候才触发 -->

<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>

可是我试了一下没有用。

.sync

对prop进行双向绑定,我的暂时用不习惯:

//父组件

<fa-comp :fatest.sync="test"></fa-comp>

//子组件

this.$emit('update:fatest,sontest);

......

持续更新~

推荐大佬的一篇关于浏览器和js线程的文章,炒鸡棒

相关文章
相关标签/搜索