最近面试遇到的一些问题,如有错误,欢迎指正O(∩_∩)O~~。
1、 浏览器先尝试从Host文件中获取该请求对应的IP地址,如果没有找到,就使用DNS域名解析服务器来解析IP地址。(一个域名可能对应多个ip地址)
2、 建立TCP连接3次握手。
3、 发送HTTP请求。
4、收到服务器的响应,浏览器解析HTML文本,构建DOM树,解析css,构建样式树,两者合成render树,最后渲染在页面上。
$(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
}
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代码被解析和执行时所在环境,函数每调用一次,都会产生一个新的执行环境,因为不同的调用可能就有不同的参数。
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的值,找到了就结束了,这就是作用域链。
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对象有三个状态: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.then()方法链式调用可以解决这个问题,当上一个then方法执行完成且成功才会调用下一个then。
1、var声明的变量属于函数作用域,let和const声明的变量属于块级作用域;
2、var存在变量提升现象,而let和const不存在,会报错。
3、var变量可以重复声明,let和const不能重复声明。
4、let声明变量可以改,const声明常量不可改,声明变量可以改,只要保证变量的内存地址不改动,比如向数组push数据、改变对象的属性值,这些都是没问题的。
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
fn.call(obj,1,2); //立即执行
fn.apply(obj,[1,2]); //立即执行
var f=fn.bind(obj,1,2);
f(); //等调用后再执行
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
第三个参数是boolean值,true表示事件捕获,false表示事件冒泡。
width: 0;
height: 0;
border-width: 100px;
border-style: solid;
border-color: red transparent transparent transparent;
浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,修改其中任意一个对象的值,另一个对象的值也会随之变化。
深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,深拷贝新开辟了一个地址,修改其中任意一个对象的值,不会影响另一个。
所有对元素视觉表现属性的修改,都会导致重绘,比如修改了背景颜色、文字颜色、透明度等。
所有会触发元素布局发生变化的修改,都会导致重排,比如窗口尺寸发生变化,添加、删除DOM元素,修改了元素盒子大小如width、height、padding等。
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事件。
当用户点击屏幕后,浏览器不能立即判断用户是单击还是双击缩放,因此会延迟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;
}
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不再对此动作进行响应了。
ngOnChanges:当数据绑定输入属性(@input)的值发生变化时调用;
ngOninit:在第一次ngOnChanges后调用,只调用一次;
ngDoCheck:用于检测和处理值的改变,可能会被多次调用;
ngAfterContentInit:被投影组件内容初始化之后调用;
ngAfterContentChecked:被投影组件内容的变更检测之后调用;
ngAfterViewInit:被投影组件视图及其子视图初始化之后调用;
ngAfterViewChecked:被投影组件视图及其子视图的变更检测之后调用;
ngOnDestroy:在Angular销毁指令/组件之前调用。
1、实现一个数据监听器Observer,具体利用Object.defineProperty()
来监听属性变动,如有变动可拿到最新值并通知订阅者;
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,以及绑定相应的更新函数;
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应函数,从而更新视图。
angular1:$scope
绑定了n个属性,就会添加n个watcher,当有一个watcher发生变化时,angular就发触发$scope.$digest
循环触发脏检查。
angular2:数据监听通过zoneJs实现,zoneJs就像是一个代理,它监听了angular所有的异步事件(用户输入、点击提交等;ajax请求;setTimeout,setInterval)并重写了所有的异步API(猴子补丁),当异步事件触发时,zoneJs会通知angular有数据发生变化,需要检测更新。
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
在b.html:
Insert title here
我是b.study.cn的body
这样在a页面就能获取b页面的内容了。
XSS:跨站脚本攻击(Cross-site scripting)是一种网站应用程序的安全漏洞攻击,它允许恶意用户将代码注入到网页上,这类攻击通常包含了html以及用户端脚本语言。
例如一直弹窗:
while (true) {
alert('你关不掉我')
}
网站左右两侧的广告栏:
img = document.createElement('img')
img.onclick = function() {
window.open('不好的网站')
}
防御:
1、设置cookie的属性为HttpOnly,那么js脚本将无法读取cookie信息;
2、对用户输入进行编码,转义过滤掉特殊字符;
XSRF:跨站请求伪造(Cross Site Request Forgery),诱导用户发起请求,完成一些违背用户意愿的请求(如恶意发帖、删帖、发邮件等)。
例如在论坛中发一贴,包含一链接:
www.csdnblog.com/bbs/delete_article.php?id=“X"
只要有用户点击了这个链接,那么ID为X的这一篇文章就被删掉了,而且是用户完全不知情的情况。
防御:
1、referer验证
referer是http请求header中的一部分,例如在www.google.com里有一个www.baudu.com的链接,那么点击www,baidu,com,它的header信息里就有:
Referer:http://www.google.com
如果伪造请求的referer不是http://www.google.com,就拦截该请求。
2、token验证
如果攻击者伪造了转账的表单,那么网站可以在表单中加入一个随机的token来验证,银行服务器通过验证表单的值来判断post请求是否合法,不合法则拦截。
3、加验证码
https://blog.csdn.net/qq_37012533/article/details/84620865
https://blog.csdn.net/qq_37012533/article/details/84984570
https://blog.csdn.net/qq_37012533/article/details/84786135
https://blog.csdn.net/qq_37012533/article/details/84958566
https://blog.csdn.net/qq_37012533/article/details/84951655
https://blog.csdn.net/qq_37012533/article/details/84632930