目录
目录
Html相关
- 什么是文档流?
文档流(Normal Flow):也叫作普通流/正常流,相对于盒子模型来说的,就是html元素默认在页面中的排版布局,比如div块级元素是从上到下,span等行内元素从左到右排列。
脱离文档流:就是将元素从排版布局中脱离出来,脱离文档流的方式:position中的absolute和fixed,还有float属性。
文本流:相对于文字段落来说的,是指html中文本的排版显示
- 什么是dom什么是bom?
DOM:Document Object Model是文档对象模型,DOM遵循W3c的标准,定义了如何访问html文档元素,并允许脚本动态对文档进行操作,根比如document.getElementById(),getElementByName()等
BOM:Browser Object Model是浏览器对象模型,暂时还没有相关的标准,但是现代的浏览器都已经实现了获取和设置浏览器的一系列的操作,BOM包含windows(窗口)、navigator(浏览器)、screen(浏览器屏幕)、history(访问历史)、location(地址)等
- 什么是web worker和websocket
web worker:是html5的一个新特性,让web应用程序可以具备多线程的处理能力,可以运行在后台的javascript,而不会影响页面其他正常处理和显示,可以将复杂需要时间的处理用web worker来处理。它的应用场景是,可以把一些阻塞页面渲染的一些js计算放到web worker中去做。
1.通过 worker = new Worker( url ) 加载一个JS文件来创建一个worker,同时返回一个worker实例。
2.通过worker.postMessage( data ) 方法来向worker发送数据。
3.绑定worker.onmessage方法来接收worker发送过来的数据。
4.可以使用 worker.terminate() 来终止一个worker的执行。
web worker能做:
1.可以加载一个JS进行大量的复杂计算而不挂起主进程,并通过postMessage,onmessage进行通信
2.可以在worker中通过importScripts(url)加载另外的脚本文件
3.可以使用 setTimeout(), clearTimeout(), setInterval(), and clearInterval()
4.可以使用XMLHttpRequest来发送请求
5.可以访问navigator的部分属性
缺点:
1.不能跨域加载JS
2.worker内代码不能访问DOM
3.各个浏览器对Worker的实现不大一致,例如FF里允许worker中创建新的worker,而Chrome中就不行
4.不是每个浏览器都支持这个新特性
websocket:websoket是html5的一种新的网络协议,也是基于tcp的协议,它是持久的,可以持续在客户端和服务器端保持双工链接,服务器的更新可以被及时推送给客户端,不需要客户端再设置定时查询。
- img标签中title和alt有什么区别?
title是鼠标滑过图片弹出框提示的信息,alt是在图片未成功加载情况下显示的信息
Css相关
- 什么是css盒子模型?
在网页中,一个元素的空间构成主要包括内容(content),边框(border),内边距(padding),外边距(margin)这些构成,这些就像实际中的盒子一样,所以叫做css的盒子模型。
- 盒子模型box-sizing中content-box和border-box的区别?
比如div的width和height都是100px,padding是10px,如果用content-box是不包含padding和border的元素,实际的高和宽是120px;border-box是包含padding和border的,实际的高和宽是设置的100px
- 什么是flexbox布局?
弹性盒子布局,设置元素的display=flex,会影响其子元素的排列方式,会使块级元素不再独占一行。使用布局之后,其子元素无论多少都会在一行显示。并且通过设置一些属性能达到垂直居中,水平居中,对齐和排序等等,可以自由操作布局,当前所有的浏览器都支持,并且手机上在安卓和ios上也支持
- bfc是什么?
BFC(Block Formatting Context)是块格式化上下文,简单来说就是一个独立的渲染区域,在bfc内部的元素不会影响到外面的元素,因为他们隔离互不影响的。
示例场景:比如两个div,同时设置margin:100px;这时候上下两个div的距离不是200px,而是100px,两个的外边距会重叠,这时候就需要用bfc来解决,分别用一个有bfc的div包裹着,这个bfc的div可以设置成overflow:hidden;来触发bfc即可。
触发条件:
1.根元素 float属性不为none
2.position为absolute或fixed。
3.display为inline-block, table-cell, table-caption, flex, inline-flex。
4.overflow为hidden。
-
css的选择器有哪些呢?
ID 选择器, 如 #id{}
类选择器, 如 .class{}
属性选择器, 如 a[href="segmentfault.com"]{}
伪类选择器, 如 :hover{}
伪元素选择器, 如 ::before{}
标签选择器, 如 span{}
通配选择器, 如 *{}
- css的优先级?
!import > 内联样式 > ID 选择器 > 类选择器 = 属性选择器 = 伪类选择器 > 标签选择器 = 伪元素选择器 > 通配选择器
- 什么叫优雅降级和渐进增强?
其实就是向上兼容和向下兼容浏览器,优雅降级就是向下兼容,渐进增强就是向上兼容
- sass和less的区别?
1.定义变量的符号不同,less是用@,sass使用$
2.语法有些不同,sass支持if else条件判断,以及for循环,还支持function函数
3.编译环境不同,less是基于javascript,在客户端环境处理,sass是基于ruby的,在服务器环境端处理。
4.作用域不同,sass中的变量修改,会按照修改前后顺序赋值。 less是只要变量被修改了,全局再引用都是被修改过的了。
- px,em,rem的区别?
px:实际就是像素,px是是相对于显示器分辨率的
em:是相对父元素计算字体大小,如果父元素没有设置大小,会以body的字体大小或者浏览器默认大小来计算。
rem:称为root em,也就是说是以根节点来计算,它是以<html>根的字体大小来计算,不会依赖父元素,整个页面的字体大小设置好后都不会乱了。想多个端兼容,最好是使用rem。一般方便rem和px换算的话,html中定义font-size:62.5%,这样1rem就相当于10px了。
- 移动端怎么实现响应性布局?
1.在head标签中加一根meta标签,
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0">
2.使用媒体查询,即 @media 查询,媒体查询可以针对不同的屏幕尺寸设置不同的样式,通过控制screen的min-width和max-width。
3.使用rem来代替px,rem会根据html节点的字体大小来计算。而em呢是根据父元素节点大小,所以相对于还是rem更适合方便一些。
- link和@import的区别
两者都是外部引用css样式的方式,其他区别如下:
1.link是HTML提供的标签,不仅可以加载CSS文件,还可以定义rel连接属性,比如stylesheet,index,help,start,next,prev,contents等等;
2.@import是CSS提供的语法规则,只有导入样式表的作用;
3.link引用CSS时,在页面载入时可以同时加载;@import需要页面网页完全载入以后加载。
4.link支持使用js动态操作dom去添加删除标签;而@import不支持。
- css 中可以让文字在垂直和水平方向上重叠的两个属性是什么?
垂直方向:line-height
水平方向:letter-spacing
- css中怎么解决inline-block的空白间隙?
1.设置父元素的font-size为0,然后设置子元素的font-size。
2.父元素设置letter-spacing为负值,子元素设置letter-spacing:0px;即可。
3.子元素用margin-left来调整。
4.子元素用float:left;来布局。
- css中垂直居中的方法
1.设置固定的高度,然后line-height等于这个高度。
2.设置父元素position:relative;子元素设置为position:absolute;top:50%;transform:translateY(-50%);意思通过设置translateY为-50%,就是自身的偏移量往上一半。
3.父元素设置postion:relative;子元素设置positon:absolute;top:0;bottom:0;margin:auto;若想水平也居中,再设置个left:0;right:0;即可
4.使用flex布局,父元素设置display:flex;align-items:center;如果想水平居中,父元素设置justify-content: center;
5.父元素使用display:table;子元素使用display:table-cell;vertical-align:middle;
- 用css隐藏元素的几种方法
1.display:none;
2.visibilit:hidden;
3.opacity:0;
4.position:absolute;top:-999px;left:-999px;
5.transform: translateX(-500%);
- css英文首字母大写
比如:hello it's ok,使用text-transform:capitalize; 输出:Hello It's Ok
- CSS优化、提高性能的方法有哪些?
避免过度约束
避免后代选择符
避免链式选择符
使用紧凑的语法
避免不必要的命名空间
避免不必要的重复
最好使用表示语义的名字。一个好的类名应该是描述他是什么而不是像什么
避免!important,可以选择其他选择器
尽可能的精简规则,你可以合并不同类里的重复规则
- transition与animation的区别
他们虽然都可以做出动画效果,但是transition主要做简单的过渡效果,而animation可以做复杂的动画效果,在语法和用法上有一些区别。
transition是过渡属性,强调过渡,他的实现需要触发一个事件(比如鼠标移动上去,焦点,点击等)才执行动画,过渡只有一组(两个:开始-结束)关键帧。
animation是动画属性,他的实现不需要触发事件,设定好时间之后可以自己执行,且可以循环一个动画(设置多个关键帧)。
JavaScript相关
- js编译原理?以及什么是ast
js是一种动态解释型语言,包含有:编译器(负责语法分析以及代码生成),引擎(负责js程序的编译和执行过程),作用域(负责收集并维护所有生成的标识符(变量),并实施一套非常严格的规则,确定当前执行的代码对这些变量的访问权限。
编译的顺序:
1.词法解析,将代码字符串分解为词法单元,比如定义一个变量,var num = 10; 会逐个拆分。
2.语法分析,将词法单元转换成一棵由元素逐级嵌套的程序语法结构的树,也叫作抽象语法树,也就是AST,
3.生成代码,js引擎将抽象语法树AST转换为一组机器可执行的指令,比如创建变量,分配内存等
- js数据类型都有哪些?
基本数据类型:字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol。
引用数据类型:对象(Object)、数组(Array)、函数(Function)。
- typeoff的返回值都有哪些呢?
有:string,number,boolean,object,undefined,function,ES6新增了symbol
- js变量命名规则?
1.常用骆驼命名法,首字母小写。
2.以字母,下划线,$符号开头,不能以中文,空格,特殊标点符号,数字开头。
3.变量命名尽量简洁和意思明了,不能过长。
4.不能使用js里面的关键字命名。
- es6去重方法?
Array.from(new Set([1,1,2,3]))
[...new Set([1,1,2,3])]
- typeof 和 instanceof 的区别?
1.typeof可以判断一个变量是否为空,可以判断变量是属于哪个数据类型,比如返回number,string这些。注意的是对于 Array,Null 等特殊对象使用 typeof 一律返回 object,typeof undefined是返回undefined。
2.instanceof是判断一个变量是否属于某个对象的实例,比如:[] instanceof Array,输出true
- 什么是闭包?
闭包是指一个能够读取其他函数内部变量的函数。
优点:1.变量在内存中,可以提高性能。2.避免全局变量的污染。3.可以保护私有成员变量。
缺点:1.因为变量可以一直在内存中,会内存消耗大,也可能会导致不会被垃圾回收,所以在使用完之后把变量赋值为null。
- js中作用域有哪些?
1.全局作用域:声明在函数外部的变量,在代码中任何地方都能访问的到(没有用var声明的变量属于全局变量哦)
2.函数作用域:函数内声明的所有变量在函数体内始终是可见的,可以在整个函数的范围内使用。
3.块级作用域:是es6有的一个概念,通过一对{}花括号定义的代码块,在这里定义的所有变量在代码块外面都是不可见的,这个就叫块级作用域。使用let和const定义的变量,只会在这一范围内起作用,也不会存在变量提升。
- 什么是变量提升?
js引擎在编译代码的时候,所有使用var声明的变量,都会被提升到当前作用域的顶部。同样函数也是会存在提升的。
- 什么是暂时性死区?
let和const是块级作用域,声明的变量不会存在变量提升,在未声明之前就使用变量就会报错,所以在代码块内,使用let和const声明变量,先声明后使用是不行的,这在语法上称为‘暂时性死区‘,简称TDZ。
- Array对象的属性有哪些?
constructor:返回对创建此对象的数组函数的引用。
length:设置或返回数组中元素的数目。
prototype :使您有能力向对象添加属性和方法。
- Array对象方法有哪些?
concat() 连接两个或更多的数组,并返回拼加后的新数组。
pop() 删除数组最后一个元素,并返回该删除的元素。
shift() 删除数组第一个元素,并返回该删除的元素。
unshift() 向数组的开头添加一个或更多元素,并返回新的长度。
push() 向数组的末尾添加一个或更多元素,并返回新的长度。
reverse() 颠倒数组中元素的顺序。
slice() 通过下标截取数组
splice() 删除或者替换数组元素
fill()将一个搞定的值填充一个数组中从开始位置到起始位置的所有元素
keys() 返回一个可以迭代的对象
sort() 对数组的元素进行排序
from()将一个类似数组或可迭代对象转换成一个数组
some()遍历时候,只要有一项满足,就返回true
every()遍历时候,全部都满足,才返回true
forEach()遍历数组
map()对数组中的每个元素进行处理,得到一个新的数组
filter()返回满足条件的数组元素
includes()判断数组中是否包含某一个值,会返回true和false
indexOf()判断数组中包含某一个值 ,存在则返回下标,不存在就返回-1
join()将数组中内容按照某个字符串分割,并返回分割后的字符串。
isArray()判断传递的对象是否是一个数组类型
toString()把数组转化为字符串
- 对象和类的区别?
类是对象的抽象,对象是类的实例,对象是实际存在的,有对应的行为和属性。
- ["1","2","3"].map(parseInt)的结果是多少?
答:[1,NaN,NaN],
['1','2','3'].map(parseInt)即
parseInt('1',0);radix 为 0,parseInt() 会根据十进制来解析,所以结果为 1;
parseInt('2',1);radix 为 1,超出区间范围,所以结果为 NaN;
parseInt('3',2);radix 为 2,用2进制来解析,应以 0 和 1 开头,所以结果为 NaN。
- 介绍一些es6的特性
1.块级作用域:let,const。
2.变量解构赋值:如let [a,b]=[1,2],输出是a=1, b=2
3.字符串的扩展:比如新增includes(),startsWith(),endsWith(),padStart(),padEnd(),matchAll(),字符串模版等。
4.函数的扩展:箭头语法,双冒号运算符(可以像bind一样将冒号前面的对象绑定到冒号右边,比如 foo:bar 相当于 bar.bind(foo))
5.数组和对象的扩展:新增了扩展运算符(...),用来合并数组和对象,不过这种是浅拷贝,数组的方法也新增了from(),fill(),includes()等方5.法,对象也新增了Object.is(),Object.assign()浅拷贝的哦,Object.keys(),Object.values()等。
6.新增了Symbol原始数据类型。
7.新增了Set和Map,WeakSet,WeakMap,Set里面的值是不会重复的,WeakSet只能存对象,WeakMap只能接受对象和null作为key。
8.新增了Promise对象,用来处理异步操作,可以通过then链式调用,来控制异步代码执行顺序。
9.新增了Generator和Async和await来处理异步,和Promise一样的作用,async返回的其实就是一个Promise对象。
10.新增了Class的语法,可以用extends来实现继承。
11.es6的import,export语法来实现模块化,和commonJS的module是一样作用的。
- es6中set和map区别?
set是没有元素可以重复的,map是键值对可以允许重复
- this指向问题?
普通函数:只要是普通函数,即使是在箭头函数里面的普通函数,也是指向的window。严格模式下使用 "use strict" 声明后,输出this是undefined。
实例化对象或者字面量对象:这种是该对象调用了,this就指向这个对象,如果对象里面有一个普通函数调用了,还是指向的window,如果是箭头函数调用了,就指向当前的这个对象。
箭头函数:根据所在的环境,在哪个环境就指向谁。
- 什么是函数柯里化?
柯里化(Currying)是把接受多个参数的函数变换成嵌套着接受一个单一参数的函数,并返回一个函数接受剩下的参数。这中间可嵌套多层这样的接受部分参数的函数,直至返回最后结果。
例如:
function add(a){
return function(b){
return function(c){
return a+b+c;
}
}
}
console.log(add(1)(2)(3));
输出结果:6
- call和apply的区别?
1.apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, argsArray); 即A对象调用B对象的方法。
2.call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2); 即A对象调用B对象的方法。
3.参数不同,call可以接受多个参数,apply职能接受的一个数组参数。
4.call和apply可以重新修改this的指向。
- 怎么让一个构造函数的实例 instanceof 它为false?
主要是直接修改对象的prototype就可以了,就不是同一个实例了,比如下面:
function Cat(){
this.name='cat'
}
var cat = new Cat();
Cat.prototype ={
say:function(){
console.log('a cat')
}
}
console.log(cat instanceof Cat) // 这里输出false
- 什么是构造函数?
构造函数也是普通的函数,只不过会通过new来调用并创建一个新的实例,这个函数就叫做构造函数。
- 构造函数的执行流程?
1.立刻在堆内存中创建一个新的空对象
2.让this指向这个对象
3.执行构造函数里的代码,给这个新的空对象添加属性和方法
4.返回这个新的对象
- 什么是原型和原型链?
原型:所有的函数都有一个prototype属性,这个就叫原型,也称为显示原型。我们用构造函数创建的对象会有prototype原型上面所有绑定的方法。
原型链:当我们用obj.xxx访问一个对象的属性时,会先在对象自身属性中查找,如果没有找到,再沿着__proto__这条链向上层去找,这样一层一层的查找就会形成一个链式的结构,就叫做原型链。如果找到原型链的顶层Object.prototype还没有,就返回null,也就是 Object.prototype.__proto__ === null。
- prototype 和 __proto__ 的区别?
①prototype(原型)是构造函数才有的属性,可以叫做显示原型,它实例化的对象包含prototype上所有共享的方法。(当构造函数new实例化一个对象时候,它实例化对象的__proto__指向了它构造函数的prototype);
②__proto__ 是对象(不论是普通对象还是构造函数实例化的对象)才有的属性,可以叫做隐式原型,用于指向创建它的构造函数的原型对象。(对象的__proto__会指向它构造函数的prototype);
function foo(){}
var f = new foo();
// 该实例化的对象的__proto__指向了其的构造函数prototype
console.log(f.__proto__ === foo.prototype) // 输出:true
var obj = {}
// __proto__指向构造函数的prototype
console.log(obj.__proto__ === obj.constructor.prototype) // 输出:true
- 怎么用js给元素添加class?
// 为 <div> 元素添加 class:
document.getElementById("myDIV").classList.add("mystyle");
// 为 <div> 元素添加多个类:
document.getElementById("myDIV").classList.add("mystyle", "anotherClass", "thirdClass");
// 为 <div> 元素移除一个类:
document.getElementById("myDIV").classList.remove("mystyle");
// 为 <div> 元素移除多个类:
document.getElementById("myDIV").classList.remove("mystyle", "anotherClass", "thirdClass");
// 为 <div> 设置属性
document.getElementById("myDIV").setAttribute("title","this is a title");
- js哪些情况会造成内存泄漏?
1.大量声明使用全局变量。2.闭包引起的内存泄漏。3.dom清空或者删除时候,绑定的事件未清除。4.定时器未被清除。5.子元素存在引用。
- js中垃圾回收的策略?
标记清除:
当变量进入环境时,将变量标记"进入环境",当变量离开环境时,标记为:"离开环境",这种标记离开环境的就回收内存。
引用计数:
机制就是跟踪一个值的引用次数,当声明一个变量并将一个引用类型赋值给该变量时该值引用次数加1,当这个变量指向其他一个时候,该值的引用次数便减一,当该值引用次数为0时就会被回收。
- js中undefined和null区别?
这两个的值是不相等的,即undefined === null 是 false。undefined表示变量定义了未赋值,null表示变量的引用是空的。
注意(null == undefined)为true,是成立的,因为在ecmascript规范中,null和undefined的行为很相似,都表示一个无效的值,所以它们是相等的。
- commonjs,amd,cmd的区别?
CommonJS, AMD, CMD都是JS模块化的规范。
1.CommonJs 是服务器端模块的规范,Node.js采用了这个规范。 根据CommonJS规范,一个单独的文件就是一个模块,加载模块使用require方法,CommonJS 加载模块是同步的,所以只有加载完成才能执行后面的操作。
var clock = require('clock');
clock.start();
2.AMD(Asynchronous Module Definition) 是 RequireJS (这里可以简记AR)定义的规范 ,AMD异步加载模块,AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块 。
require([module], callback);
3.CMD(Common Module Definition)是SeaJS (这里可以简记CS)定义的规范。CMD推崇就近依赖,只有在用到某个模块的时候再去require模块 。
require(['clock'],function(clock){
clock.start();
});
- require和import的区别?
1.require是commonJS的规范
2.import是es6中的语法
3.require是运行时动态加载,import是编译的时候调用
4.require输出的是一个值的拷贝,import输出的值是引用
- js中深拷贝和浅拷贝区别?
1.浅拷贝的对象和原对象的引用是同一个,当源对象发生改变,浅拷贝的对象也会改变。object.asign和...运算符属于浅拷贝
2.深拷贝是完全创建一个新的引用,可以用JSON.stringify和JSON.parse来实现,或者手动写函数,递归遍历对象,重新赋值个新的拷贝后的对象
- 什么是事件流?
也就是事件处理的流程,是有先后执行顺序的,标准的事件流它分为3个阶段:事件捕获 》事件目标 》事件冒泡
- 什么是事件模型?
就是事件的一个标准模型,分为3个模型。分别是:
1.原始事件模型(DOM0)
在原始事件模型中,事件发生后没有传播的概念,也没有事件流的产生,事件发生后就马上处理然后结束,比如:
document.getElementById("btn").onClick=function(){alert('hello')}
2.IE事件模型
这个是在ie系列浏览器里支持的,ie中的事件流不是标准的,它只有事件目标和事件冒泡,没有事件捕获,ie中创建事件是用attachEvent('onclick',function(){});移除用detachEvent('onclick',function(){}): 注意的是ie中组织事件冒泡的方法是获得event对象,这个event对象是用的全局变量window.event获得的,而且函数执行完毕,这个event就是null了。
3.DOM2事件模型
这个模型是W3C指定的标准模型,我们现在用的浏览器都是按照这个标准,在W3C指定的事件模型中,一次事件的发生包含3个过程:
* 事件捕获(事件被从document一直向下传播到目标元素,在这过程中依次检查经过的节
点是否注册了该事件的监听函数,若有则执行。)
* 事件处理阶段(事件到达目标元素,执行目标元素的事件处理函数)
* 事件冒泡阶段(事件从目标元素上升一直到达document,同样依次检查经过的节点是否注册
了该事件的监听函数,有则执行。)
添加事件:document.getElementById('div').addEventListener('click',function(){},false)
addEventListener第三个参数是false就是事件冒泡,是true就是事件捕获。
删除:removeEveentListener('click')
- 什么是事件委托?
说到事件委托,其实也是事件代理,都是表示有一个第三方去做某件事情。
委托就是通过事件冒泡机制,把事件监听函数绑定到父元素上,在父辈元素的监听函数中,可通过event.target属性拿到触发事件的原始元素,然后再对其进行相关处理。
举个例子,比如我们去饭店吃饭,小明说想吃蛋炒饭,小花说想吃牛肉面,小明和小花不可能直接告诉厨师吃什么,人多的话厨师记不清,这时候服务员出来了,服务员记录下来小明和小花想吃的饭,然后报给厨师,做好后,服务员根据做好的饭和订单上对应(event.target判断),依次给小明和小花, 这个服务员就是个委托,也是代理。
- 同源策略是什么,还有跨域是什么?
同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以a.com是读取不了b.com下面的资源。
不受同源策略限制的有:
1、页面中的链接,重定向以及表单提交是不会受到同源策略限制的。
2、跨域资源的引入是可以的,如嵌入到页面中的<script src="..."></script>,<img>,<link>,<iframe>等。
跨域就是前面说的同源策略影响的解决办法,就是跨域。
跨域的方式有:
1.jquery ajax的jsonp跨域,通过设置回调。
2.通过docuemnt创建script,通过回调函数获取返回数据
2.通过修改document.domain来跨域。
3.cors实现跨域,主要是后端配置Access-control-allow-origin来实现。
4.nginx做代理也可以实现,配置proxy_pass地址。
5.在开发环境下也可以实现,比如可以在package.json中配置proxy。
具体也可以参考:https://segmentfault.com/a/1190000011145364
- 什么是作用域?什么是作用域链?
作用域:作用域其实就是变量或者函数起作用的范围,比如定义一个var a在一个函数里,那这个a的作用域就是在这个函数里,外面是访问不到的。
作用域链:是javascript内部中一种变量、函数查找机制。进入执行环境后,访问一个变量时候js引擎会在当前作用域往上去找,直到找到global全局作用域为止,和原型链有一点相近,也是逐级往上去寻找,但是作用域链的顶层是window。
- 栈和堆的区别?
栈(stack)会自动分配内存空间,会自动释放,栈先进后出。堆(heap)动态分配的内存,大小不定,也不会自动释放,一般是手动释放,也可以由垃圾回收机制回收。
1.基本数据类型是直接值存到栈中的,占用一定的空间。
2.引用类型类型的数据实际存储是放到堆中,然后在栈中会存一个地址(指针),通过栈中的地址去堆中获取真正的值。
- js异步加载的方法
1.在script标签中使用async属性,虽然可以实现,但是它是乱序执行的,只要加载完了就会执行,所以不能保证执行顺序。
2.在script标签里使用defer属性,对脚本进行延迟,直到页面元素加载完成为止,而且它是按照加载顺序执行脚本的
3.动态生成script标签,在onload里动态使用document生成标签。也可以用jquery的ready函数执行,
- js中创建对象的方式有哪些?
1.直接通过字面量创建var obj = {};
2.直接通过new Object()方式创建。
3.工厂模式
4.构造函数模式
5.原型模式
6.组合模式(原型和构造函数)
- js中实现继承的方式有哪些?
1.原型链继承。
2.es6的extends继承。
3.构造函数继承。
4.组合继承。
5.寄生式继承。
- JS中的== 与 ===的区别
==:叫做相等运算符,比较时候会进行类型转换,值相等就是相等。
===:叫做严格运算符,只要类型不用,就不会相等。
-
sessionStorage 、localStorage 和 cookie 之间的区别?
共同点:都是保存在浏览器端、且同源的
区别:
1、创建方式不同:cookie是由服务器端创建,发送客户端,当用户发送请求后,会在http请求中携带传递到服务器端。而sessionStorage和localStorage是创建保存在客户端,也不会自动把数据发送给服务器。
2、存储大小不同:cookie数据不能超过4K,只适合保存很小的数据,比如会话标识。sessionStorage和localStorage本地存储可以达到5M以上。
3、数据有效期不同:sessionStorage:仅在当前浏览器窗口关闭之前有效;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭 。
4、作用域不同:sessionStorage只能在同一个浏览器页面中有效,或者打开链接和用window.open新打开一个页面也可以有效的,除了这些其他的情况都是不能共享的;localstorage和cookie都可以在所有同源窗口中都是共享的;
5、web Storage支持事件通知机制,可以将数据更新的通知发送给监听者,具体是在页面添加监听事件:window.addEventListener("storage", handleStorage, false);
6、web Storage的api接口使用更方便,比如setItem,getItem,removeItem,clear都可以很方便的操作。cookie必须自己手动封装。
- 原生ajax的工作原理?
var xhr = new XMLHttpRequest(); // 创建xmlHttpRequest对象
xhr.onreadystatechange=function() {
if (xhr.readyState==4 && xhr.status==200)
// 服务器正常响应后,获取返回数据
}
xhr.open('get','http://222.11.11.2/getUser?id=1',false);//通过发送get或者post请求到服务器的url地址, 第三个参数是是否async,true是同步,false是异步
xhr.send(); // 发送
- js中eventloop是什么?
event loop称为事件循环机制,javascript是单线程的,js中所有的任务都需要按顺序一个一个的执行,但是一个任务消耗太长,后面的任务就需要等待,为了解决这种情况,javascript把任务分为两种,一种是同步任务,一种是异步任务,同步任务会在主线程排队执行的任务;异步任务是会进入到任务队列task queue,任务队列还分为宏任务macro-task(setTimeout(),setInterval(),script块,Promise构造函数是宏任务)和微任务micro-task(Promise,process.nextTick(),Promise的then和catch是微任务)。当主线程中的任务执行完毕之后,会不断读取异步任务队列中的任务来执行,这就是事件循环。
执行异步任务队列中任务时候,如果有微任务了会先执行完所有的微任务,再执行下一个宏任务,没有微任务就会执行宏任务。
- 什么是防抖和节流?
防抖:如果设定的时间到来之前,就连续触发事件,就重新开始延时执行事件。
// 函数防抖
var timer = false;
document.getElementById("debounce").onscroll = function(){
clearTimeout(timer); // 清除未执行的代码,重置回初始化状态
timer = setTimeout(function(){
console.log("函数防抖");
}, 300);
};
节流:当持续触发事件时,保证一定时间段内只调用一次事件处理函数。
// 函数节流
var canRun = true;
document.getElementById("throttle").onscroll = function(){
if(!canRun){
// 判断是否已空闲,如果在执行中,则直接return
return;
}
canRun = false;
setTimeout(function(){
console.log("函数节流");
canRun = true;
}, 300);
};
- 什么是解构赋值?
解构赋值语法是一种js表达式,它使得将值从数组,属性,对象中提取到不同变量里。
比如:[a,b]=[10,20],结果是a=10,b=20;
- js里求出数组中的最大值
1.使用for循环来比较
let num = 0;
for(let i = 0;i<array.length;i++){
if(i>num){
num=i;
}
}
2.使用es6的语法
var n = Math.max(...array)
- js实现数字千分位
第一种:直接用数字的原型方法
var num = 123456789;
num.toLocaleString();
第二种:使用正则
var num = 123456789;
var str = num.toString().replace(/(?=(?!(\b))(\d{3})+$)/g,",");
ReactJs相关
- react是什么?
React 是一个用于构建用户界面的 JAVASCRIPT 库。 React主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图),React是Facebook开发的一个项目,它是单向数据流的,和vue数据双向绑定不同。
- react组件之间都是独立互不影响,state也是组件独立的,如果发生多次渲染,react的render函数自会渲染发生变化的地方,组件之间也是可以互相嵌套的。
- react中使用函数组件和class创建组件的区别?
1.函数组件只能接收props。
2.使用es6 class创建的可以不单可以使用props,还可以使用this,和state,以及生命周期函数。
- react中怎么绑定this?
1.在constructor里bind
constructor(props){
super(props);
this.handleClick=this.handleClick.bind(this);
}
2.使用属性初始化器语法
handleClick = () =>{}
3.在元素中的事件使用箭头函数
<div onClick={(e)=> this.handleClick(id,e)}>click me</div>
4.在元素的事件中也可以使用bind
<div onClick={this.handleClick.bind(this,id)}>click me</div>
- react中的虚拟dom和diff算法理解
1.虚拟dom其实就是用一个对象来描述dom树,对数据和状态的变更会同步到虚拟dom上,通过计算新旧虚拟dom的差异,最终把变化的部分重新渲染。
2.diff算法是实现比较虚拟dom差异的一个算法,它可以对虚拟dom进行逐层的比较,如果树类型不同,就会重新创建,如果类型相同,属性不同,就会只更新属性不同的部分,如果在子节点后新增节点,会直接增加节点,如果在子节点前增加节点,会重新生成这几个节点。
3.给节点加key,key更方便diff算法计算出来节点之间的差异。
- 什么是高阶组件?高阶组件就是一个没有副作用的纯函数,且该函数接受一个组件作为参数,并返回一个新的组件。
- 什么是高阶函数?高阶函数是一个可以接受函数作为参数,并返回一个新的函数。
- 什么叫纯函数?一个函数的返回结果只依赖于它的参数,并且不会对别的对象产生副作用,就叫做纯函数。
- react中component和element的区别?
element:元素是构成react应用的最小单位,用来描述页面上看到的内容,可以用jsx语法创建一个元素,比如const element=<div>hello</div>,与浏览器dom元素不同的是,react中的元素实际上是普通的对象,所以没有办法调用dom原生的api。
component:组件就是一个方法或者一个类,可以接受任意的输入值(称之为props),并且返回一个需要在页面上展示的react元素。
- 什么是redux框架?
Redux是一个流行的JavaScript框架,为应用程序提供一个可预测的状态容器。
那什么是可以预测化,我的理解就是根据一个固定的输入,必然会得到一个固定的结果。
核心概念,三大原则:①单一数据源 ②state是只读的 ③使用纯函数执行修改
处理流程,主要是action,reducer,store,
组件dispatch一个action,然后到reducer,reducer是一个纯函数,它接收到这个action,根据action的类型,来更新状态。
缺点:
1.修改一个state可能要动4,5个文件,修改复杂。
2.每次dispatch一个action都会遍历所有的reducer,重新计算connect,很费效率。
3.如果store较大时候,频繁的修改store,会明显看到页面卡顿。
4.不支持typescript。
- thunk和saga是什么?
thunk和saga是redux的异步解决方案,thunk可以接受一个函数并且可以在里面dispath action,但是缺点是action的调用会分散在各个文件中,不易管理。saga的优点是action统一管理,集中处理异步操作,但是个人觉得saga可能初学起来不是太容易,需要先学习es6的yield和async以及await语法。
- 什么是mobx?
mobx是一个简单的可扩展的状态管理框架。它通过@observable定一个被观察的状态数据,state的修改是在action函数中进行,并且提供了computed,通过get和set也可以计算state,它比起redux更加的简洁明了,在页面中是通过@inject("store")注入store,并且把组件@observer变为观察的组件。
- redux和mobx的区别在哪里?
这两个框架都是可以做react状态管理的,mobx很简洁,上手很快,原理也是比较简单,从页面发起action到对应的action去处理state,大量使用了装饰器语法。不需要花大量的时间去研究即可上手编写。
redux则比较庞大一点,它的衍生出来的框架也有thunk和saga,学习saga需要学习es6的await,yield,async语法,学习成本和维护成本高一点。
redux是单数据源的,其中一个原则是单一数据源,你需要将所有的state放到一个全局的store里面,而mobx相反,它可以@observable观察多个state,也就是可以由多个数据源。
- react的生命周期
分为4个阶段:初始化阶段,挂载阶段,更新阶段,卸载阶段
初始化阶段:
defaultProps={}:设置默认的props
constructor() :这里可以获得props和初始化state
挂载阶段:
componentWillMount() :组件被挂载到页面之前调用,这时候还无法获取dom对象。
render() :渲染组件到页面中,这里注意不要使用setState,否则会递归渲染。
componentDidMount():组件已经挂载到页面,dom也可以获得到,也可以发送ajax请求,也可以修改state状态,但是注意这里修改状态会重新渲染。
更新阶段:
componentWillReceiveProps() :组件接收到新的props会触发这个方法,修改state不会触发这个。
shouldComponentUpdate() :这个方法返回true和false,来决定是否重新渲染组件,性能优化就是在这里进行。
componentWillUpdate() :组件将要更新时候调用。
render() :重新渲染组件,这个函数能够执行多次,只要组件的属性或状态改变了,这个方法就会重新执行
componentDidUpdate():组件已经被更改过了,会调用这个方法。
卸载阶段:
componentWillUnmount():组件将要卸载时调用,一些事件监听和定时器需要在此时清除。
- react性能优化建议
1.bind函数的使用,在constructor中bind进去,因为构造函数每次渲染只会执行一次,在jsx模版中bind会每次render都会执行。
2.shouldComponentUpdate里进行优化,这个钩子可以返回true和false,false的话就是不渲染,可以在这里面决定是否渲染组件。
3.组件继承React.PureComponent,因为它比React.Component性能更好,当props和state改变的时候,PureComponent会对它们进行浅比较,来决定是否渲染组件,而Component不会进行比较,当shouldComponentUpdate被调用时候,组件默认会重新渲染。
4.使用redux和mobx这些框架来管理状态。
5.props尽量只传递需要的数据,多余的就尽量不要代入过去了。
6.如果有组件循环,需要指定key。
- react是怎么检测数据变化?
react是单向数据流,所以不像vue和angular一样可以自动实现检测到数据变化,react是需要主动触发数据变化,比如setState时候,就可以触发更新。
VueJs相关
- vue是什么?
vue是一套用于构建用户界面的渐进式框架,它的核心是数据驱动和组件化。
代码简洁体积小,运行效率高,上手快。
- 什么是渐进式框架?
我们可以只用我们想要的一部分功能,非侵入性的,而不是必须强制注入其他不相关的依赖。
- 简述vue响应式原理?
当vue的实例被创建的时候,Vue 将遍历data中所有的属性,并使用Object.defineProperty劫持将它们全部转为getter/setter,vue追踪它们内部的相关依赖,在属性被访问和修改时候通知变化。
每个组件都对应一个watcher实例,它会在组件渲染过程中把接触过的属性记录为依赖,之后当依赖项的setter触发时候,会通知watcher,使关联的组件会重新渲染。
弊端:1.劫持需要递归遍历消耗比较大。2.对新增和删除属性没有数据劫持的,无法监听到,需要用vue.$set().3.数组的一些方法也不能监听到,比如数组的filter(),concat(),slice()
- Vue3响应式原理?
主要是使用了es6的Proxy来对数据进行代理拦截,Proxy对象接受两个参数,target和handler,handler可以对对象进行一些拦截处理,提供了有get,set,has,apply,construct,deleteProperty、defineProperty等13种方法。
通过判断当前的Reflect.get返回值是Object类型,则再通过reactive方法做代理,这样就实现了深度观测。
- vue框架的优点?
(1)轻量级框架:只关注视图层,大小只有几十Kb;
(2)简单易学:文档通顺清晰,语法简单;
(3)数据双向绑定,数据视图结构分离,仅需操作数据即可完成页面相应的更新;
(4)组件化开发:工程结构清晰,代码维护方便;
(5)虚拟 DOM加载 HTML 节点,运行效率高。
- Vue如何监测数组变化的?
同样也是通过Object.defineProperty数据劫持,引起数组变化的方法有pop,push,shift,unshift,splice,sort,reverse这7种。Vue重写了数组的原型方法,在调用数组这几个方法改变数组时候能被监测到,然后相关依赖的视图内容会更新了。
- Vue的事件绑定原理?
1.原生dom的绑定:在updateDOMListeners方法里面,对原生的dom元素用addEventListener方法来添加事件
2.组件绑定事件采用的是Vue中的$on方法
- vue的生命周期?
分为4个步骤,创建,挂载,更新,销毁。
1.创建
beforeCreate();
created(); // 初始化的内容写在这里,比如请求ajax进行数据处理
2.挂载
beforeMount();
mounted(); // dom渲染在这里就已经完成了,可以获取到dom节点
3.更新
beforeUpdate();
updated();
4.销毁
beforeDestroy();
destroyed();
第一次页面加载会触发:beforeCreate,created,beforeMount,mounted这几个钩子函数,而且dom渲染在mounted中就已经完成了。
- vue中的$nextTick()的理解?
在vue的created()钩子中操作dom,需要用到$nextTick()这个函数,因为这时候dom元素还没有渲染完毕,我们取dom元素是取不到的,这个函数是可以在dom更新之后,把操作放到它的回调函数里。它其实就是一个异步任务来做延迟,底层是使用了event loop中的微任务和宏任务,做了设备api的兼容,如果支持Promise,会优先使用Promise.then(微任务)来实现延迟,如果不支持就用普通的setTimeout(宏任务)来实现了。
- vue怎么监听键盘事件?
直接在生命周期里绑定document.οnkeydοwn=function(e){}即可。
监听事件除了keycode对应的数字之外,vue还添加了事件的别名,比如enter,tab,delete,esc,space等。
- vuex是什么?
vuex是一个专门为vuejs设计的状态管理工具,在状态比较多难以管理的时候就用它。
state:状态数据,可以通过modules来配置多个数据源操作。
getter:返回计算处理state后的函数,相当于vue中的计算属性。
mutations:真正处理state的地方,并且mutation必须是同步函数。
action:用户提交的action操作,view 层通过 store.dispath
来调用 action。Action提交的是mutation,而不是直接变更状态,Action可以包含任意异步操作。
modules:如果管理状态的业务比较复杂,可以分为几个模块,最后在vuex中使用模块,引用的时候加上模块的名字即可。比如:
const moduleA = {
state: { name:'this is a name' },
mutations: { },
actions: { }
}
const store = new Vuex.Store({
modules: { moduleA }
})
this.$store.state.moduleA.name; // 使用的时候加上模块的名称
流程是;用户在view上dispatch一个action》vuex的actions接收到数据后commit到mutations》mutations更改state的数据状态》可以通过vuex提供的getters展示到view,也可以在view里this.$store.state.text来获取状态数据。
- vuex中的异步修改怎么实现?
需要在action中做异步处理,不在mutation中处理是因为vuex官网上也有说,mutation是必须是同步的函数,mutation操作写异步的话状态很难追踪,这样就会造成很多问题。Action和Mutation的区别是,action提交的是mutation,而不是直接操作state,action中是可以包含任何异步的操作。在action中同步就需要return new Promise(),或者是使用async来定义action,这样在异步处理的时候才会同步去执行。
- Promise是什么?
Promise是异步处理的一种解决方案,多个异步的处理不需要通过回调函数来处理,es6提供的promise处理后可以返回一个resolve,异步执行完后执行resolve()就会执行then里面的代码,这样使异步不再变得不可控,甚至可以多个then链式调用来控制异步代码的执行顺序。
Promise中有3种状态:
pending:初始状态,既不是成功也不是失败
fulfilled:意味着操作完全成功
rejected:意味着操作失败
同一时间只有一个状态存在,且状态改变就不能再变了,当调用resolve()时候会执行后面的then,当执行reject()就不会继续进行下去。
- vuex如何缓存,在页面刷新时候不丢失
登录等信息存储的数据保存到sessionStorage中最好,长久保存的信息保存到localStorage中,当刷新页面时候,重新合并获取到的数据到store中。
- vue模板编译原理?
参考:https://segmentfault.com/a/1190000013763590
1.解析器将模板字符串转换成AST抽象语法树(Abstract Syntax Tree)
2.对AST抽象语法树进行静态节点标记(主要用来做虚拟DOM的渲染优化,标记静态节点好处是:每次重新渲染,不需要为静态节点再创建新的,可以跳过虚拟DOM中patching打补丁的过程)
3.代码生成器会将AST生成render函数代码字符串
4.render函数的返回值就是vnode虚拟节点
- Vue中的diff算法
diff算法是比较虚拟dom差异的一个算法,它可以对虚拟dom进行逐层的比较,如果树类型不同,就会重新创建,如果类型相同,属性不同,就会只更新属性不同的部分,如果在子节点后新增节点,会直接增加节点,如果在子节点前增加节点,会重新生成这几个节点,而且diff在比较新旧节点的时候,只会同级进行,不会跨层级比较。
- vue和react的区别?
相同点:
1.都可以做spa单页面应用。
2.都支持服务器端渲染
3.都有Virtual Dom,页面的操作数据会反应到虚拟dom上,通过diff算法计算后再渲染到页面。
4.都有组件,都有props,并且支持父子组件之间通信,也都有状态管理工具,react的redux,mobx和vue的vuex。
5.都有生命周期。
不同点:
1.react是mvc框架,vue是mvvm框架。
2.react是单向数据流,用事件来操作数据改变状态,vue是双向数据绑定,通过数据劫持和订阅者观察者来实现。
3.写法不同,react用的是jsx模版,vue就像是写一个普通HTML页面一样,同时可以包含有css和js。两者在渲染数据,更改data是不一样的写法,react渲染是必须return元素在下面引用,vue是直接在标签上用指令就可以,react用setState设置数据,vue直接用等号就可以。
4.数据发生改变,vue会自动跟踪组件的依赖 关系,不需要重新渲染组件数。而react则状态改变,全部组件都会重新渲染,所以需要在shouldComponentUpdate这个生命周期里来优化
- vue中更新数组时,可以触发视图更新的方法有哪些?
会更新视图的方法:push(),pop(),shift(),unshift(),splice(),sort(),reverse(),还可以使用Vue.set( target, key, value )
不会更新视图的方法:filter(),concat(),slice()
- mvc和mvvm的区别?
mvc:(Model模型-View视图-Controller控制器),mvc是最经典的开发模式之一,流程是用户操作,view层负责接收输入,然后到Controller控制层,对Model数据进行处理,最后将结果通过View反馈到用户。mvc的通信是单向的,简单说就是:
用户-View-Controller-Model-Controller-View,缺点是:M和V层耦合度高,所有逻辑都在C层,导致庞大难以维护。
mvvm:(Model模型-View视图-ViewModel视图模型),也就是数据双向绑定模型,Model和View之间解耦,通过ViewModel进行交互,它就是一个同步View和Model的对象,View和Model之间的同步是自动的,不需要人为干涉,开发者只需要关注业务逻辑,不需要手动操作Dom。
- vue中的keep-alive是什么?
概念:它是vue的一个内置组件,主要作用是可以缓存组件,避免重新渲染。
它是一个抽象组件,不会被渲染到真实DOM中,它提供了include与exclude两个属性,允许组件有条件地进行缓存。
原理:其实就是在created时将需要缓存的VNode节点保存在this.cache中,在render时,如果VNode的name符合在缓存条件(可以用include以及exclude控制),则会从this.cache中取出之前缓存的VNode实例进行展示。
- 什么遍历的时候使用key?
因为可以给每个遍历元素添加一个唯一标识,可以让diff更快的计算出来进行渲染。
- 怎么让css只在当前组件起作用
在当前的vue页面中的style标签纸红加上scoped即可,如:<style scoped></style>
- vue的两个核心是什么?
数据驱动和组件化
数据驱动:简单可以解释为数据(Model)的改变,使视图(View)自动更新。也就是数据双向绑定,Model的改变会通过ViewModel改变View,同时也会监听View的变化,也会通过ViewModel响应到数据Model,实现数据双向绑定。
组件化:组件化实现了可扩展和可重用可维护的html元素,通过封装可用的代码,页面上每个独立交互的功能都可以抽取出来成一个组件。
- vue的http请求都有哪些框架,ajax、axios、fetch之间的详细区别以及优缺点
可以参考:ajax、axios、fetch之间的详细区别以及优缺点_毛毛虫博客-CSDN博客_fetch和axios的区别
- 为什么new vue({data:{name:''}})中data是一个对象,而在组件中,data(){return{name:''}},data必须是一个函数呢?
首先每一个组件其实都是一个vue实例化得来的,引用的是同一个实例,所以一个发生改变,其他的引用肯定也会改变的,但是换成函数的话,因为变量在函数里外部不能直接访问,所以也就不会影响到别的组件。所以new vue的时候实例其实只有一个,用data:{}也就可以了。
- 怎么自定义一个vue的过滤器?
1.在组件中自定义过滤器
在组件中写:
filters:{
myFilter(value){
return value.toLowerCase();
}
}
使用:
直接输出属性时候{{name | myFilter}}
或者在v-bind中<div v-bind:name="name | myFilter"></div>
2.自定义全局过滤器
Vue.filter('allFilter', function (value) {
return value.toLowerCase();
})
new Vue({
// ...
})
- vue中自定义指令怎么写?
参考官方的文档的写法,指令是有几个钩子函数的,bind,inserted,update等,具体的含义和使用参考自定义指令 — Vue.js
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
- v-on可以绑定多个方法,
<div v-on="click1(),click2()")>click here</div>
- 什么是vue中的计算属性?
1.计算属性可以用来计算模版中比较复杂的逻辑,运算,并且它需要返回一个结果。
2.计算属性监听vue中的数据依赖,只要依赖的其中一个数据变化了,就会重新计算,相当于watch监听数据一样。
3.计算属性还可以依赖其他vue实例中的数据,比如new vue实例有A和B,A可以获得B的data中的数据进行计算。
4.计算属性还可以进行缓存,只要依赖的数据没有变,再次请求也不会重新计算,而是去取的缓存。
- vue中组件传值方式有哪些?
1.父-子:调用子组件<Child :name='name'></Child>,在子组件里使用props:{name:{type:String,default:'dd'}}来接收值。
2.子-父:调用子组件<Child @getChild="fromChild"></Child>,在子组件里this.$emit("fromChild",传父组件的值);
3.定义公用组件bus来传值,父组件用bus.$on("fromChild",fnction(data){});子组件用bus.$emit("fromChild",传的值);
4.使用Vuex来传值。
- v-for和v-if为什么不能连用?
在Vue2.0中v-for的优先级是高于v-if的,所以遍历的时候会把v-if的元素都添加一遍又隐藏,这样是无意义的,会造成性能浪费。
在Vue3.0中v-if的优先级是高于v-for的,同样是不建议放在一起用的。
- v-html会导致哪些问题?
1.xss攻击
2.v-html会替换标签内部的元素
- 为什么Vue组件中的data是一个函数?
避免组件中数据互相影响,同一个组件被复用会创建多个实例对象,如果data是一个对象的话是不能每个组件的数据独立的,所以data是函数,里面的数据有独立的作用域,这样每个组件中返回的数据都是独立的。
- vue中添加全局变量的方法?
第一种:定义一个全局变量的vue页面,在每个需要引用的页面import进来。
第二种:全局变量挂载到Vue.prototype原型上。
Vue.prototype.color="红色";
Vue.prototype.getColor=function(){return "红色";}
在vue页面中直接可以{{this.color}} {{this.getColor()}}来使用
第三种:在main.js的同级目录创建一个global.js,里面需要放到install里
exports.install = function (Vue, options) {
Vue.prototype.getColor = function (){
return "红色"
};
}
最后在main.js中Vue.use(global)即可,页面中的使用方法还是{{this.getColor()}}这样即可。
import global from './global'
Vue.use(global)
第四种:使用Vuex来做全局的变量,也可以在任何页面都能够获取。
- vue中如何响应路由器参数的变化?
页面路由跳转时候,如果从/use/a调到/use/b,这时候组件是会复用的,不会重新创建,所以想对路由参数变化作出响应的话,就需要使用watch来监听$route对象。或者在组件中使用beforeRouteUpdate(to,from,next){}钩子函数来监听。
- vue-router有几种导航守卫?
1.全局前置守卫:beforeEach
2.全局解析守卫:beforeResolve
3.全局后置钩子:afterEach
4.单独路由独享守卫:beforeEnter
5.组件内守卫:beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave
- vue-router路由跳转解析流程,当A路由跳转到B路由?
1.在A组件里调用离开守卫beforeRouteLeave
2.调用全局前置守卫beforeEach
3.在B路由配置里调用路由守卫beforeEnter
4.再执行B组件的进入守卫beforeRouteEnter
5.调用全局解析守卫beforeResolve
6.导航被确认
7.调用全局的后置钩子afterEach
8.触发DOM更新
- vue-router配置动态路由
路由文件:
import HelloWorld from '@/components/HelloWorld.vue'
export default new Route({
router:[
// 动态路径参数 以冒号开头
{ path: '/user/:id', component: HelloWorld}
]
})
匹配的使用方法:
<router-link :to="'/user/1">hi页面</router-link>
// 会请求/user/1
this.$router.push({name:'/user',params:{id:1} })
- vue的嵌套路由
由多个层次构成的路由就是嵌套路由,每个路由的父级定义<router-view></router-view>来显示子路由的页面,在路由配置里需要配置children:[{}]子路由的信息。
- vue中<router-link>标签解释和包含的属性
这个标签相当于a标签,用来做路由的跳转。
to: 属性是路由的地址。
replace: 跳转后不会留下history记录。
tag :把router-link标签变为某个标签,比如li,span,等
active-class:当链接被激活的时候使用的class样式。
- vue中路由普通加载和懒加载的写法
第一种,普通的加载方式
import Hello from 'Hello.vue'
const router = new VueRouter({
routes: [
{ path: '/hello', component: Hello }
]
})
第二种,vue动态组件实现的懒加载
const router = new VueRouter({
routes: [
{
path: '/hello',
component:(resolve) =>{
require(['@/components/Hello.vue'],resolve)
}
}
]
})
第三种,es6的import实现的懒加载,推荐这种,vue-router官方也写的这种。
const Hello = () => import('@/componsnts/Hello.vue')
const router = new VueRouter({
routes: [
{ path: '/hello', component: Hello }
]
})
- vue路由的两种模式
vue路由有两种模式,hash和history,默认是hash,前端路由的核心就是改变页面路径的同时不会向后台发送请求。
hash:地址栏有带一个#号,比如:http://www.abc.com/#/hello,刷新页面和前进后退都可以用。这个是不会请求后台的,是前端页面中使用的路由。
history:需要在路由里配置mode为history,利用了html5的history新增的 pushState() 和 replaceState() 方法方法,比如http://www.abc.com/user/1,这种请求的路径需要和后台匹配的,不然会返回404找不到资源。
- $route和$router区别?
1.$route是路由信息对象,包括path,params,query等路由参数。
2.$router是路由实例,包括了路由的跳转方法this.$router.push(),this.$router.replace(),this.$router.go(),this.$router.back()等,和一些钩子函数router.beforeEach(),router.afterEach()等。
webpack相关
- 什么是webpack
webpack是一个前端模块化打包工具,可以把项目中的资源打包成浏览器可以识别的资源。主要由entry入口,output出口,loader,plugins四个部分。
- 什么是webpack中的bundle,chunk,module?
bundle:是由webpack打包出来的文件,
chunk:是指webpack在进行模块的依赖分析的时候,代码分割出来的代码块。
module:是指开发中的单个模块。
- 什么是loader,plugin?
loader就是一个加载器一样,使webpack有能力处理这些非javascript类型的文件。比如处理css的less-loader,图片,字体等类型的,配置在module.rules中
plugin就是打包用到的插件,可以参与到打包的流程中,比如最常用到的htmlPlugin,可以把js和css打包到html模版文件中。
- webpack的构建流程?
1.初始化配置参数
2.初始化compiler对象,准备编译
3.确定entry入口文件并遍历
4.使用loader和plugin编译解析文件
5.输出资源文件
- webpack热更新原理?
大致原理:
1.启动本地服务后,服务端和客户端使用websocket作长连接;
2.webpack监听到源文件变化,然后webpack会重新编译,每次编译都会生成hash值、已改动模块的json文件、已改动模块代码的js文件;
3.编译完成后,会通过socket向客户端推送当前编译的hash;
4.客户端websocket监听到所有文件改动推送过来的hash,会和上一次的对比,一致的会走缓存,不一致的会通过ajax向服务器获取最新资源,使用内存文件系统去替换有修改内容的地方实习局部刷新。
- webpack打包性能优化方法?
1.定位体积比较大的模块,可以用webpack-bundle-analyzer插件来查看。
2.提取公共模块。
3.移除不必要的文件。
4.可以通过cdn引入一些库文件,可以见效打包文件的体积。
5.利用缓存。
6.更换js的压缩插件为uglifyjs-webpack-plugin。
7.使用dllpllugin,这个插件可以实现把依赖的第三方的包(比如react,vue,jquery)完全分离开,因为这些第三方包不会经常改变,除非是版本升级,所以这些第三方包只需编译一次,生成*.dll.js文件,以后每次只打包项目自身的业务代码,可以提高编译速度。
8.因为webpack是单线程的,所以可以使用happypack用多个进程并行处理,可以提高打包速度。
- webpack和gulp的区别?
webpack和gulp都是前端自动化构建工具,但是他们的定位不一样,webpack侧重于模块打包,根据模块之间的依赖,生成最终生产部署的前端资源。
gulp侧重于前端开发的流程,在gulpfile.js里通过配置task任务使用一些插件,来实现js,css压缩,图片压缩,编译less,热加载。gulp利用流的方式进行文件的处理,gulp处理的文件是写在内存中,通过管道将多个任务和操作连接起来,所以处理更快,流程更清晰。
- webpack常用的插件
1.autoprefixer 自动补全css3的前缀
2.html-webpack-plugin 生成html文件,可以使用指定的模板html。
3.extract-text-webpack-plugin 打包时候分离css,形成独立的文件
4.copy-webpack-plugin 拷贝文件和文件夹到指定目录,也可以配置ignore忽略文件。
5.webpack.ProvidePlugin 自动配置全局加载模块,比如配置jquery,不用每次都import使用。
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
6.HotModuleReplacementPlugin 模块热替换插件,修改可以实时看到。
7.uglifyjs-webpack-plugin webpack4中的压缩js插件
8.clean-webpack-plugin 清理打包目录插件,可以配置清理的文件夹目录
9.happypack webpack是单线程的,这个插件是可以多线程执行任务,加快编译速度
10.webpack-dev-server 启动server后,可以把打包的文件存储到内存中,这样可以使用热加载功能,修改代码不需要刷新页面。
- webpack怎么自定义插件
webpack自定义插件可以通过es6的class写一个类,或者用函数,最后再模块导出,在webpack.config.js中new插件即可。
第一种实现方式,使用函数方式,并且在函数的原型上绑定apply方法
function MyHelloPlugin(options){
console.log('接收插件的参数:',options)
}
MyHelloPlugin.prototype.apply = function(compiler){
compiler.plugin('emit', function(compilation) {
console.log('生成资源到output目录之前:',compilation);
});
compiler.plugin('done', function() {
console.log('编译完成了');
});
}
module.exports=MyHelloPlugin;
// 在webpack.config.js中引入并入使用
const MyHelloPlugin = require('./webpack.myplugin.js')
new MyHelloPlugin({option:true})
第二种方式,使用class,并在里面添加apply方法
class MyHelloPlugin{
constructor(options){
console.log('传递的参数:',options)
}
apply(compiler){
compiler.plugin('done',function(compilation){
console.log('编译完成')
})
}
}
module.exports=MyHelloPlugin;
// 在webpack.config.js中引入并入使用
const MyHelloPlugin = require('./webpack.myplugin.js')
new MyHelloPlugin({option:true})
以上两种方式都可以,但是必须要写apply方法,因为自定义插件运行的时候会自动应用插件对象绑定的这个apply方法。
apply方法的回调返回一个compiler对象,这个对象是继承自Tapable类,compiler可以监听整个编译的过程,它里面包含整个webpack声明周期钩子,比如有beforeRun,watchRun,run,beforeCompile,compile,compilation,emit,afterEmit,done,watchClose等等钩子。
Tapable这个类暴露很多的钩子函数,compiler中的钩子其实用到的是这里面的,比如写插件需要的plugin方法,apply方法都是继承的tapable里面。这个类的作用实际上就是一个事件管理器,是一个基于发布订阅者的模式,专注于事件的触发和处理。
compiler的钩子的回调是返回一个Compilation对象,这个对象是继承Compiler,它的主要作用是在打包的过程中可以获得打包的模块和依赖,同时也提供了一些钩子函数,在这个阶段模块可以被加载(loaded),封存(sealed),优化(optimized),分块(chunked),哈希(hashed),重新创建(restored),当然它也是属于compiler声明周期中的一个钩子。
Koa相关
- koa中的koa-body是什么?
是koa中的一个插件,可以处理请求和实现上传文件等操作,可以代替请求处理的koa-bodyparser和图片文件上传的koa-multer。
Nodejs相关
- 什么是PM2?
pm2是一个node进程管理器,可以利用它来简化很多node应用管理的繁琐任务,如性能监控、自动重启、负载均衡等。
Web相关
- 理解web标准,了解可用性,可访问性和安全性
web标准是一些列标准的集合,主要包括 结构,表现,行为。
结构标准:是指用html,xhtml,xml来描述页面的结构。
表现标准:是指使用css样式来美化页面结构,使它更具有美感。
行为标准:是指用户和页面之间有一定的交互,可以使页面结构和表现发生改变,比如W3c制定的EcmaScript标准来实现。
可用性:是指页面从用户的感官上来说是否容易上手,容易理解,容易操作完成,可用性好说明产品质量高。
可维护性:是指系统出现问题时候可以快速定位解决,成本低,可维护性高,而且代码结构是否清晰符合标准,让其他的开发者更容易上手维护。
可访问性:是指在不同浏览器,不同屏幕下是否可以很好的去展示,并且对不同的用户或者有残疾的用户是否都可以使用。
- 什么是html语义化?
使用语义适当的标签去构建html页面的结构,比如使用h1-h6设置标题,使用header,footer,nav,aside标签来划分结构。html语义化可以使html的页面结构变得更加清晰,即使没有css的情况下页面也能够很好的呈现出结构,还能提升用户体验,方便维护,方便爬虫抓取和seo搜索引擎优化,也便于不同设备之间的访问。
- 什么是响应式网页设计?
网页可以在不同尺寸的设备上面可以自动调整显示和布局,以适应不同尺寸屏幕的浏览体验。
- web安全及防护
1.sql注入:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
2.xss攻击:指的是攻击者往Web页面里注入恶意脚本代码,当用户浏览网页时候执行恶意代码来窃取用户的信息。
3.csrf攻击:指的是打开未受信任的网站,导致本地存储的cookie和个人信息泄露,而造成的被盗用了个人信息。比如你刚转了钱,本地保存了你的银行的个人信息,接着你又不小心访问了一个网站,这个网站就会盗取你的信息,去盗取你的银行信息。
- web性能优化有哪些?
优化的目的:
用户角度:网页加载速度快,操作响应及时,用户体验好。
服务商角度:能减少页面请求、和占用的带宽资源,提高服务器的处理响应速度。
主要分为:
①页面级别优化
1.减少http请求。
2.使用外部脚本和css,可以缓存下来。
3.打包资源优化。
4.避免请求重复的资源,减少不必要的http跳转。
5.按需加载资源,比如js和图片懒加载。
6.从设计层面上简化页面,避免过于复杂的交互操作。
7.把js放到底部,把css放到header,可以避免造成阻塞。
8.使用骨架屏,可以用base64图片代替展示,数据加载完了就替换当前图片。
②代码级别优化
1.减少dom的操作,避免重绘和回流而影响页面性能。
2.减少闭包的使用,因为闭包的变量都会在内存中,过多会造成内存消耗。
3.css优化,减少使用行内标签,可以用类和标签选择器,同样的功能建议抽取出来一个common css。
4.在手机端的页面,可以添加样式transform:transition3d(0,0,0)来开启硬件加速,会使页面流畅。
5.避免大量的声明全局变量,因为这些变量会绑定到window全局变量上,会可能造成内存溢出。
③服务器优化
1.提高硬件环境。
2.优化nginx,比如加大进程数,配置gzip压缩减少网络上所传输的数据量,配置超时时间,缓存等
- 移动端性能优化有哪些?
1.尽量使用css3的动画开启硬件加速,比如transform:transition3d(0,0,0)。
2.使用touch事件代替click事件。
3.避免使用css3的阴影效果。
4.不滥用float,因为float在渲染时候计算了比较大,会影响性能。
5.不滥用web字体,web字体需要下载,解析,重绘,尽量减少使用。
6.pc端的性能优化同样适用在手机端。
- 什么是web语义化?
Web语义化是指使用语义恰当的标签,使页面有良好的结构,页面元素有含义,能够让人和搜索引擎都容易理解。比如使用footer,body,header,section标签等,好处是便于阅读和理解,便于爬虫抓取和搜索引擎优化。
- 什么是前端模块化?
可以理解为一组自定义业务的抽象封装,是根据项目的情况来进行封装组合到一起的,比如我们可以分为登录模块,评论模块。模块可维护性好,组合灵活,方便调用,多人协作互不干扰。因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。
- 什么是前端组件化?
指对具体的某个功能的封装,比如所有的分页可以封装为分页组件来统一使用,以此来达到组件复用,提高开发效率。
- 什么是前端工程化?
概念:指使用软件工程的技术和方法来进行前端项目的开发、维护和管理。
前端工程化包含如下:
1.代码规范: 保证团队所有成员以同样的规范开发代码。
2.分支管理: 不同的开发人员开发不同的功能或组件,按照统一的流程合并到主干。
3.模块管理: 一方面,团队引用的模块应该是规范的;另一方面,必须保证这些模块可以正确的加入到最终编译好的包文件中。(以上两点可以总结为模块化或者组件化开发。)
4.自动化测试:为了保证和并进主干的代码达到质量标准,必须有测试,而且测试应该是自动化的,可以回归的。
5.构建:主干更新以后,自动将代码编译为最终的目标格式,并且准备好各种静态资源,
6.部署。 将构建好的代码部署到生产环境。
- 什么是spa单页面应用?
spa(single page web application)单页面应用,就是只有一个Web页面的应用,浏览器一开始会加载所需要的HTML、CSS和js资源,所有的操作通过js来动态更新该页面,这样的程序就叫做spa单页面应用。
优点:
1.用户体验好,避免不必要的跳转页面和重复渲染。
2.减轻服务器端压力。
3.前后端分离,各司其责,便于优化管理。
缺点:
1.不利于seo搜索优化。(可以通过ssr服务器端渲染等方法)
2.首屏加载时间过长。
- 什么是SSR服务器端渲染?
就是在服务器端生成页面的html,再发送到浏览器。与单页面应用相比,服务器端渲染更好的利于seo搜索优化,和减少首页加载时间。但是同时也存在缺点,比如学习成本比较大,也会加大服务器的压力。
网络协议相关
- http协议的介绍
http协议(Hyper Text Transfer Protocol超文本传输协议),是一个应用层的协议。
- http的特点是?
1.支持客户端/服务器模式,也就是请求/响应的模式。
2.简单快速:是说我们只需要指定get,post,head这些请求方式和访问路径,就可以进行访问了。
3.灵活:是指现在的版本中可以传输任意的数据,文件,xml,json都可以,只需要指定content-type对应的类型即可。
4.无连接:是指每次链接只处理一个请求,服务器处理完请求后,响应给客户端并收到客户的应答后就断开链接。
5.无状态:是说http协议对事务的处理没有记忆能力,如果中断了,就必须要重新传输了。
- http每个版本的区别有哪些?
http有4个版本,http/0.9,http/1.0,http/1.1,http/2.0。
1.http/0.9:在1991年发布,是http协议最初的版本,功能简陋,只支持get的请求方式,也不支持请求头,服务器只能返回html格式的字符串。
缺点:功能比较简陋,只能处理get请求,返回类型比较少。
2.http/1.0:在1996年发布,比0.9支持了很多的内容;
①支持get,post,head请求
②支持请求头和响应头,状态码,缓存,内容编码。
③服务器响应对象不仅限于超文本了,content-type可以设置更多的格式,图片,视频等。
④新建一个tcp连接,只能发送一个请求,服务器也只能处理一个请求。
⑤部分浏览器支持connection:keep-alive;长连接,可以在请求结束后服务器不关闭连接。
缺点:tcp连接新建需要三次握手,每个tcp连接只能发送一个请求,而且发送后服务器就会断开此次连接,这样的处理比较耗费效率,也没办法复用。虽然也有一些浏览器实现了Connection:keep-alive;长连接,但是并不是每个浏览器都支持这个。
3.http/1.1:在1997年发布,添加了很多优化性的内容;
①支持持久连接,不用声明Connection: keep-alive;tcp新建连接后默认不关闭,可以被对个请求复用。客户端也可以主动在最后一个请求发送Connection:close;来关闭连接。
②支持在一个tcp连接里,支持客户端可以同时请求多个连接,但是服务器还是需要按照顺序来处理,谁先发送的就先处理谁。
③新增了多个请求的方法,options,put,delete,connect,trace。
④新增了一些状态码,身份认证机制,支持文件断点续传。
⑤添加了一些cache的新特性,增加Cache-control属性。
缺点:虽然支持多个请求,但是在服务器端需要排队处理,会出现请求堵塞的情况。消息头部无法压缩,比较占字节,会浪费一些网络资源。
4.http/2.0:在2015年发布,在谷歌,ie11以及火狐等现代浏览器已经可以支持http/2.0协议了;
①二进制协议,在http1.1里是超文本传输协议,http2.0已经可以支持二进制协议了,体积更小,易于解析不会出错。
②真正的多请求处理,客户端请求多个到服务器端,在服务器端处理是可以多对多的,也不用服务器按照请求的顺序去处理,即使某个请求堵塞了也不会影响到其他的请求处理。
③解决了http1.1的请求头部压缩问题,加快请求传输速度。
④服务器推送,服务器可以主动向客户端推送资源,资源包括页面,css,js,图片等资源,客户端检测到后解析处理,这样这些资源已经在本地了,浏览器可以更快的拿到而不是再通过网络重新请求,这样减少了客户端去请求服务器再到服务器响应的过程,大大提高了效率和资源的利用。
- TCP三次握手和四次挥手?参考我的博客 TCP三次握手和四次挥手_qq575792372的博客-CSDN博客
- http和https的区别?
1.https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2.http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3.http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4.http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
注:ssl是一个位于tcp和http之间的安全协议,为数据通讯提供安全支持
- http状态码301和302的区别?
301 redirect: 301 代表永久性转移(Permanently Moved)
302 redirect: 302 代表暂时性转移(Temporarily Moved )
- ETag是什么?
etag是entity tag的缩写,意思就是实体标签的意思,它是http协议中请求head中的一个属性,用来帮助服务器控制web端的缓存验证。
- tcp和udp的区别?两个都是传输层的协议,
①TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
②TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
③UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
④每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
⑤TCP对系统资源要求较多,UDP对系统资源要求较少。
-
get和post的区别?
1.get用于获取数据,post是提交数据。
2.get提交的参数追加在url的后面,用?和&来连接,post的参数放在Request Body提交。
3.get的url会有长度限制,最多2K,post则不会限制数据大小,而且还可以设置提交的数据类型(文件,json这些)。
4.get是不安全的,因为url上参数都已经暴露了,post是安全的。
5.get的请求参数会被保存在浏览历史记录里,post则没有。
6.get请求可以被浏览器缓存,post则没有。
- http请求的过程?
1.当我们输入某个地址后,首先需要dns域名解析这个地址,根据一系列的dns解析域名的步骤找到对应服务器的ip。
2.tcp的三次握手建立连接。
3.建立tcp的链接后发送http请求的报文,包括请求行,消息报头,请求正文这些。
4.http响应报文,包括状态行,消息报头,响应正文,浏览器得到html代码。
5.最后浏览器解析得到的html,将结果呈现给用户。
浏览器相关
- 浏览器内核有哪些?
1.Trident: 主要是IE,一些双核浏览器也会用到,比如360浏览器,腾讯浏览器,百度浏览器
2.Gecko:现在主要有火狐
3.Webkit:苹果自主研发的内核,使用的浏览器相当多,比如safari,Google chrome,opera,以及360,腾讯这些浏览器的高速模式都是用的这个。
4.Blink:基于webkit,Google与Opera共同开发,现在google在用。
- 渲染引擎工作流程?
1.解析html生成dom树
2.解析css生成cssom规则树
3.将dom树和cssom规则树合并在一起生成render渲染树
4.遍历render渲染树的节点开始布局,计算每个节点的位置大小信息。
5.将render渲染树每个节点绘制到页面来显示。
注意:渲染的时候回出现阻塞的情况,当浏览器碰到script标记时候,dom构建将暂停,直到脚本执行完毕,所以要把脚本放到最下面,避免阻塞。css的话要放在最上面。
- 什么是重绘(repaint)和回流(reflow)
重绘:当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如添加个背景色,设置个文字颜色,则就叫称为重绘。
回流:当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。
回流何时发生:
当页面布局和几何属性改变时就需要回流。下述情况会发生浏览器回流:
1、添加或者删除可见的DOM元素;
2、元素位置改变;
3、元素尺寸改变——边距、填充、边框、宽度和高度
4、内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变;
5、页面渲染初始化;
6、浏览器窗口尺寸改变——resize事件发生时;
注意:回流必定触发重绘,重绘不一定触发回流,重绘的开销比较小,回流的代价比较高。