前端面试题(附答案)

最近面试遇到的一些问题,如有错误,欢迎指正O(∩_∩)O~~。

输入www.baidu.com并按下回车,中间发生了什么?

1、 浏览器先尝试从Host文件中获取该请求对应的IP地址,如果没有找到,就使用DNS域名解析服务器来解析IP地址。(一个域名可能对应多个ip地址)
2、 建立TCP连接3次握手。
3、 发送HTTP请求。
4、收到服务器的响应,浏览器解析HTML文本,构建DOM树,解析css,构建样式树,两者合成render树,最后渲染在页面上。

$(document).ready() 与window.onload的区别?

$(document).ready:意思就是DOM树加载完毕,就执行,不必等到页面中图片或其他外部文件都加载完毕。并且可以写多个.ready。
window.onload:是页面所有元素都加载完毕,包括图片、视频等所有元素。只能执行一次。

谈谈你对闭包的理解

使用闭包主要是为了封装私有的方法和变量,闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,使用不当容易造成内存泄漏。
闭包有三个特性:
1、函数嵌套函数;
2、函数内部可以引用外部的参数和变量;
3、参数和变量不会被垃圾回收机制回收;
清除:把变量设为null。

清除浮动的几种方式?

1、浮动的元素后面加一个空div,设为clear:both;
2、父元素overflow:hidden或zoom:1;
3、父元素设置高度
4、父元素:

.div:after(伪类){
    height: 0;
    clear: both;
    content: '.';
    visibility: hidden;
    zoom: 1;    //兼容IE
}

webpack和gulp的区别

1、 webpack是前端资源模块的管理和打包工具,gulp是规范前端开发流程的工具。
2、webpack文档资源文件的处理是通过入口文件产生的依赖形成的,gulp是配置不同的task,对该task配置路径下的所有资源都可以管理。

npm install、npm install --save与npm install --save-dev区别?
npm install moduleName //安装模块到文件node_modules目录下
npm install --save moduleName //将模块安装到文件node_modules目录下,并在package文件的dependencies节点写入依赖。
npm install --save-dev moduleName //将模块安装到文件node_modules目录下,并在package文件的devDependencies节点写入依赖。

如何判断一个变量是不是数组?

1、使用Array.isArray()判断,如果返回true,说明是数组;

Array.isArray([1,2,3]);    //true
Array.isArray(arguments);   //false   arguments是类数组,不是数组。

2、使用instanceof判断,如果返回true,说明是数组;

[1,2,3] instanceof Array;    //true

3、使用Object.prototype.toString.call()判断,如果值是[object Array],说明是数组,如果值是[object Object],说明是对象;

Object.prototype.toString.call([1,2,3]);    //[object Array]

4、通过constructor来判断,如果是数组,那么arr.constructor===Array(不准确,因为可以更改值);

[1,2,3].constructor===Array;    //true
function fn(){
    console.log(arguments.constructor===Array);  //false
    arguments.constructor=Array;
    console.log(arguments.constructor===Array);  //true
}
fn(1,2,3);

谈谈你对JS执行上下文和作用域链的理解

执行上下文就是当前js代码被解析和执行时所在环境,函数每调用一次,都会产生一个新的执行环境,因为不同的调用可能就有不同的参数。

function fn(x) {
  console.log(arguments)
  console.log(x)
}
fn(20);
fn(10);

作用域是一个‘地盘’,作用域是静态观念的,而执行上下文环境是动态的,有闭包存在时,一个作用域存在两个上下文环境也是有的。

let x = 100;          // 全局作用域
function fn(x) {     // fn作用域 
    function bar(x) {     // bar作用域
      console.log(x)
    }
}
let f1 = fn(5);
let f2 = fn(10);
f1() // 5
f2() // 10

同一个作用域下,对同一个函数的不同调用会产生不同的执行上下文环境,继而产生不同的变量的值,所以,作用域变量的值是在执行过程中确定的,而作用域是在函数创建时就确定的

let a = 100
function fn() {
   let b = 20
   return function bar() {
     console.log(a + b);
   }
}
let x = fn();
b = 200
x()     //120

bar的这个作用域中没有a和b的值,它就会向上找到fn的作用域取得b的值,再向上全局作用域找到a的值,找到了就结束了,这就是作用域链

js的常见错误类型

1、 SyntaxError (语法错误)
eg:var 1a;
2、Reference (引用错误)
eg:console.log(a); var a=1;
3、TypeError(类型错误)
eg:var a=new 123;
4、RangeError(范围错误)
eg:var a=new Array(-1); //超出有效范围

谈谈你对promise的理解

