相信你们也和我同样,2020年的春节过得很是特别。新型冠状病毒不只对国家仍是对社会以及对咱们的我的都有很大影响!javascript
不少小伙伴内心确定想着因为种种缘由,内心开始蠢蠢欲动了...css
笔者经过平时面试总结以及面试别人常提的问题,结合本身认为很是重要的前端各技术栈的知识点,总结了这篇中高级前端面试。让须要的小伙伴所阅读,让不在大厂的小伙伴提早了解大厂前端面试官常问的各类常见前端问题。html
文章有点长,请各位小伙伴耐心阅读完。相信认真阅读者一定或多或少有点感悟!前端
我的理解:vue
DTD(document type definition,文档类型定义)是一系列的语法规则,用来定义XML或(X)HTML的文件类型。浏览器会使用它来判断文档类型,决定使用何种协议来解析以及切换浏览器模式。(DTD告诉浏览器我是什么文档类型,浏览器会根据这个来判断用什么引擎来解析和渲染他们)java
DOCTYPE是用来声明文档类型和DTD规范的,一个主要的用途即是文件的合法性验证。若是文件代码不合法,那么浏览器解析时会出一些错误。(DOCTYPE告诉浏览器当前是哪一个文档类型)node
一、什么是HTML语义化?jquery
二、为何要使用语义化标签?webpack
三、 HTML5新特性有哪些?nginx
一、行内元素的特色?
二、块级元素的特色?
常见行内元素标签:
a、br、code、em、img、input...
复制代码
常见块级元素标签:
div、p、dl、dt、form、h1~h6...
复制代码
渐进加强(Progressive Enhancement):
一开始就针对低版本浏览器进行构建页面,完成基本的功能,而后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。
优雅降级(Graceful Degradation):
一开始就构建站点的完整功能,而后针对浏览器测试和修复。好比一开始使用 CSS3 的特性构建了一个应用,而后逐步针对各大浏览器进行 hack 使其能够在低版本浏览器上正常浏览。
二者区别?
一、广义:
其实要定义一个基准线,在此之上的加强叫作渐进加强,在此之下的兼容叫优雅降级
二、狭义:
渐进加强通常说的是使用CSS3技术,在不影响老浏览器的正常显示与使用情形下来加强体验,而优雅降级则是体现html标签的语义,以便在js/css的加载失败/被禁用时,也不影响用户的相应功能。
例子:
.transition { /*渐进加强写法*/
-webkit-transition: all .5s;
-moz-transition: all .5s;
-o-transition: all .5s;
transition: all .5s;
}
.transition { /*优雅降级写法*/
transition: all .5s;
-o-transition: all .5s;
-moz-transition: all .5s;
-webkit-transition: all .5s;
}
复制代码
相同点:
不一样点:
cookie数据大小不能超过4k;sessionStorage和localStorage的存储比cookie大得多,能够达到5M+
cookie设置的过时时间以前一直有效;localStorage永久存储,浏览器关闭后数据不丢失除非主动删除数据;sessionStorage数据在当前浏览器窗口关闭后自动删除
cookie的数据会自动的传递到服务器;sessionStorage和localStorage数据保存在本地
盒子由margin(外边距)、border(边框)、padding(内边距)、content(内容)组成
盒子的宽度 = 内容宽度 + 左填充 + 右填充 + 左边框 + 右边框 + 左边距 + 右边距
盒子的高度 = 内容高度 + 上填充 + 下填充 + 上边框 + 下边框 + 上边距 + 下边距
box-sizing: content-box(默认)----指的是标准模型(自己内容宽高度+边框和内边距)
box-sizing: border-box-----指的是IE模型(自己内容的宽高度)
dom.style.width/height
复制代码
这种方式只能取到dom元素内联样式所设置的宽高,也就是说若是该节点的样式是在style标签中或外联的CSS文件中设置的话,经过这种方法是获取不到dom的宽高的
dom.currentStyle.width/height
复制代码
获取渲染后的宽高。可是仅IE支持
window.getComputedStyle(dom).width/height
复制代码
与2原理类似,可是兼容性,通用性更好一些
dom.getBoundingClientRect().width/height
复制代码
计算元素绝对位置,获取到四个元素left,top,width,height
扩展:
获取浏览器高度和宽度的兼容性写法:
var w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
var h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
复制代码
想详细了解Flex布局知识点的小伙伴,请查看 Flex布局详解
-webkit-font-smoothing在window系统下没有起做用,
可是在IOS设备上起做用-webkit-font-smoothing:antialiased是最佳的,灰度平滑
一、CSS选择器:
二、CSS3属性选择器:
a[href$='.pdf']:选择href属性中以.pdf结尾的元素
a[href^='www']:选择href属性中以www开头的元素
a[href*='tmc']:选择href属性中包含tmc的元素
三、CSS3常见伪类选择器:
:nth-of-type():
:nth-child():
可继承的属性:font-size, font-family, color
不可继承的样式:border, padding, margin, width, height
优先级(就近原则):!important > [id > class > tag]
!important比内联优先级高
1、BFC的概念?
BFC(块级格式上下文):它是页面中的一块渲染区域,有本身的渲染规则,决定了其子元素如何布局,以及和其余元素之间的关系和做用
2、BFC的原理?
3、如何建立BFC?
4、BFC的使用场景?
1、清除浮动的方法
方式1、使用overflow 属性来清除浮动
.parent {
overflow: hidden;
}
复制代码
缺点:离开这个元素所在区域的会被隐藏(overflow: hidden将超出的分布隐藏起来)
方式2、使用额外标签法
.clear {
clear: both;
}
复制代码
缺点:会增长页面的标签,形成结构的紊乱
方式3、使用伪元素来清除浮动【推荐使用】
.clearfix:after { content: ""; // 设置内容为空 height: 0; // 高度为0 line-height: 0; // 行高为0 display: block; // 将文本转为块级元素 visibility: hidden; // 将元素隐藏 clear: both; //清除浮动 } .clearfix { zoom: 1; // 为了兼容IE } 复制代码
2、定位 posiiton的值:
过渡
动画
形状转换
选择器
阴影
文字阴影: text-shadow: 2px 2px 2px #000;(水平阴影,垂直阴影,模糊距离,阴影颜色) 盒子阴影: box-shadow: 10px 10px 5px #999
边框
背景
文字
渐变
弹性布局、栅格布局、多列布局
媒体查询
1. px:绝对单位,页面按精确像素展现
2. em:相对单位,基准点为父节点字体的大小,若是自身定义了font-size按自身来计算(浏览器默认字体是16px),整个页面内1em不是一个固定的值
3. rem:相对单位,可理解为”root em”, 相对根节点html的字体大小来计算,CSS3新加属性,chrome/firefox/IE9+支持
4. vw:viewpoint width,视窗宽度,1vw等于视窗宽度的1%
5. vh:viewpoint height,视窗高度,1vh等于视窗高度的1%
6. vmin:vw和vh中较小的那个
7. vmax:vw和vh中较大的那个
8. %:百分比
复制代码
<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> initial-scale:初始的缩放比例 minimum-scale:容许用户缩放到的最小比例 maximum-scale:容许用户缩放到的最大比例 user-scalable:用户是否能够手动缩放 复制代码
1、行内元素水平垂直居中方法:
方式1:
text-align:center /*水平居中*/
height = 100px; /*垂直居中 */
line-height = 100px;
复制代码
方式2:
text-align:center 水平居中
display:table-cell; 垂直居中
vertical-align:middle;
复制代码
2、块级元素水平居中方法:
margin:0 auto;只能设置水平居中, 而margin:auto 0 不能设置垂直居中 ,由于margin垂直塌陷问题
方法1:定位+margin
父级元素设置position:relative;
儿子元素设置
width: 100px;
height: 100px;
position:absolute;
top:50%;
left:50%;
margin-top:-50px;
margin-right:-50px;
复制代码
方式2:定位方法
复制代码
父级元素设置position:relative;
儿子元素设置
position:absolute;
top:0;
bottom:0;
left:0;
right:0;
margin:auto;
复制代码
方式3:单元格方法
复制代码
父级元素
display:table-cell;
text-align:center;
vertical-align:middle;
子元素
display:inline-table
复制代码
什么事CSS预处理器?
CSS预处理器是一种语言用来为CSS增长一些变成的特性,无需考虑浏览器兼容问题,例如你能够在CSS中使用变量,简单的程序逻辑、函数等在编程语言中的一些基本技巧,可让CSS更加简洁,适应性更强,代码更直观等诸多好处
基本语法区别
Sass是以.sass为扩展名,Less是以.less为扩展名,Stylus是以.styl为扩展名
变量的区别
Sass 变量必须是以$开头的,而后变量和值之间使用冒号(:)隔开,和css属性是同样的。
Less 变量是以@开头的,其他sass都是同样的。
Stylus 对变量是没有任何设定的,能够是以$开头或者任意字符,并且变量之间能够冒号,空格隔开,可是在stylus中不能用@开头
三种预处理器都有:嵌套、运算符、颜色函数、导入、继承、混入。Stylus还有一些高级特性。例如循环、判断等
使用@media查询能够针对不一样的媒体类型定义不一样的样式
@media 能够针对不一样的屏幕尺寸设置不一样的样式,特别是若是须要设置设计响应式的页面。
重置浏览器大小的过程当中,页面也会根据浏览器的宽度和高度从新渲染页面。
语法:@media 媒介类型 and | not | only (媒介特性) { css 代码 } 媒介类型: print: 用于打印机和打印预览 screen: 用于电脑屏幕、平板电脑、只能手机等 all: 用于全部媒体设备类型 媒介特性: device-height: 定义输出设备的屏幕可见高度 device-width: 定义输出设备的屏幕可见宽度 height:定义输出设备中的页面可见区域高度。 width:定义输出设备中的页面可见区域宽度。 max-device-height:定义输出设备的屏幕可见的最大高度。 max-device-width:定义输出设备的屏幕可见的最大宽度。 max-height:定义输出设备中的页面可见的最大高度。 max-width:定义输出设备中的页面可见的最大宽度。 min-device-height:定义输出设备的屏幕可见的最小高度。 min-device-width:定义输出设备的屏幕可见的最小宽度。 min-height:定义输出设备中的页面可见的最小高度。 min-width:定义输出设备中的页面可见的最小宽度。 复制代码
1. link属于html标签,除了引入css样式之外还能够定义RSS等其余事物,@import是css提供的,只能引入css
2. lilnk在页面加载的时候会同时加载,@import引用的css要等页面加载结束后再加载
3. link是html标签,没有兼容性,@import只有ie5以上才能识别
复制代码
display: none与visibility: hidden的区别
display:none 不显示对应的元素,在文档布局中再也不分配空间(回流+重绘)
visibility:hidden 隐藏对应元素,在文档布局中仍保留原来的空间(重绘)
二者的做用不一样,CSS选择器找到元素后为设置该元素的样式,jQuery选择器找到元素后添加行为
jQuery选择器拥有更好的跨浏览器的兼容性
二者选择器的效率不一样 CSS选择器的效率:id选择器(#myid)、类选择器(.myclassname)、标签选择器(div,h1,p)、相邻选择器(h1+p)、子选择器(ul > li)、后代选择器(li a)、通配符选择器(*)、属性选择器(a[rel="external"])、伪类选择器(a:hover,li:nth-child)从高到低依次排列
jQuery选择器的效率:id选择器('form')、类选择器
('[attribute=value]')和伪类选择器$(':hidden')
$("#aijquery"): //这种方式获取获得的就是jquery对象 document.getElementById("aijquery")://这种方法获取到的就是dom对象 复制代码
dom对象转换为jquery对象:通常状况下,dom对象直接用$()就能够转换成jquery对象,如:
$(document.getElementById("aijquery")) 复制代码
jquery对象转换成dom对象,有两种方法,一种是用jquery的内置函数get,来获取dom对象,如:
$("#aijquery").get(0) 复制代码
还有一种方法更简单,由于jquery对象的属性是一个集合,因此咱们能够像数组那样,取出其中一项就行:
$("#aijquery")[0]; $("div")[5]; //上面这两种返回的都是dom对象,能够直接使用js里的方法 复制代码
5个简单数据类型(基本数据类型)+ 1个复杂数据类型
undefined、number、string、null、boolean+object ES6新增Symbol
async function async1() { console.log('async1 start'); await async2(); console.log('async1 end'); } async function async2() { console.log('async2'); } console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0) async1(); new Promise(function(resolve) { console.log('promise1'); resolve(); }).then(function() { console.log('promise2'); }); console.log('script end'); 复制代码
1. 第一步,输出script start;
虽然有两个函数声明,有async关键字,可是没有调用,就不看,直接打印同步代码console.log(‘script start’)
2. 第二步,输出async1 start; 由于执行async1这个函数的时候,async表达式定义的函数也是当即执行
3. 第三步,输出async2;
由于async2是async定义的函数,输出async2并返回promise对象
4. 第四步,输出promise1;
由于执行到new promise,promise是当即执行,就先打印promise1
5. 第五步,输出script end;
由于上一步先打印了promise1,而后执行到resolve的时候,而后跳出promise继续向下执行,输出script end
6. 第七步,输出async1 end;
由于await定义的这个promise已经执行完,而且返回结果,因此继续执行async1函数后的任务,就是console.log(‘async1 end’)
7. 第六步,输出promise2;
由于前面的nue promise放进resolve回调,因此resolve被放到调用栈执行
8. 第八步,输出setTimerout; setTimeout被放在最后被调用
复制代码
document.querySelectorAll('*') 复制代码
[...document.querySelectorAll('*')] 复制代码
[...document.querySelectorAll('*')}.map(ele => ele.tagName) 复制代码
new Set([...document.querySelectorAll('*').map(ele=>ele.tagName)).size 复制代码
1、typeof
console.log(typeof 1); // number console.log(typeof true); // boolean console.log(typeof 'mc'); // string console.log(typeof function(){}); // function console.log(typeof []); // object console.log(typeof {}); // object console.log(typeof null); // object console.log(typeof undefined); // undefined 复制代码
优势:可以快速区分基本数据类型 缺点:不能将Object、Array和Null区分,都返回object
复制代码
2、instanceof
console.log(1 instanceof Number); // false console.log(true instanceof Boolean); // false console.log('str' instanceof String); // false console.log([] instanceof Array); // true console.log(function(){} instanceof Function); // true console.log({} instanceof Object); // true 复制代码
优势:可以区分Array、Object和Function,适合用于判断自定义的类实例对象 缺点:Number,Boolean,String基本数据类型不能判断
复制代码
3、Object.prototype.toString.call()
var toString = Object.prototype.toString; console.log(toString.call(1)); //[object Number] console.log(toString.call(true)); //[object Boolean] console.log(toString.call('mc')); //[object String] console.log(toString.call([])); //[object Array] console.log(toString.call({})); //[object Object] console.log(toString.call(function(){})); //[object Function] console.log(toString.call(undefined)); //[object Undefined] console.log(toString.call(null)); //[object Null] 复制代码
优势:精准判断数据类型 缺点:写法繁琐不容易记,推荐进行封装后使用
复制代码
如何建立Ajax XMLHttpRequest对象的工做流程 ==========兼容性写法=========== var xmlHttp = null; if(window.XMLHttpRequset) { // IE7+,Firefox,Chrome,Safari,Opera xmlHttp = new XMLHttpRequset(); } else { // IE5,IE6 xmlHttp = new ActiveXObject("Microsoft.XMLHTTP") } 兼容性处理 事件的触发条件 xmlHttp.onreadystatechange = function() { if(xmlHttp.readyState == 4 && xmlHttp.status == 200) { responseText、responseXML } } 事件的触发顺序 ======================注意================= 若是是POST请求则须要添加头 xmlHttp.setRequestHeader("Content-type": "application/x-www-form-urlencoded") 复制代码
undefined是访问一个未初始化的变量时返回的值,而null是访问一个还没有存在的对象时所返回的值。
undefined看做是空的变量,而null看做是空的对象
实现 (5).add(3).minus(2),使其输出结果为6
有题目分析可得,该表达式属于链式调用方法。以数组为例:
arr.push() 为何arr有push方法?
由于arr是Array的实例,push是Array原型上的方法,全部实例arr能够调用原型上的方法;故,咱们只须要在数字Number的原型上添加add和minus方法便可。
~ function () { function add(number) { if (typeof number !== 'number' || Number.isNaN(number)) { throw new Error('请输入数字~'); } return this + n } function minus(number) { if (typeof number !== 'number' || Number.isNaN(number)) { throw new Error('请输入数字~'); } return this - n } Number.prototype.add = add Number.prototype.minus = minus }() console.log((5).add(3).minus(2)) // 6 复制代码
注意:this的指向始终指向最后谁调用了this所在的函数,this就指向谁!
基本概念:DOM事件的级别(事件的本质在于信息的传递)
DOM0:element.onlick = function(){} 一是在标签内写onclick事件 二是在JS写onclick=function(){}函数 DOM2:element.addEventListener('click', function(){},false) 三个参数分别表示为:事件名、事件处理的函数、为true则表示在捕获阶段调用,为false则表示在冒泡阶段调用 DOM3:element.addEventListener('keyup',function(){},false) DOM事件模型:(冒泡、捕获...) 冒泡事件是从内向外;捕获是从外向内======document->html->body->div DOM事件流 一个完整的事件流分为三个阶段:捕获-》目标阶段-》冒泡=========事件经过捕获到达目标元素再从目标元素经过冒泡上传到元素 描述DOM事件捕获的具体流程 捕获:window->document->html->body->......->目标元素 冒泡:相反 Event事件的用 event.preventDefault() // 阻止默认行为 event.stopPropagation() // 阻止冒泡行为 event.stopImmediatePropagation() // 在调用完stopPropagation函数以后,就会当即中止对后续节点的访问,可是会执行完绑定到当前节点上的全部事件处理程序;而调用stopImmediatePropagation函数以后,除了全部后续节点,绑定到当前元素上的、当前事件处理程序以后的事件处理程序就不会再执行了 event.currentTarget // 指的是绑定了事件监听的元素(能够理解为触发事件元素的父级元素) event.target // 表示当前被点击的元素 自定义事件(CustomEvent) var eve = new Event('custom'); eve.addEventListener('custom',function(){ console.log('custom') }) eve.dispatchEvent(eve) 复制代码
1、深拷贝
1.1 最简单的方法就是JSON.parse(JSON.stringify())
可是这种拷贝方法不能够拷贝一些特殊的属性(例如正则表达式,undefine,function)
1.2 用递归去复制全部层级属性
复制代码
function deepCopyTwo(obj) { let objClone = Array.isArray(obj) ? [] : {}; if (obj && typeof obj == 'object') { for (const key in obj) { //判断obj子元素是否为对象,若是是,递归复制 if (obj[key] && typeof obj[key] === "object") { objClone[key] = deepCopyTwo(obj[key]); } else { //若是不是,简单复制 objClone[key] = obj[key]; } } } return objClone; } 复制代码
2、浅拷贝
Object.assign(target, ...sources)
复制代码
function simpleClone(obj) { var result = {}; for (var i in obj) { result[i] = obj[i]; } return result; } 复制代码
想详细了解,请点击查看 对象深浅拷贝
想详细了解,请点击查看 一步步教你实现Promise/A+ 规范 完整版
this表示当前对象,this的指向是根据调用的上下文来决定的,默认指向window对象,指向window对象时能够省略不写
全局环境: this始终指向的是window对象
局部环境: 在全局做用域下直接调用函数,this指向window 对象函数调用,哪一个对象调用就指向哪一个对象 使用new实例化对象,在构造函数中的this指向实例化对象 使用call或apply改变this的指向
总结:this始终指向最后一个调用它的函数的对象
1. 箭头函数不能被直接命名,不过容许它们赋值给一个变量
2. 箭头函数不能用作构造函数,你不能对箭头函数使用new关键字
3. 箭头函数也没有prototype属性箭头函数绑定了词法做用域,不会修改this的指向(**最大特色**)
4. 箭头函数的做用域不能经过.call、.apply、.bind等语法来改变,这使得箭头函数的上下文将永久不变
复制代码
1. let/const
2. 多行字符串/模板变量
3. 解构赋值
4. 块级做用域
5. 函数默认参数
6. 箭头函数
复制代码
当你的简写箭头函数返回值为一个对象时,你须要用小括号括起你想返回的对象。不然,浏览器会把对象的{}解析为箭头函数函数体的开始和结束标记。
// 正确的使用形式 **var** objectFactory = () => ({ modular: 'es6' }) 复制代码
/** * 函数柯里化 * 柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,而且返回接受余下的参数且返回结果的新函数的技术。 */ // 通用版 function curry(fn, args) { var length = fn.length; var args = args || []; return function() { newArgs = args.concat(Array.prototype.slice.call(arguments)) console.log(newArgs) if(newArgs.length < length) { return curry.call(this, fn, newArgs); } else { return fn.apply(this, newArgs); } } } function multiFn(a, b, c) { console.log(a * b * c) return a * b * c; } var multi = curry(multiFn); multi(2)(3)(4) // multi(2, 3, 4) // multi(2)(3, 4) // multi(2, 3)(4) 复制代码
单线程,只有一个线程,只能作一件事
缘由:避免DOM渲染的冲突
解决方案:异步
实现方式:event-loop
复制代码
事件轮询-----JS异步的解决方案
JS实现异步的具体解决方案
一、同步代码,直接执行
二、异步代码先放在 异步队列 中
三、待同步函数执行完毕,轮询执行异步队列 中的函数
复制代码
1、具体实现步骤:
1. 首先函数接受不定量的参数,第一个参数为构造函数,接下来的参数被构造函数使用
2. 而后内部建立一个空对象 obj
3. 由于 obj 对象须要访问到构造函数原型链上的属性,因此咱们经过 setPrototypeOf 将二者联系起来。这段代码等同于 obj.__proto__ = Con.prototype
4. 将 obj 绑定到构造函数上,而且传入剩余的参数
5. 判断构造函数返回值是否为对象,若是为对象就使用构造函数返回的值,不然使用 obj,这样就实现了忽略构造函数返回的原始值
复制代码
2、 new操做符的特色
1. new经过构造函数Test建立处理的实例能够访问构造函数中的属性也能够访问构造函数原型链上的属性,因此:经过new操做符,实例与构造函数经过原型链链接了起来
2. 构造函数若是返回原始值,那么这个返回值毫无心义
2. 构造函数若是返回对象,那么这个返回值会被正常的使用,致使new操做符没有做用
复制代码
3、new操做符的几个做用:
1. new操做符返回一个对象,因此咱们须要在内部建立一个对象
2. 这个对象,也就是构造函数中的this,能够访问到挂载在this上的任意属性
3. 这个对象能够访问到构造函数原型链上的属性,因此须要将对象与构造函数连接起来
4. 返回原始值须要忽略,返回对象须要正常处理
复制代码
/** * 建立一个new操做符 * @param {*} Con 构造函数 * @param {...any} args 忘构造函数中传的参数 */ function createNew(Con, ...args) { let obj = {} // 建立一个对象,由于new操做符会返回一个对象 Object.setPrototypeOf(obj, Con.prototype) // 将对象与构造函数原型连接起来 // obj.__proto__ = Con.prototype // 等价于上面的写法 let result = Con.apply(obj, args) // 将构造函数中的this指向这个对象,并传递参数 return result instanceof Object ? result : obj } 复制代码
相同点: 三个函数的做用就是改变this的指向,将函数绑定到上下文中; 不一样点: 三个函数的语法不一样
fun.call(thisArg[, arg1[, arg2[, ...]]]) fun.apply(thisArg, [argsArray]) var bindFn = fun.bind(thisArg[, arg1[, arg2[, ...]]]) bindFn() 复制代码
扩展 :手写三个函数的源码
手写apply源码
Function.prototype.apply = function(content = window) { content.fn = this; let result; // 判断是否有第二个参数 if(arguments[1]) { result = content.fn(...arguments[1]); } else { result = content.fn(); } delete content.fn; return result; } 复制代码
手写call源码
/** * 完整版 步骤: * 将函数设为对象属性 * 执行&删除这个函数 * 指定this到函数并传入给定参数执行函数 * 若是不传参数,默认指向window * */ Function.prototype.call = function(content = window) { // 判断是不是underfine和null // if(typeof content === 'undefined' || typeof content === null){ // content = window // } content.fn = this; let args = [...arguments].slice(1); let result = content.fn(...args); delete content.fn; return result; } 复制代码
手写bind源码
/** * bind() 方法 * 会建立一个新函数。当这个新函数被调用时,bind() 的第一个参数将做为它运行时的 this,以后的一序列参数将会在传递的实参前传入做为它的参数。(来自于 MDN ) */ Function.prototype.bind = function(content) { if(typeof this != 'function') { throw Error('not a function'); } let _this = this; let args = [...arguments].slice(1); return function F() { // 判断是否被当作构造函数使用 if(this instanceof F) { return _this.apply(this, args.concat([...arguments])) } return _this.apply(content, args.concat([...arguments])) } } 复制代码
// 第一种:字面量 var o1 = {name: "o1"} var o2 = new Object({name: "o2"}) // 第二种:经过构造函数 var M = function(name){this.name = name} var o3 = new M("o3") // 第三种:Object.create() var p = {name: "p"} var o4 = Object.create(p) 复制代码
想详细了解的,请查看MVVM详解
1、什么是vdom?
Virtual DOM 用JS模拟DOM结构
复制代码
2、为什么要用vdom?
1. DOM操做很是很是“rang贵”,将DOM对比操做放在JS层,提升效率
2. DOM结构的对比,放在JS层来作(图灵完备语言:能实现逻辑代码的语言)
复制代码
3、vdom核心函数有哪些
核心函数: h('标签名', {...属性名...}, [...子元素...]) h('标签名', {...属性名...}, '.........') patch(container, vnode) patch(vnode, newVnode) 复制代码
Vue项目中实现路由按需加载(路由懒加载)的3中方式:
1. vue异步组件
2. es6提案的import()
3. webpack的require.ensure()
复制代码
1、Vue异步组件技术: { path: '/home', name: 'Home', component: resolve => reqire(['path路径'], resolve) } 2、es6提案的import() const Home = () => import('path路径') 3、webpack提供的require.ensure() { path: '/home', name: 'Home', component: r => require.ensure([],() => r(require('path路径')), 'demo') } 复制代码
想详细了解的小伙伴,请查看个人 从零开发一套完整的vue项目开发环境
Proxy的优势:
1. 能够直接监听对象而非属性,并返回一个新对象
2. 能够直接监听数值的变化
3. 能够劫持整个对象,并返回一个新对象
复制代码
Proxy的缺点:
Proxy是es6提供的新特性,兼容性很差,因此致使Vue3一致没有正式发布让让广大开发者使用
复制代码
Object.defineProperty的优势:
E9如下的版本不兼容
复制代码
Object.defineProperty的缺点:
1. 只能劫持对象的属性,咱们须要对每一个对象的每一个属性进行遍历,没法监控到数组下标的变化,致使直接经过数组的下标给数组设置值,不能实时响应
复制代码
想详细了解的小伙伴,请查看个人 从零实现一套属于本身的UI框架-发布到npm
props 和 $emit
父组件向子组件传递数量经过props传递
子组件向父组件传递经过$emit派发事件
parent
中央数据总线EventBus
ref 和 refs
Provide 和 inject
listeners
Vuex
生命周期:Vue实例从开始建立、初始化数据、编译模板、挂载DOM-》渲染、更新-》渲染、卸载等一系列过程,称为Vue的生命周期
vue.js的生命周期一共有10个: beforeCreate:实例初始化以后,this指向建立实例,不能访问到data、computed、watch、method上订单方法和数据 created:实例建立完成,可访问data、computed、watch、method上的方法和数据,未挂载到DOM,不能访问到$el属性,$ref属性内容为空数组 beforeMount:在挂载开始以前被调用,beforeMount以前,会找到对应的template,并编译成render函数 mounted:实例挂载到DOM上,此时能够经过DOMAPi获取到DOM节点,$ref属性能够访问 beforeUpdate:响应式数据更新时调用,发生在虚拟DOM打补丁以前 updated:虚拟DOM从新渲染和打补丁以后调用,组件DOM已经更新,可执行依赖于DOM的操做 activated:keep-alive开启时调用 deactivated:keep-alive关闭时调用 beforeDestroy:实例销毁以前调用。实例仍然彻底可用,this仍能获取到实例 destroy:实例销毁后调用,调用后,Vue实例指示的全部东西都会解绑定,全部的事件监听器会被移除,全部的子实例也会被销毁 复制代码
问题:渲染真实的DOM开销是很大的,修改了某个数据,若是直接渲染到真实dom上会引发整个DOM树的重绘和重排。
Virtual Dom 根据真实DOM生成的一个Virtual DOM,当Virtual DOM某个节点的数据改变后生成一个新的Vnode,而后Vnode和oldVnode做对比,发现有不同的地方就直接修改在真实的DOM上,而后使oldVnode的值为Vnode.
注意:在采起diff算法比较的时候,只会在同层级进行,不会跨层级比较。
当数据发生改变时,set方法会让调用Dep.notify()方法通知全部订阅者Watcher,订阅者就会调用patch函数给真实的DOM打补丁,更新响应的试图。
想详细了解的小伙伴,请查看个人 从零实现一套属于本身的UI框架-发布到npm
1、导航守卫大致分为三类:
1. 全局守卫钩子
2. 独享守卫钩子
3. 路由组件守卫钩子
复制代码
2、全局守卫钩子(在路由切换全局执行)
全局守卫钩子函数有三种:
const router = new VueRouter({....}) // 全局前置守卫 router.beforeEach((to, from, next) => { // do something }) // 全局解析守卫 router.beforeResolve((to, from, next) => { // do something }) // 全局后置守卫 router.afterEach((to, from) => { // do something }) 注意: to:route即将进入的路由 from:route即将离开的路由 next:function这个是必需要调用的 next()接受参数: next():直接执行下一个钩子,若是执行完了导航状态为comfirmed状态 next(false):中断当前导航,回到from的位置 next('/hello')或next({path:'/hello'}):路由到任意地址,能够携带参数等 next(error):会回到router.onError(callback) 复制代码
3、独享守卫钩子
独享守卫是定义在单独的某一个路由里的
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // do something }, beforeLeave: (to, from, next) => { // do something } } ] }) 复制代码
4、路由组件守卫钩子
路由组件便是在vue-router中注册的组件叫路由组件
beforeRouteEnter(to, from, next) {}
beforeRouteUpdate(to, from, next) {}
beforeRouteLeave(to,from, next){}
复制代码
Vuex 是一个专为 Vue 应用程序开发的状态管理模式。每个 Vuex 应用的核心就是 store(仓库)。
1. Vuex 的状态存储是响应式的;当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地获得高效更新
2. 改变 store 中的状态的惟一途径就是显式地提交 (commit) mutation,这样使得咱们能够方便地跟踪每个状态的变化
复制代码
Vuex主要包括如下几个核心模块:
1. State:定义了应用的状态数据
2. Getter:在 store 中定义“getter”(能够认为是 store 的计算属性),就像计算属性同样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被从新计算
3. Mutation:是惟一更改 store 中状态的方法,且必须是同步函数
4. Action:用于提交 mutation,而不是直接变动状态,能够包含任意异步操做
5. Module:容许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中
复制代码
vue.js是采用数据劫持结合发布者-订阅者模式的方式,经过Object.defineProperty()来劫持各个属性的setter和getter,在数据变更时发布消息给订阅者,触发相应的监听回调
Vue是一个典型的MVVM框架,模型(Model)只是普通的javascript对象,修改它则试图(View)会自动更新。这种设计让状态管理变得很是简单而直观
复制代码
Vue实现这种数据双向绑定的效果,须要三大模块:
1. Observer:可以对数据对象的全部属性进行监听,若有变更可拿到最新值并通知订阅者.
2. Compile:对每一个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数。
3. Watcher:连接Observer和Compile的桥梁,可以订阅并收到每一个属性变更的通知,执行指令绑定的相应的回调函数,从而更新试图。
复制代码
Observer(数据监听器)
Observer的核心是经过Object.defineProprtty()来监听数据的变更,这个函数内部能够定义setter和getter,每当数据发生变化,就会触发setter。这时候Observer就要通知订阅者,订阅者就是Watcher
Watcher(订阅者)
Watcher订阅者做为Observer和Compile之间通讯的桥梁,主要作的事情是:
1.在自身实例化时往属性订阅器(dep)里面添加本身
2.自身必须有一个update()方法
3.待属性变更dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调
Compile(指令解析器)
Compile主要作的事情是解析模板指令,将模板中变量替换成数据,而后初始化渲染页面视图,并将每一个指令对应的节点绑定更新函数,添加鉴定数据的订阅者,一旦数据有变更,收到通知,更新试图
复制代码
若小伙伴想详细了解Vue的MVVM源码实现,请查看 MVVM原理
若小伙伴想详细了解React生命周期,请查看 React生命周期
使用Redux应该遵循原则:
整个应用共享的state应该存储在store的状态数中,store是惟一的
state不能直接修改,只能经过action表达修改的意图,调用dispatch()修改state
state的修改规则reducers必须是一个纯函数,不能有反作用
Redux提供的API 一、createStore createStore方法的做用就是建立一个Redux store来存放应用中全部的state createStore(reducer, [preloadState], [enhancer]) createStore方法接受三个参数,后面两个是可选参数 reducer: 参数的类型必须是function preloadState: 这个参数表明初始化的state(initialState), 能够是任意类型的参数 enhancer: 这个参数表明添加的各类中间件,参数的类型必须是function createStore提供的方法: 一、getState() 返回当前的state 二、dispach(action) 参数action必须是一个对象,且必须含有type字段 三、subscribe(listener) 事件监听 二、combineReducers combineReducers主要是把多个reducer合并成一个,而且返回一个新的reducer函数,该函数接收的参数也是两个state和action 三、compose 主要是在中间件时候使用,合成函数 compose(applyMiddleware(thunk), window.devToolsExtension ? window.devToolsExtension() : undefined ) 四、applyMiddleware 五、bindActionCreator bindActionCreator的主要做用就是将aciton与dispatch函数绑定,生成直接能够出发action的函数 复制代码
1、HTTP/0.9
只有一个命令GET
没有HEADER等描述数据的信息
服务器发送完毕,就关闭TCP链接
2、HTTP/1.0
增长了不少命令
增长status code和header
多字符集支持、多部分发送、权限、缓存等
3、HTTP/1.1
持久链接
pipeline
增长host和其余命令
4、HTTP2
全部数据以二进制传输(之前是以字符串)
同一个链接里面发送多个请求再也不须要按照顺序来
头信息压缩以及推送等提升效率的功能
HTTP1.0定义了三种请求方法:GET(查)、POST(增)、HEAD
HTTP1.1新增了五种请求方法:OPTIONS、PUT(改)、DELETE(删)、TRACE、CONNECT
复制代码
HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。
客户端向服务器发送一个请求报文,请求报文:【请求方法、URL、协议版本、请求头部和请求数据】
服务器以一个状态行做为响应,响应的内容:【协议的版本、成功或失败代码、服务器信息、响应头部和响应数据】
复制代码
客户端链接到Web服务器
发送HTTP请求
服务器接受请求并返回HTTP响应
释放链接TCP链接
客户端(浏览器)解析HTML内容
简单快速
灵活
无链接
无状态
支持B/S、C/S模式
请求报文{ 请求行、请求头、空行、请求体 } 请求行:{http方法、页面地址、http协议、http版本} 响应报文{ 状态行、响应头、空行、响应体 }
GET---获取资源
POST---传输资源
PUT---更新资源
DELETE---删除资源
HEAD---获取报文首部
复制代码
GET在浏览器回退时时无害的,而POST会再次提交请求
GET请求会被浏览器主动缓存,而POST不会,除非手动设置
GET请求参数会被完整的保留在浏览器历史记录里,而POST中的参数不会被保留
GET请求在URL中传送的参数是有长度的限制,而POST没有限制
GET请求参数会暴露,不安全
GET参数经过URL传递,POST放在Requset Body中
复制代码
1xx:指示信息类,表示请求已接受,继续处理
2xx:指示成功类,表示请求已成功接受
3xx:指示重定向,表示要完成请求必须进行更近一步的操做
4xx:指示客户端错误,请求有语法错误或请求没法实现
复制代码
5xx:指示服务器错误,服务器未能实现合法的请求
200 OK:客户端请求成功
206 Partial Content:客户发送了一个带有Range头的GET请求,服务器完成了它(当时音频或视频文件很大时返回206)
301 Moved Permanently:所请求的页面已经转移至新的URL
302 Found:所请求的页面已经临时转移至新的URL
303 Not Modified:客户端有缓冲的文档并发出看一个条件性的请求,服务器告诉客户,原来缓冲的文档还能够继续使用
403 Forbidden:对请求页面的访问被禁止
404 Not Found:请求资源不存在
500 Internal Server Error:服务器发生不可预期的错误原来缓冲的文档还能够继续使用
503 Server Unavailable:请求未完成,服务器临时过载或宕机,一段时间后可恢复正常
复制代码
HTTP协议采用”请求-应答“模式,当使用普通模式,既非Keep-Alive模式时,每一个请求/应答客户和服务器都要新建一个链接,完成以后当即断开链接(HTTP协议为无链接的协议)
当使用Keep-Alive模式(又称持久链接、链接重用)时,Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后续请求时,Keep-Alive功能避免了创建或者从新创建链接
注意:keep-alive是1.1版本才有
复制代码
管线化技术:客户端能够发送屡次请求到服务器,而不须要等待上一次请求获得响应的时候才能进行下一次请求。实现并行发送请求 管线化机制经过持久链接完成,仅HTTP/1.1支持此技术 只有GET和HEAD请求能够进行管线化,而POST则有所限制
从输入URL到页面加载的主干流程以下:
1. 首先,在浏览器地址中输入url
2. 浏览器先查看**浏览器缓存**-系统缓存-路由器缓存,若是缓存中有,会直接在屏幕中显示页面内容。若没有,则跳到第三步操做
3. 浏览器向DNS(Domain Name System)服务器请求解析该URL中的域名对应的IP地址
4. 解析出IP地址后,根据该IP地址和默认端口80,和服务器创建TCP链接
5. 浏览器发出读取文件(URL中域名后面部分对应的文件)的HTTP请求,该请求报文做为TCP三次握手的第三个报文的数据发送给服务器
6. 服务器对浏览器请求作出响应,并把对应的html文本发送给浏览器
7. 释放TCP链接
8. 浏览器将该html文本并显示内容
复制代码
其中,步骤2的具体过程是:
1. **浏览器缓存**:浏览器会记录DNS一段时间,所以,只是第一个地方解析DNS请求;
2. **操做系统缓存:**若是在浏览器缓存中不包含这个记录,则会使系统调用操做系统,获取操做系统的记录(保存最近的DNS查询缓存);
3. **路由器缓存**:若是上述两个步骤均不能成功获取DNS记录,继续搜索路由器缓存;
4. **ISP缓存:**若上述均失败,继续向ISP搜索。
复制代码
DOM结构中的各个元素都有本身的盒子(模型),这些都须要浏览器根据格式的样式来计算并根据计算结果将元素放到它该出现的位置,这个过程称为reflow
当各个盒子的位置、大小以及其余属性,如颜色、字体大小等都肯定下来后,浏览器因而便把这些元素都按照各自的特性绘制了一遍,因而页面的内容出现了,这个过程称之为repaint
// 触发Reflow
当你增长、删除、修改DOM节点时,会致使Reflow或Repaint
当你移动DOM的位置,或是搞个动画的时候
当你修改CSS样式的时候
当你Resize窗口的时候(移动端没有这个问题),或是滚动的时候
当你修改网页的默认字体时
// 触发Repaint
DOM改动
CSS改动
// 如何防止重排Reflow和重绘Repaint?
复制代码
1. -webkit-:webkit核心浏览器,Chrome
2. -moz-:Gecko核心浏览器,fixfox
3. -o-:Opera核心浏览器,Opera
4. -ms-:微软的IE浏览器
复制代码
1. JSONP(只支持GET请求)
2. window + hash
3. window + domain
4. window + name
5. postMessage
6. WebSocket
7. CORS(Cross-origin resource sharing) 跨域资源共享(全部的HTTP请求)
8. nginx反向代理
复制代码
资源压缩合并、减小HTTP请求
非核心代码异步加载---------》异步加载的方式---------》异步加载的区别
利用浏览器缓存---------》缓存的分类-----------》缓存的原理【重点】
利用CDN
预解析DNS
<meta http-equiv="x-dns-prefetch-control" content="no"> <link rel="dns-prefetch" href="//host_name_to_prefetch.com"> 复制代码
1. 即时运行错误:代码错误;捕获方式:try...catch...、window.onerror
2. 资源加载错误;object.onerror(不会冒泡 )、performance.getEntries、Error事件捕获
复制代码
1. CSRF:(称为跨站请求伪造)(Cross-site request forgery)缩写CSRF
2. CSRF预防措施:Token验证、Refer验证(页面来源)、隐藏令牌
3. XSS缩写(cross-site scripting)跨域脚本攻击
复制代码
同源策略限制从一个源加载的文档或脚本如何与来自另外一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制
源======协议+域名+端口(默认为80)源不同就是跨域了
不一样源之间不能执行如下状况,如下状况都是同源时执行:
1. Cookie、LocalStorage和indexDB没法读取
2. DOM没法得到
3. AJAX请求不能发送
复制代码
1. 不一样浏览器的标签默认的margin和padding不同。*{margin:0;padding:0;}
2. IE6双边距bug:块属性标签float后,又有横行的margin状况下,在IE6显示margin比设置的大。hack:display:inline;将其转化为行内属性。
3. 设置较小高度标签(通常小于10px),在IE6,IE7中高度超出本身设置高度。hack:给超出高度的标签设置overflow:hidden;或者设置行高line-height 小于你设置的高度。
4. Chrome 中文界面下默认会将小于 12px 的文本强制按照 12px 显示,可经过加入 CSS 属性 -webkit-text-size-adjust: none; 解决。
5. 超连接访问事后hover样式就不出现了,被点击访问过的超连接样式再也不具备hover和active了。解决方法是改变CSS属性的排列顺序:L-V-H-A ( love hate ): a:link {} a:visited {} a:hover {} a:active {}
复制代码
很是喜欢的一段话:在咱们20岁的时候用30岁的心态来作事,那么当咱们30岁的时候就能够享受别人40岁的成功!~💪💪💪
若是本文对你有帮助得话,给本文点个赞❤️❤️❤️
欢迎你们加入,一块儿学习前端,共同进步!