前端笔试题一
css
css3新特性
1.过渡 transition
2.动画 animation
3.形状转换 transform
4.阴影 box-shadow
5.滤镜 Filter
6.颜色 rgba
7.栅格布局 gird
8.弹性布局 flex
css中link与@import的区别
1、@import是 CSS 提供的语法规则,只有导入样式表的作用;link是HTML提供的标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等。
2、加载页面时,link引入的CSS被同时加载,@import引入的CSS将在页面加载完毕后加载。
3、link标签作为HTML元素,不存在兼容性问题,而@import是CSS2.1才有的语法,故老版本浏览器(IE5之前)不能识别。
4、可以通过JS操作DOM,来插入link标签改变样式;由于DOM方法是基于文档的,无法使用@import方式插入样式。
伪类与伪元素区别
1)伪类(pseudo-classes)
- 其核⼼就是⽤来选择DOM树之外的信息,不能够被普通选择器选择的⽂档之外的元素,⽤来添加⼀些选择器的特殊效果。
- ⽐如:hover :active :visited :link :visited :first-child :focus :lang等
- 由于状态的变化是⾮静态的,所以元素达到⼀个特定状态时,它可能得到⼀个伪类的样式;当状态改变时,它⼜会失去这个样式。
- 由此可以看出,它的功能和class有些类似,但它是基于⽂档之外的抽象,所以叫 伪类。
2)伪元素(Pseudo-elements)
- DOM树没有定义的虚拟元素
- 核⼼就是需要创建通常不存在于⽂档中的元素,
- ⽐如::before ::after 它选择的是元素指定内容,表示选择元素内容的之前内容或之后内容。
- 伪元素控制的内容和元素是没有差别的,但是它本身只是基于元素的抽象,并不存在于⽂档中,所以称为伪元素。⽤于将特殊的效果添加到某些选择器
2)伪类与伪元素的区别
- 表示⽅法
- CSS2 中伪类、伪元素都是以单冒号:表示,
- CSS2.1 后规定伪类⽤单冒号表示,伪元素⽤双冒号::表示,
- 浏览器同样接受 CSS2 时代已经存在的伪元素(:before, :after, :first�line, :first-letter 等)的单冒号写法。
- CSS2 之后所有新增的伪元素(如::selection),应该采⽤双冒号的写法。
- CSS3中,伪类与伪元素在语法上也有所区别,伪元素修改为以::开头。浏览器对以:开头的伪元素也继续⽀持,但建议规范书写为::开头
- 定义不同
- 伪类即假的类,可以添加类来达到效果
- 伪元素即假元素,需要通过添加元素才能达到效果
- 总结:
- 伪类和伪元素都是⽤来表示⽂档树以外的"元素"。
- 伪类和伪元素分别⽤单冒号:和双冒号::来表示。
- 伪类和伪元素的区别,关键点在于如果没有伪元素(或伪类),
- 是否需要添加元素才能达到效果,如果是则是伪元素,反之则是伪类。
4)相同之处:
- 伪类和伪元素都不出现在源⽂件和DOM树中。也就是说在html源⽂件中是看不到伪类和伪元素的。
不同之处: - 伪类其实就是基于普通DOM元素⽽产⽣的不同状态,他是DOM元素的某⼀特征。
- 伪元素能够创建在DOM树中不存在的抽象对象,⽽且这些抽象对象是能够访问到的。
让一个div水平垂直居中
- 使用position + transform
- 使用flex
- 使用position
- 使用伪类
.parent{
font-size: 0;
text-align: center;
}
.parent::before {
content: “”;
display: inline-block;
width: 0;
height: 100%;
vertical-align: middle;
}
.child{
display: inline-block;
vertical-align: middle;
}
link和@import有什么区别
(1)link属于XHTML标签,除了加载CSS外,还能用于定义RSS, 定义rel连接属性等作用;而@import是CSS提供的,只能用于加载CSS;
(2)页面被加载的时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载;
(3)import是CSS2.1 提出的,只在IE5以上才能被识别,而link是XHTML标签,无兼容问题;
js
数组和对象的原生方法
内存泄漏
写JavaScript的基本规范
1.不要在同一行声明多个变量。
2.请使用 ===/!==来比较true/false或者数值
3.使用对象字面量替代new Array这种形式
4.不要使用全局函数。
5.Switch语句必须带有default分支
6.函数不应该有时候有返回值,有时候没有返回值。
7.For循环必须使用大括号
8.If语句必须使用大括号
9.for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染。
JS的数据类型
基本类型:Number、Boolean、String、null、undefined、symbol(ES6 新增的),BigInt(ES2020) 引用类型:Object,对象子类型(Array,Function)
讲讲Map和Set?
- Map的key相比较普通对象来说更为灵活,普通对象的key只能以基础数据类型作为key值,并且所有传入的key值都会被转化成string类型,而Map的key可以是各种数据类型格式。
- Set可以讲讲它去重的特性。
WeakMap和Map之间的区别?
WeakMap只能以复杂数据类型作为key,并且key值是弱引用,对于垃圾回收更加友好。
this
浅拷贝和深拷贝的区别
- 浅拷贝:一般指的是把对象的第一层拷贝到一个新对象上去
- 深拷贝:一般需要借助递归实现,如果对象的值还是个对象,要进一步的深入拷贝,完全替换掉每一个复杂类型的引用。
浅拷贝:浅拷贝通过ES6新特性Object.assign()或者通过扩展运算法…来达到浅拷贝的目的,浅拷贝修改
副本,不会影响原数据,但缺点是浅拷贝只能拷贝第一层的数据,且都是值类型数据,如果有引用型数据,修改
副本会影响原数据。
深拷贝:通过利用JSON.parse(JSON.stringify())来实现深拷贝的目的,但利用JSON拷贝也是有缺点的,
当要拷贝的数据中含有undefined/function/symbol类型是无法进行拷贝的,当然我们想项目开发中需要
深拷贝的数据一般不会含有以上三种类型,如有需要可以自己在封装一个函数来实现。
事件冒泡和事件捕获
判断数组的方法
Object.prototype.toString.call()、instanceof、Array.isArray()以及typeof
面向对象
面向对象的三大特性:继承/多态/封装
作用链域
全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节。
当需要从局部函数查找某一属性或方法时,如果当前作用域没有找到,就会上溯到上层作用域查找,
直至全局函数,这种组织形式就是作用域链。
原型,原型链,原型链继承
-
原型
每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。 -
什么是原型链?
当对象查找一个属性的时候,如果没有在自身找到,那么就会查找自身的原型,如果原型还没有找到,那么会继续查找原型的原型,直到找到 Object.prototype 的原型时,此时原型为 null,查找停止。这种通过 通过原型链接的逐级向上的查找链被称为原型链原型链实际上在上面原型的问题中就有涉及到,在原型的继承中,我们继承来多个原型,这里再提一下实现完美
继承的方案,通过借助寄生组合继承,PersonB.prototype = Object.create(PersonA.prototype)
这是当我们实例化PersonB得到实例化对象,访问实例化对象的属性时会触发get方法,它会先在自身属性上查
找,如果没有这个属性,就会去proto中查找,一层层向上直到查找到顶层对象Object,这个查找的过程
就是原型链来。
- 什么是原型继承
一个对象可以使用另外一个对象的属性或者方法,就称之为继承。具体是通过将这个对象的原型设置为另外一个对象,这样根据原型链的规则,如果查找一个对象属性且在自身不存在时,就会查找另外一个对象,相当于一个对象可以使用另外一个对象的属性和方法了。
每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时,
如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,
于是就这样一直找下去,也就是我们平时所说的原型链的概念。
关系:instance.constructor.prototype = instance.proto
特点:
JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。
当我们需要一个属性的时,Javascript引擎会先看当前对象中是否有这个属性, 如果没有的话,
就会查找他的Prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象。
function Func(){}
Func.prototype.name = "Sean";
Func.prototype.getInfo = function() {
return this.name;
}
var person = new Func();//现在可以参考var person = Object.create(oldObject);
console.log(person.getInfo());//它拥有了Func的属性和方法
//"Sean"
console.log(Func.prototype);
// Func { name="Sean", getInfo=function()}
防抖节流
- 防抖
- 原理:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
- 适用场景:
- 按钮提交场景:防止多次提交按钮,只执行最后提交的一次
- 搜索框联想场景:防止联想发送请求,只发送最后一次输入
- 节流
- 原理:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
- 适用场景
- 拖拽场景:固定时间内只执行一次,防止超高频次触发位置变动
- 缩放场景:监控浏览器resize
重绘回流
当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流
会导致回流的操作:
- 页面首次渲染
- 浏览器窗口大小发生改变
- 元素尺寸或位置发生改变
- 元素内容变化(文字数量或图片大小等等)
- 元素字体大小变化
- 添加或者删除可见的DOM元素
- 激活CSS伪类(例如::hover)
- 查询某些属性或调用某些方法
- 当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。
- 性能影响
回流比重绘的代价要更高 - 如何避免
CSS- 避免使用table布局。
- 尽可能在DOM树的最末端改变class。
- 避免设置多层内联样式。
- 将动画效果应用到position属性为absolute或fixed的元素上。
- 避免使用CSS表达式(例如:calc())。
JavaScript - 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。
- 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
- 也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
- 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
- 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
js事件循环机制
事件循环机制从整体上告诉了我们 JavaScript 代码的执行顺序Event Loop即事件循环,是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。
先执行 Script 脚本,然后清空微任务队列,然后开始下一轮事件循环,继续先执行宏任务,再清空微任务队列,如此往复。
- 宏任务:Script/setTimeout/setInterval/setImmediate/ I/O / UI Rendering
- 微任务:process.nextTick()/Promise
上诉的 setTimeout 和 setInterval 等都是任务源,真正进入任务队列的是他们分发的任务。
js
JavaScript的任务分为两种同步和异步,它们的处理方式也各自不同,同步任务是直接放在主线程上排队依次执行,异步任务会放在任务队列中,若有多个异步任务则需要在任务队列中排队等待,任务队列类似于缓冲区,任务下一步会被移到调用栈然后主线程执行调用栈的任务。
调用栈:调用栈是一个栈结构,函数调用会形成一个栈帧,帧中包含了当前执行函数的参数和局部变量等上下文信息,函数执行完后,它的执行上下文会从栈中弹出。
JavaScript是单线程的,单线程是指 js引擎中解析和执行js代码的线程只有一个(主线程),每次只能做一件事情,然而ajax请求中,主线程在等待响应的过程中回去做其他事情,浏览器先在事件表注册ajax的回调函数,响应回来后回调函数被添加到任务队列中等待执行,不会造成线程阻塞,所以说js处理ajax请求的方式是异步的。
宏任务微任务
- 宏任务指执行栈中待执行的任务,setTimeout、setInterval、script,http回调都是宏任务。
- 微任务指执行栈清空后立即执行的任务,Promise和 MutationObserver,nextTick都是微任务。
作用域,作用域链
- ES5 中只存在两种作用域:全局作用域和函数作用域。在 JavaScript 中,我们将作用域定义为一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套子作用域中根据标识符名称进行变量(变量名或者函数名)查找
- 作用域链,当访问一个变量时,编译器在执行这段代码时,会首先从当前的作用域中查找是否有这个标识符,如果没有找到,就会去父作用域查找,如果父作用域还没找到继续向上查找,直到全局作用域为止,,而作用域链,就是有当前作用域与上层作用域的一系列变量对象组成,它保证了当前执行的作用域对符合访问权限的变量和函数的有序访问
闭包
-
什么是闭包
函数执行后返回结果是一个内部函数,并被外部变量所引用,如果内部函数持有被执行函数作用域的变量,即形成了闭包。
可以在内部函数访问到外部函数作用域。使用闭包,一可以读取函数中的变量,二可以将函数中的变量存储在内存中,保护变量不被污染。而正因闭包会把函数中的变量值存储在内存中,会对内存有消耗,所以不能滥用闭包,否则会影响网页性能,造成内存泄漏。当不需要使用闭包时,要及时释放内存,可将内层函数对象的变量赋值为null。 -
优点
- 可以从内部函数访问外部函数的作用域中的变量,且访问到的变量长期驻扎在内存中,可供之后使用
- 避免变量污染全局
- 把变量存到独立的作用域,作为私有成员存在
-
缺点
- 对内存消耗有负面影响。因内部函数保存了对外部变量的引用,导致无法被垃圾回收,增大内存使用量,所以使用不当会导致内存泄漏
- 对处理速度具有负面影响。闭包的层级决定了引用的外部变量在查找时经过的作用域链长度
- 可能获取到意外的值(captured value)
-
应用场景
应用场景一: 典型应用是模块封装,在各模块规范出现之前,都是用这样的方式防止变量污染全局。
应用场景二: 在循环中创建闭包,防止取到意外的值。 -
如何产生闭包
返回函数
函数当做参数传递
Javascript如何实现继承
1、构造继承
2、原型继承
3、实例继承
4、拷贝继承
原型prototype机制或apply和call方法去实现较简单,建议使用构造函数与原型混合方式。
function Parent(){
this.name = 'wang';
}
function Child(){
this.age = 28;
}
Child.prototype = new Parent();//继承了Parent,通过原型
var demo = new Child();
alert(demo.age);
alert(demo.name);//得到被继承的属性
}
javascript创建对象的几种方式
javascript创建对象简单的说,无非就是使用内置对象或各种自定义对象,当然还可以用JSON;但写法有很多种,也能混合使用。
1、对象字面量的方式
person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};
2、用function来模拟无参的构造函数
function Person(){}
var person=new Person();//定义一个function,如果使用new"实例化",该function可以看作是一个Class
person.name="Mark";
person.age="25";
person.work=function(){
alert(person.name+" hello...");
}
person.work();
3、用function来模拟参构造函数来实现(用this关键字定义构造的上下文属性)
function Pet(name,age,hobby){
this.name=name;//this作用域:当前对象
this.age=age;
this.hobby=hobby;
this.eat=function(){
alert("我叫"+this.name+",我喜欢"+this.hobby+",是个程序员");
}
}
var maidou =new Pet("麦兜",25,"coding");//实例化、创建对象
maidou.eat();//调用eat方法
4、用工厂方式来创建(内置对象)
var wcDog =new Object();
wcDog.name="旺财";
wcDog.age=3;
wcDog.work=function(){
alert("我是"+wcDog.name+",汪汪汪......");
}
wcDog.work();
5、用原型方式来创建
function Dog(){
}
Dog.prototype.name="旺财";
Dog.prototype.eat=function(){
alert(this.name+"是个吃货");
}
var wangcai =new Dog();
wangcai.eat();
6、用混合方式来创建
function Car(name,price){
this.name=name;
this.price=price;
}
Car.prototype.sell=function(){
alert("我是"+this.name+",我现在卖"+this.price+"万元");
}
var camry =new Car("凯美瑞",27);
camry.sell();
什么是虚拟dom,优势是什么,存储在哪
-
Virtual DOM 可以理解为一个简单的JS对象,并且最少包含标签名( tag)、属性(attrs)和子元素对象( children)三个属性。
-
优势:
1、具备跨平台的优势-由于 Virtual DOM 是以 JavaScript 对象为基础而不依赖真实平台环境,所以使它具有了跨平台的能力,比如说浏览器平台、Weex、Node 等。2、提升渲染性能-Virtual DOM的优势不在于单次的操作,而是在大量、频繁的数据更新下,能够对视图进行合理、高效的更新。 为了实现高效的DOM操作,一套高效的虚拟DOM diff算法显得很有必要。通过找出本次DOM需要更新的节点来更新,其他的不更新。 3、是一个js对象,存储在内存中。
js脚本加载问题,async、defer问题
- 如果依赖其他脚本和 DOM 结果,使用 defer
- 如果与 DOM 和其他脚本依赖不强时,使用 async
浏览器内核的理解?
- 主要分成两部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎。
渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。
JS引擎则:解析和执行javascript来实现网页的动态效果。
最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。
- 常见的浏览器内核有哪些?
Trident内核:IE,MaxThon,TT,The World,360,搜狗浏览器等。[又称MSHTML]
Gecko内核:Netscape6及以上版本,FF,MozillaSuite/SeaMonkey等
Presto内核:Opera7及以上。 [Opera内核原为:Presto,现为:Blink;]
Webkit内核:Safari,Chrome等。 [ Chrome的:Blink(WebKit的分支)]
ES6
this
this指向
bind,call,apply
call: Array.prototype.call(this, args1, args2])
apply: Array.prototype.apply(this, [args1, args2])
ES6 之前用来展开数组调用, foo.appy(null, []),ES6 之后使用 … 操作符
- New 绑定 > 显示绑定 > 隐式绑定 > 默认绑定
- 如果需要使用 bind 的柯里化和 apply 的数组解构,绑定到 null,尽可能使用 Object.create(null) 创建一个 DMZ 对象
- 四条规则:
-
- 默认绑定,没有其他修饰(bind、apply、call),在非严格模式下定义指向全局对象,在严格模式下定义指向 undefined
- 隐式绑定:调用位置是否有上下文对象,或者是否被某个对象拥有或者包含,那么隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象。而且,对象属性链只有上一层或者说最后一层在调用位置中起作用
- 显示绑定:通过在函数上运行 call 和 apply ,来显示的绑定 this
- New 绑定时,如果是 new 一个硬绑定函数,那么会用 new 新建的对象替换这个硬绑定 this,
symbol
用来表示一个独一无二的变量防止命名冲突
promise
- 概念
抽象表达
Promise是 js 进行异步编辑的新的解决方案(旧的方式:纯回调的形式)
具体表达
1 从语法上来说Promise 是一个构造函数
2 从功能上来说promise 对象用来封装一个异步操作并可以获取其结果 - Promise优点
- 统一异步 API
- Promise 的一个重要优点是它将逐渐被用作浏览器的异步 API ,统一现在各种各样的 API ,以及不兼容的模式和手法。
- Promise 与事件对比
- 和事件相比较, Promise 更适合处理一次性的结果。在结果计算出来之前或之后注册回调函数都是可以的,都可以拿到正确的值。 Promise 的这个优点很自然。但是,不能使用 Promise 处理多次触发的事件。链式处理是 Promise 的又一优点,但是事件却不能这样链式处理。
- Promise 与回调对比
- 解决了回调地狱的问题,将异步操作以同步操作的流程表达出来。
- Promise 带来的额外好处是包含了更好的错误处理方式(包含了异常处理),并且写起来很轻松(因为可以重用一些同步的工具,比如 Array.prototype.map() )。
Promise缺点 - 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
- 当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
- Promise 真正执行回调的时候,定义 Promise 那部分实际上已经走完了,所以 Promise 的报错堆栈上下文不太友好。
- 统一异步 API
- 状态改变
pending 变为 resolved
* pending rejected
* 一个promise 对象只能改变一次
* 无论变为成功还是失败,都会有一个结果数据
* 成功的结果数据一般称为value 失败的结果数据一般称为reason
* 为什么要使用promise
*
* 1 指定的回调函数的方式更加灵活
* 旧:必须要启动异步任务前指定
* promise 启动异步任务=>返回 promise对象=>给promise对象
* 绑定回调函数(甚至可以在异步结束后指定/多个)
*
* 2 promise 支持链式调用。可以解决回调地狱问题
* 什么是回调地狱 回调函数嵌套调用,外部回调函异步执行的结果是嵌套的
* 回调函数执行条件
* 回调地狱的缺点?不便于阅读/不便于异常处理
* 解决方案 promise 链式调用
* 错误回调:异常传透
* then 是原型对象方法
* new Promise 是实例对象方法
* Promise.all promise函数对象方法
箭头函数与普通函数的区别
- 箭头函数是匿名函数,不能作为构造函数,不能使用new
- 箭头函数不绑定arguments,取而代之用rest参数…解决
- 箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值
- 箭头函数通过call()或apply()方法调用一个函数时,只传入了一个参数,对 this 并没有影响
- 箭头函数没有原型属性
普通函数通过 function 关键字定义, this 无法结合词法作用域使用,在运行时绑定,只取决于函数的调用方式,在哪里被调用,调用位置。(取决于调用者,和是否独立运行)
箭头函数使用被称为 “胖箭头” 的操作 => 定义,箭头函数不应用普通函数 this 绑定的四种规则,而是根据外层(函数或全局)的作用域来决定 this,且箭头函数的绑定无法被修改(new 也不行)。
- 箭头函数常用于回调函数中,包括事件处理器或定时器
- 箭头函数和 var self = this,都试图取代传统的 this 运行机制,将 this 的绑定拉回到词法作用域
- 没有原型、没有 this、没有 super,没有 arguments,没有 new.target
- 不能通过 new 关键字调用
- 一个函数内部有两个方法:[[Call]] 和 [[Construct]],在通过 new 进行函数调用时,会执行 [[construct]] 方法,创建一个实例对象,然后再执行这个函数体,将函数的 this 绑定在这个实例对象上
- 当直接调用时,执行 [[Call]] 方法,直接执行函数体
- 箭头函数没有 [[Construct]] 方法,不能被用作构造函数调用,当使用 new 进行函数调用时会报错。
http
同步和异步的区别
同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,j进行下一步操作。
异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容。
跨域
Http 缓存策略
ajax实现原理及方法使用
原生ajax的请求步骤
//创建 XMLHttpRequest 对象
var ajax = new XMLHttpRequest();
//规定请求的类型、URL 以及是否异步处理请求。
ajax.open('GET',url,true);
//发送信息至服务器时内容编码类型
ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//发送请求
ajax.send(null);
//接受服务器响应数据
ajax.onreadystatechange = function () {
if (obj.readyState == 4 && (obj.status == 200 || obj.status == 304)) {
}
};
如何防范CSRF攻击,XSS攻击
XSS攻击的防范
1、HttpOnly 防止劫取 Cookie
2、输入检查-不要相信用户的所有输入
3、输出检查-存的时候转义或者编码
复制代码
CSRF攻击的防范
1、验证码
2、Referer Check
3、添加token验证
一个页面从输入 URL 到页面加载显示完成的全部过程
1、浏览器会开启一个线程来处理这个请求,对 URL 分析判断如果是 http 协议就按照 Web 方式来处理;
2、调用浏览器内核中的对应方法,比如 WebView 中的 loadUrl 方法;
3、通过DNS解析获取网址的IP地址,设置 UA 等信息发出第二个GET请求;
4、进行HTTP协议会话,客户端发送报头(请求报头);
5、进入到web服务器上的 Web Server,如 Apache、Tomcat、Node.JS 等服务器;
6、进入部署好的后端应用,如 PHP、Java、JavaScript、Python 等,找到对应的请求处理;
7、处理结束回馈报头,此处如果浏览器访问过,缓存上有对应资源,会与服务器最后修改时间对比,一致则返回304;
8、浏览器开始下载html文档(响应报头,状态码200),同时使用缓存;
9、文档树建立,根据标记请求所需指定MIME类型的文件(比如css、js),同时设置了cookie;
10、页面开始渲染DOM,JS根据DOM API操作DOM,执行事件绑定等,页面显示完成。
常用的http状态码
基本概念:
HTTP,全称为 HyperText Transfer Protocol,即为超文本传输协议。是互联网应用最为广泛的一种网络协议
所有的 www 文件都必须遵守这个标准。
http特性:
HTTP 是无连接无状态的
HTTP 一般构建于 TCP/IP 协议之上,默认端口号是 80
HTTP 可以分为两个部分,即请求和响应。
http请求:
HTTP 定义了在与服务器交互的不同方式,最常用的方法有 4 种
分别是 GET,POST,PUT, DELETE。URL 全称为资源描述符,可以这么认为:一个 URL 地址
对应着一个网络上的资源,而 HTTP 中的 GET,POST,PUT,DELETE
就对应着对这个资源的查询,修改,增添,删除4个操作。
HTTP 请求由 3 个部分构成,分别是:状态行,请求头(Request Header),请求正文。
HTTP 响应由 3 个部分构成,分别是:状态行,响应头(Response Header),响应正文。
HTTP 响应中包含一个状态码,用来表示服务器对客户端响应的结果。
状态码一般由3位构成:
1xx : 表示请求已经接受了,继续处理。
2xx : 表示请求已经处理掉了。
3xx : 重定向。
4xx : 一般表示客户端有错误,请求无法实现。
5xx : 一般为服务器端的错误。
比如常见的状态码:
200 OK 客户端请求成功。
301 Moved Permanently 请求永久重定向。
302 Moved Temporarily 请求临时重定向。
304 Not Modified 文件未修改,可以直接使用缓存的文件。
400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解。
401 Unauthorized 请求未经授权,无法访问。
403 Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因。
404 Not Found 请求的资源不存在,比如输入了错误的URL。
500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求。
503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常。
大概还有一些关于http请求和响应头信息的介绍。
http的基本结构
cookies,sessionStorage 和 localStorage 的区别
cookie是网站为了标示用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。
cookie数据始终在同源的http请求中携带(即使不需要),记会在浏览器和服务器间来回传递。
sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
存储大小:
cookie数据大小不能超过4k。
sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
有期时间:
localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
sessionStorage 数据在当前浏览器窗口关闭后自动删除。
cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
https的原理
http的缓存机制吧,强缓存,协商缓存
vue
基础
vue中key
便于diff算法的更新,key的唯一性,能让算法更快的找到需要更新的dom,需要注意的是,key要唯一,不然会出现很隐蔽性的更新问题。
vue双向绑定的原理
双向数据绑定是基于Object.defineProperty()重新定义get和set方法实现的。修改触发set方法赋值,获取触发get方法取值,并通过数据劫持发布信息。
高级
组件router
Vue通信
1.props和$emit
2.中央事件总线 EventBus(基本不用)
3.vuex(官方推荐状态管理器)
4.parent和children
Vue路由守卫有哪些,怎么设置,使用场景
常用的两个路由守卫:router.beforeEach 和 router.afterEach
每个守卫方法接收三个参数:
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 一定要调用该方法来 resolve 这个钩子。
在项目中,一般在beforeEach这个钩子函数中进行路由跳转的一些信息判断。
判断是否登录,是否拿到对应的路由权限等等。
组件中的name
- 项目使用 keep-alive 时,可搭配组件 name 进行缓存过滤
- DOM 做递归组件时需要调用自身 name
- vue-devtools 调试工具里显示的组见名称是由vue中组件name决定的
vuex
vuex是一个专为vue.js应用程序开发的状态管理器,它采用集中式存储管理应用的所有组件的状态,并且以相
应的规则保证状态以一种可以预测的方式发生变化。
state: vuex使用单一状态树,用一个对象就包含来全部的应用层级状态
mutation: 更改vuex中state的状态的唯一方法就是提交mutation
action: action提交的是mutation,而不是直接变更状态,action可以包含任意异步操作
getter: 相当于vue中的computed计算属性
keep-alive
- keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染
- 一般结合路由和动态组件一起使用,用于缓存组件;
- 提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高;
- 对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated。
vue中$nextTick作用
处理数据动态变化后,dom还未及时更新的问题。$nextTick就可以获取到数据更新后最新的dom变化
vue项目优化的手段有哪些
前端方面:
1、路由懒加载
2、图片,资源放cdn
3、页面图片较多进行懒加载
4、骨架屏方案
5、采用服务端渲染—nuxt.js
服务器端:
开启gzip
其他
前端工程化、模块化、组件化
前端工程化
1、将前端项目当成一项系统工程进行分析、组织和构建从而达到项目结构清晰、分工明确、团队配合默契、开发效率提高的目的
2、工程化思维就是“结构、样式和动作分离”。如目录分为assets,components,router,util
前端模块化
1、可以简单的认为模块化和组件化是工程化的表现形式
2、JS模块化方案很多有AMD/CommonJS/UMD/ES6 Module等,CSS模块化开发大多是在less、sass、stylus
前端组件化
1、组件化将页面视为一个容器,页面上各个独立部分例如:头部、导航、焦点图、侧边栏、底部等视为独立组件,不同的页面根据内容的需要,去盛放相关组件即可组成完整的页面。
2、模块化和组件化一个最直接的好处就是复用
vue,jq,react,angular区别,各自优势
jq
1、需要频繁操作dom
2、容易引起重绘和回流,影响页面性能
复制代码
vue
1、mvvm模式,采用虚拟dom不需要频繁操作dom,通过双向绑定,用数据驱动页面变化,页面变化对应数据也发生变化,只需要关注数据层的业务逻辑,而无需关注视图层的更新。可以尽量减少无用的更新操作,提高dom渲染效率。
2、组件化开发,页面由若干个组建组成,可复用性高。
3、社区环境好,各类资源文档十分齐全。
4、通过Object.defineProperty() 方法,监控对数据的操作,从而可以自动触发数据同步。
复制代码
react
1、虚拟dom。
2、一切都是组件,组件实例之间可以嵌套。
3、使用独特的jsx语法。
复制代码
angular
1、AngularJS的学习成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比较简单、直观。
2、在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢。
webpack
1、Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。
2、Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
3、Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。
4、Loader:模块转换器,用于把模块原内容按照需求转换成新内容。
5、Plugin:扩展插件,在 Webpack 构建流程中的特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情。
6、Output:打包后文件输出的位置
项目
原来公司工作流程是怎么样的,如何与其他人协作的?如何夸部门合作的?
你遇到过比较难的技术问题是?你是如何解决的?
设计模式 知道什么是singleton, factory, strategy, decrator么?
常使用的库有哪些?常用的前端开发工具?开发过什么应用或组件?
页面重构怎么操作?
网站重构:在不改变外部行为的前提下,简化结构、添加可读性,而在网站前端保持一致的行为。
也就是说是在不改变UI的情况下,对网站进行优化,在扩展的同时保持一致的UI。
对于传统的网站来说重构通常是:
表格(table)布局改为DIV+CSS
使网站前端兼容于现代浏览器(针对于不合规范的CSS、如对IE6有效的)
对于移动平台的优化
针对于SEO进行优化
深层次的网站重构应该考虑的方面
减少代码间的耦合
让代码保持弹性
严格按规范编写代码
设计可扩展的API
代替旧有的框架、语言(如VB)
增强用户体验
通常来说对于速度的优化也包含在重构中
压缩JS、CSS、image等前端资源(通常是由服务器来解决)
程序的性能优化(如数据读写)
采用CDN来加速资源加载
对于JS DOM的优化
HTTP服务器的文件缓存
你有什么想问我的
公司常用的技术栈是什么?
你们如何测试代码?
你们如何解决线上故障?
你们如何准备故障恢复?是否有完善的发布机制?
公司是否有技术分享交流活动?有的话,多久一次呢?
一次迭代的流程是怎么样的?从 PRD 评审开始到发布这一整个流程。
公司技术团队的架构和人员组成?
有公司级别的学习资源吗?比如电子书订阅或者在线课程?
你们认为和竞品相比有什么优势?