promise是处理异步操作的一种解决方案。
promise对象有三个状态:pending、fulfilled、rejected,异步操作的结果是由pending变成fulfilled成功或变成rejected失败。
promise构造函数接受一个函数作为参数,以及该函数的两个参数分别为resolve和reject两个函数。

const promise = new Promise(function(resolve, reject){
    if(success){
        resolve(value);
    }else{
         reject(error);
    }
})

分别对应promise对象的then()和catch()方法。

promise.then(function(value){
    console.log(success);
}.catch(error){
    console.log(error);
})

Promise.all()方法用于将多个Promise实例,包装成一个新的Promise实例。

const p=Promise.all([p1,p2,p3]);

注:a、只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
b、只要p1、p2、p3之中有一个变成rejected,p的状态就会变成rejected,此时第一个变成reject的实例的返回值,会传递给p的回调函数

Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.race([p1, p2, p3]);

上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

promise解决了什么问题?

promise解决了多层嵌套回调的问题。
上一个函数请求的输出作为下一个请求的输入,如果网络延迟,下一个请求执行时,很可能上一个请求还没返回值,这样就会导致请求失败。
而用promise.then()方法链式调用可以解决这个问题,当上一个then方法执行完成且成功才会调用下一个then。

let和const的区别?

1、var声明的变量属于函数作用域,let和const声明的变量属于块级作用域;
2、var存在变量提升现象,而let和const不存在,会报错。
3、var变量可以重复声明,let和const不能重复声明。
4、let声明变量可以改,const声明常量不可改,声明变量可以改,只要保证变量的内存地址不改动,比如向数组push数据、改变对象的属性值,这些都是没问题的。

typeof、instanceof、constructor的区别?

1、typeof 判断运算数的数据类型,返回字符串。

typeof a='number'/'string'/'function'/'object';
typeof null='object';

2、instanceof 用来判断一个变量是否是某个对象的实例,只能用来判断对象、数组和函数。

[] instanceof Array    //true
[] instanceof Object    //true

3、constructor是每一个原型对象都拥有的属性,而这个属性也相当于是一个指针,它指向于创建当前对象的对象。

[1,2,3].constructor==Array;    //true
[1,2,3].constructor==Object;    //false

call、apply和bind的区别

fn.call(obj,1,2);           //立即执行
fn.apply(obj,[1,2]);      //立即执行
var f=fn.bind(obj,1,2);
f();        //等调用后再执行

js获取url的参数值

function getRequest(){
    var url=location.search;   
    var theRequest=new Object();
    if(url.indexOf('?')!=-1){
        var  a=url.substr(1);
        var b=a.split('&');
        for(var i=0; i

addEventListenter第三个参数是什么以及它的作用?

第三个参数是boolean值,true表示事件捕获,false表示事件冒泡。

纯css画三角形

width: 0;
height: 0;
border-width: 100px;
border-style: solid;
border-color: red transparent transparent transparent;

浅拷贝和深拷贝的区别?

浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,修改其中任意一个对象的值,另一个对象的值也会随之变化。
深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,深拷贝新开辟了一个地址,修改其中任意一个对象的值,不会影响另一个。

重绘和重排的区别?

所有对元素视觉表现属性的修改,都会导致重绘,比如修改了背景颜色、文字颜色、透明度等。
所有会触发元素布局发生变化的修改,都会导致重排,比如窗口尺寸发生变化,添加、删除DOM元素,修改了元素盒子大小如width、height、padding等。

get和post的区别?

GET/POST都是TCP链接。GET和POST能做的事情是一样一样的。你要给GET加上request body,给POST带上url参数,技术上是完全行的通的。
get后退无刷新,post后退会重新发请求;
get能自动缓存网页,post要手动缓存;
get有长度限制,不超过2048个字节,post长度无限制;
都是TCP连接,get产生一个TCP数据包(http header和data一起发送),post产生两个TCP数据包(http header和data分开发送);
get向服务器索取数据,post向服务器提交数据。

什么是事件委托?

事件委托是利用事件冒泡,只指定一个事件处理程序来管理某一类型的所有事件。
优点:
减少事件注册,节省内存;
动态添加事件,即不用在新添加或删除的li上绑定或解绑click事件。

移动端click事件延迟300ms的原因以及解决办法?

当用户点击屏幕后,浏览器不能立即判断用户是单击还是双击缩放,因此会延迟300ms。
解决方案:
1、添加viewpoint meta标签(user-scalable=no解决安卓的300ms延迟问题)


2、fastClick (https://github.com/ftlabs/fastclick)
移动端事件触发顺序:touchstart–>touchmove–>touchend–>click。
fastClick.js的原理是:在检测到touchend事件的时候,会通过DOM自定义事件立即触发模拟一个click事件,并把浏览器在300ms之后真正的click事件阻止掉。

说出几个常见的状态码?

100:请求开始连接;
200:请求连接成功;
301:表示永久重定向,搜索引擎会把旧地址替换成新地址,输入www.baidu.com会跳转至https://www.baidu.com;
302:表示临时重定向,例如未登录的用户会跳转至登录页面,搜索引擎会保留旧地址;
304:再次刷新网页返回304,表示客户端存在缓存;
400:表示服务器不理解请求的语法;
401:用户身份未验证,需要先登录;
404:客户端请求失败,找不到该请求的链接;
500:服务器端错误,比如tomcat正在启动;

移动端开发遇到过哪些坑?

1、IOS滚动不平滑的问题 -webkit-overflow-scrolling:touch;
2、fastclick可以解决在手机上点击事件的300ms延迟;
3、统一分辨率,禁止用户缩放;


4、去掉移动端点击时的高亮效果

* {
  -webkit-tap-highlight-color: rgba(0,0,0,0);
}

5、 IOS中input键盘事件keyup、keydown、keypress支持不是很好
解决:可以用html5的oninput事件去代替keyup
6、input输入框聚焦时底部的按钮被弹起
解决:input聚焦时底部隐藏
7、开发App时,ios7以上顶部header和手机状态栏重合

window.uexOnload = function(type){
    var ios7style=uexWidgetOne.iOS7Style;
    var isFullScreen = uexWidgetOne.isFullScreen;
    if (ios7style == '1' && isFullScreen != '1') {
     $("body").addClass("uh_ios7");
    }
}

.uh_ios7 .uh,.uh_ios7{
    padding: 20px 0 0;
}

vue生命周期?

beforeCreate:el和data还未初始化,都为undefined;
created:完成了data数据的初始化,el没有;
beforeMount:完成了el和data的初始化,但是el里面的{{message}}还没显示出来,虚拟Dom,先把位置占住;
mounted:el的{{message}}显示,完成Dom元素的挂载,这个阶段可以写入ajax请求;
beforeUpdate和updated:修改meaasge两者先后调用;
beforeDestroy和destroyed:实例销毁后,重新改变组件里的message,vue不再对此动作进行响应了。

angular生命周期?

ngOnChanges:当数据绑定输入属性(@input)的值发生变化时调用;
ngOninit:在第一次ngOnChanges后调用,只调用一次;
ngDoCheck:用于检测和处理值的改变,可能会被多次调用;
ngAfterContentInit:被投影组件内容初始化之后调用;
ngAfterContentChecked:被投影组件内容的变更检测之后调用;
ngAfterViewInit:被投影组件视图及其子视图初始化之后调用;
ngAfterViewChecked:被投影组件视图及其子视图的变更检测之后调用;
ngOnDestroy:在Angular销毁指令/组件之前调用。

vue如何实现双向数据绑定的?

1、实现一个数据监听器Observer,具体利用Object.defineProperty()来监听属性变动,如有变动可拿到最新值并通知订阅者;
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,以及绑定相应的更新函数;
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应函数,从而更新视图。

angular如何实现双向数据绑定的?

angular1:$scope绑定了n个属性,就会添加n个watcher,当有一个watcher发生变化时,angular就发触发$scope.$digest循环触发脏检查。
angular2:数据监听通过zoneJs实现,zoneJs就像是一个代理,它监听了angular所有的异步事件(用户输入、点击提交等;ajax请求;setTimeout,setInterval)并重写了所有的异步API(猴子补丁),当异步事件触发时,zoneJs会通知angular有数据发生变化,需要检测更新。

EventLoop事件循环机制?

Javascript的事件分两种,宏任务(Macrotasks)和微任务(Microtasks)。
宏任务:setTimeout、setInterval、setImmediate;
微任务:Process.nextTick、Promise.then(注意不是new Promise);
执行顺序:同步任务–>微任务–>宏任务。

谈谈如何跨域?(高频问)

同源策略:域名、端口、协议相同,其中有一个不同就会产生跨域。
1、通过使用jsonp解决跨域



如果要在jQuery中使用Ajax,则只需要在dataType属性中把json改为jsonp即可。注意:跨域请求是只能是get请求不能使用post请求

$.ajax({
    type: 'get',
    url: 'api/register.php',
    data:data,
    dataType: 'jsonp',
    jsonp: "callback",            //参数名
    jsonpCallback:"success",      //自定义函数名
    success:function(data){
        console.log(data);
    }
})

2、后台配置CORS解决跨域
服务器端文件加上header("Access-Control-Allow-Origin", "*");
3、通过iframe来解决跨域
基于iframe实现的跨域要求两个域具有 aa.xx.com,bb.xx.com这种主域相同的域。
http://a.study.cn/a.html 请求 http://b.study.cn/b.html
在a.html:



 
 
 Insert title here