总结一下学的知识,免得老是忘了,记录起来还有得复习。和大家共享,水平有限希望大家指正错误,热烈欢迎讨论,一个人学太孤单了。
HTML
- 行内元素、块级元素、空元素有哪些?
首先我们得了解一下这各种元素是什么,css规定每个元素都应该有默认的display的值。值为inline的就是行内元素,block则是块级元素。行内元素与其他元素共占一行,无法给它们设定宽高和上下边距(设置了也不会生效);块级元素则是独占一行,可以设定宽高和上下左右边距。空元素则是指元素中间没有内容,类似于单标签元素(注意,没有内容是指在html代码中而不是在页面上没有内容)。欢迎补充
行内元素:a,b,span,img,input,strong,select,label,em,button
块级元素:div,ul,li,dl,h系列,p,table,blockquote,form,ol
空元素:img,hr,br,link,meta,source,input
- <img>的标签上面,title和alt属性的区别是什么
首先title属性其实是全局属性,不仅仅是img标签才有的属性,如果我们给一个标签设置了title属性的话,鼠标悬停上面就可以显示。它可以用于给元素提供建议性的信息。
其次alt这个属于img的属性,它生效的地方就没有title那么广阔,它在图片加载失败的时候才会显示。作用是告诉用户这里本来应该显示什么图片。这里的加载失败其实包括了不支持图像显示或者关闭了图像显示的用户还有视觉障碍和使用屏幕阅读器的用户等(与语义化相关)
- 标签语义化的作用
1、我们经常说html负责页面的结构,但实际上去掉样式之后,页面的结构就不那么清晰了对吗?语义化可以通过nav、header等标签来确保当样式无法加载的时候,还能显示基本的页面结构。
2、有利于搜索引擎搜索,标签语义化之后,有爬虫依赖标签来确定上下文
3、方便其他设备解析,如盲人阅读器、移动设备等
4、便于团队开发和维护,使得代码更有可读性。
- html5有哪些新特性
1、html5已经不是SGML的子集,添加了图像、位置、存储,多任务等功能
2、拖拽释放(Drag和Drop)API
3、音频视频相关(audio和video)
4、画布
5、地理位置
6、离线存储
7、表单控制
- 等待
CSS
- link和@import的区别
我们都知道,外部引入 CSS 有2种方式,link
标签和@import
。
- 作用上:link是HTML的一个标签,不只是用来引入CSS文件,还可以定义 RSS、rel 连接属性等。而@import是css提供的语法规则,只用于导入样式表。
- 加载顺序的区别:加载页面时,由link引入的CSS文件被同时加载,而用import方法则在页面加载完毕以后再加载。
- 兼容性区别:link是HTML元素,在哪都能用;而link是CSS2.1才有的语法,IE5+才能用。不过现在基本上已经被全面支持。
- DOM操作可控性:前面说了,link是html标签,js能进行DOM操作,因此也能给页面添加link标签引入新的文件;而import就无法进行这样的操作了。
- 权重争议:这个问题由于时间关系本人在书写这部分内容时无法进行验证,请大家自行探索,涉及加载先后和浏览器工作的问题。
- css样式优先级计算
css样式优先级就涉及到了多种选择器,像是标签选择器、类选择器等,以下列出各种选择器的权重。
- 用户设定的浏览器样式:可以认为权重最最低,只有当完全没有设定样式时才会使用。
- 标签选择器:如p、div等,权重为 1 。
- 类选择器:如.container,权重为 10。
- id选择器:如#id,权重为100。
- 内联样式:写在html元素中的样式,权重为1000。
计算样式优先级的时候,根据该样式有对应的选择器,将所有的样式权重相加,数字大的则优先显示。权重相同时则按样式书写的先后进行显示。
PS:如height:100px!important;出现了 !important 字眼,则说明这个样式超越了权重,它有最高的优先级(不管其它的样式权重多大)。
- css的盒模型
首先要理解盒模型的概念:盒模型就是页面看上去元素的内容、内外边距、边框等内容组成的一张平面图,反应元素整体和各部分的宽高。使用box-sizing定义
盒模型分为两种,一种是W3C的标准盒模型(content-box),这种模型定义了宽高是固定的,就算我们给他定义了内边距以及边框,也不会改变元素的宽高,但是外边距会改变它与其他元素的距离;另一个种是IE的盒模型(border-box),我们给元素定义的宽高仅仅只是指元素内容的宽高,再定义内边距和边框,那么元素会变大,与我们预期的有差别。
不过,新增一个新的盒模型,padding-box。它表示元素的实际宽度等于我们设置的宽度加左右内边距。
- display:none、visible:hidden和opacity:0的区别
display元素彻底消失,不占据空间,脱离了文档流,并且子元素跟随父元素被隐藏,无法单独显示,其他的绑定时间无法触发。
visible:元素不可见,但不会脱离文档流,子元素可以通过设置visible来显示。绑定的事件也无法触发。
opacity:元素的透明度为0,子元素无法通过设置opacity来显示,并且不脱离文档流,绑定的事件依旧可以调用
- 未知宽高的图片水平垂直居中的几种方法
1、背景法
顾名思义就是把要显示的图片当做一个块级元素的背景使用,嘿嘿嘿,那我们岂不是想怎么定位就怎么定位?但是虽然这个方法不错,但是遇到那种动态改变图片的就GG喽,你说什么例子?淘宝电脑端 宝贝的图片呀。背景法代码像是下面这样(顺便复习了一下背景的写法 /狗头),center一个是代表横向居中,一个是竖向居中。
.mydiv {
width: 300px;
height: 300px;
background: url(imgUrl) center center no-repeat;
}
2、行高法
这个方法其实就是通过一个可以设置行高的元素,通过行高使得图片垂直居中。大家都设置差不多的行高,然后再用margin-top微调一下,这个方法很容易想到,只是不允许图片和文字出现在同一行中,否则永远都没法将两者对齐的。
3、利用display:table-cell
emmm。第一看到这个方法我是真没想到还有这种操作。通过给图片的父元素设置相关的属性来达到目的,下面的属性宽高和边框可以自定义。
.imgContainer {
width:100px;
height:100px;
border:1px solid black;
display:table-cell;
vertical-align:middle;
text-align:center;
}
4、一刀9999法
这个方法实在是太有特色了,你看了就知道为什么我会叫他一刀9999
.imgFather {
position:relative;
}
.imgFather img {
position:absolute;
margin:auto;
top:-9999px;
right:-9999px;
bottom:-9999px;
left:-9999px;
}
好多9999是吧,而且都是负的哦,别漏了子绝父相。其实也不一定得固定9999,大小可以根据具体情况写,图片越大,负得越多。
- 画一条0.5px的线
1、使用meta viewport的方式,实际上就是设置页面缩放倍数
<meta name="viewport" content="width=device-width,initial-scale=0.5,minimum-scale=0.5, maximum-scale=0.5"/>
2、采用transform:scale()的方式
transform: scale(0.5,0.5);
- 试试
JS
- js有的基本数据类型(具体细节后面下班回去再整理)
js有的基本类型其实和其他的语言很相似,有Number、String、Boolean、null、undefined和object这些基本类型。
其中,null和undefined是由object派生而来的类型,对null进行typeof操作,返回object字眼。null和undefined这两个类型只有一个值,就是null和undefined。
- 使用new操作符发生了什么
function Func(){
this.age = 1;
};
var newFunc=new Func ();
new操作符相信大家都知道通常在新建一个对象实例时使用。但是它实际上并没有这么简单。红宝书上面写了有四个过程,我这里把它搬过来。
function Func(){
this.age = 1;
};
var newFunc=new Func ();
var obj = new Object(); //1.创建一个新对象,并设置新对象的原型链
obj.__proto__ = Func.prototype
Func.call(obj); //2.将构造函数的作用域赋给了新对象(此时this指向了新对象)
obj.age = 1; //3.给新对象设定属性和方法
return obj; //4.将新建的对象obj返回
- call()和apply()方法
这两个方法这里就不细致说如何使用了,搜一下有很多的文章讲这些。个人觉得这两个方法的作用真正理解应该是:传入一个执行上下文,代替原先的执行上下文,也就是this指向的改变,或者可以说是作用域链(可参考高性能JavaScript这本书讲到的作用域链)的第一个作用域的修改。
此外这两个方法的区别是在从第二个参数起的部分。我们有时候使用类数组对象arguments来使用没有显式声明的函数参数。但是这个技巧在call方法不能使用,所有要使用的参数都得显示声明好;而apply方法可以使用arguments来灵活使用参数。
- eval()方法是做啥的?
这个方法可以将传入的参数(字符串)解析成js代码,然后马上执行。但我们不只是该关注这个解析字符串的点。
如果eval接收的参数不是字符串,那么它将原封不动的返回参数。此外,使用eval的开销非常大。大部分文章提到它要先解析字符串称为JavaScript代码,然后执行,因此消耗大。但是它背后的原理是什么?下面简单说一下
js执行的时候,会形成一个作用域链的东西,查询读取变量的时候就是根据作用域链一直往上查询直到全局的global对象(浏览器里面是window)。这意味着,我们所要的变量离当前作用域越远,那么访问它的代价就更大(因为查找的开销比较大)。而eval方法在执行的时候,会马上建立一个新的作用域,并将这个作用域放在作用域链的最前面(类似于链表头部插入一个节点),这个时候之前的所有变量会离我们当前的作用域更远,也就是访问时会有更大的开销。所以eval执行的时候会比普通的代码消耗更大。
eval还存在安全问题。
- 变量提升是什么?为什么会出现这种情况?
变量提升是指:在变量未曾声明之前调用该变量,但是不会报错。例如:
console.log(a); //undefined
var a = 6;
可以看到,这个语句没有报错,而且输出了undefined,这是变量只声明而没有赋值的情况。这是因为浏览器执行脚本的时候,会先检查一遍代码,先执行声明语句,再执行其他的语句。也就是说,上面代码其实等同于
var a;
console.log(a);
a = 6;
- typeof返回哪些数据类型
string、Boolean、number、undefined、object、function(注意 typeof null 会返回object)
- 显式和隐式类型转换
显式:number系列(parseInt,parseFloat,Number),同理String(),欢迎补充。注意toString()是一个方法,而不是类型转换的一种。(每个数据类型都有它对应的类,当我们调用一个类型的toString()方法时,浏览器会创建一个该类型的对象,然后调用该对象的toString方法)
隐式:==(等于号),+string(比如 +“1”能够把字符串类型的1变成数字)
- 事件委托的概念
事件委托即是将事件处理方法注册在另外一个元素上,通过目标元素触发事件后,可以通过冒泡或者捕获机制,等待事件传递到另一个元素上,由另一个元素执行这个处理方法。
比如说,某个父元素下有很多个子元素按钮,那么如果我们为每个按钮都注册点击事件(每个按钮都需要一个监听器),那么这样引起的性能开销是非常庞大的;我们可以给这些按钮的父元素注册点击事件,让他监听子元素的点击。然后使用event事件参数的target就能获得是哪个按钮被点击。(PS:这里可以顺便查一下event对象的详细知识)
- 前端跨域方法jsonp是什么?和ajax有什么不同?
浏览器有同源限制,当我们发送请求的目标服务器需要突破这个同源限制的时候就形成了跨域。浏览器默认不允许跨域(毕竟都有同源限制了,要是允许跨域哪来的同源限制)。不过对于HTML标签的src属性,浏览器不对其进行限制。那么这就有机可乘了。
jsonp是跨域方法的一种,利用的就是src属性能避开浏览器的限制这个特点。首先,jsonp在页面中创建一个script标签。然后给script标签设置src路径(像是get请求那样在路径里面包含要传递的数据和一个回调方法)。如下:
var scriptTag = document.createElement("script");
body.append(scriptTag);
scriptTag.scr = "www.xxxx.com?id=xxx&password=xxx&callback=handleData";
//服务器根据我们发送的数据处理完之后,返回一个 handleData(data); 这样的JS语句
//另一个地方定义了handleDAta方法
function handleData(data){
console.log(data);
}
这就等同于,我们在script标签里面调用了handleData的回调函数,这里的callback就是告诉服务器该调用哪个函数。时间关系写的不详细,具体知识可以自己学习。
可以看到,虽然我们像浏览器发送了请求,但是,实际上这个请求是浏览器的默认执行操作,看到src就自动去获取该路径的值,并且回调函数并不是由我们执行,而是由服务器返回的脚本执行。这样就存在安全隐患,万一服务器返回别的脚本呢?就算你信任你的服务器,万一请求在中途被拦截了呢?
- window.onload和document.ready的区别
简单来说,浏览器加载一个页面的过程是①加载html ②加载JS和CSS文件 ③加载图片(其实这个过程有些交错进行,具体细节还很多)。onload方法就是在第三步,就是页面所有内容都加载完毕后执行,ready方法则是在第一步即是完成页面结构后就执行。其实可以看到window本身就比document的范围要大,从可这个方面去理解。
- JavaScript的事件流模型
浏览器触发事件,这个事件从发生到传递到各个属性的过程就是事件流模型。说的比较抽象, 其实就是冒泡和捕获这些。
事件冒泡:从目标元素开始,事件逐步往上传递给父元素的过程;事件捕获:由最外面的父元素开始直到传递给到目标子元素。而事件流实际上被划分为三个阶段:捕获阶段==>处于目标阶段==>冒泡阶段。事件流模型的应用就是上面说到的事件委托。更详细的内容等我看完红宝书这一部分再进行补充。
- 关于作用域上下文(this)的理解
var User = {
count: 1,
getCount: function() {
return this.count;
}
};
console.log(User.getCount()); // what?
var func = User.getCount;
console.log(func()); // what?
问两处console输出什么?为什么?
答案:是1和undefined。
func是在window的上下文中被执行的,所以不会访问到count属性。
个人觉得这this的理解可以用前面提到的作用域链来解释。第一个输出语句,对于getCount来说,执行的时候,位于作用域链最前面的就是User对象的作用域,this指向了User对象,于是在这里访问count就是1。而第二个输出语句的时候,getCount的运行作用域就是全局,也就是说this指向的就是全局对象window,但是全局上并没有找到count属性,所以返回undefined。特别注意一下,箭头函数没有this,或者说箭头函数里面的this是函数定义时所在对象,而不是执行时的对象;箭头函数没有this也就不能被构造调用
- ajax的流程
(1)创建一个XMLHTTPRequest对象
var xhr = new XMLHttpRequest();
(2)打开请求
xhr.open('GET', 'example.txt', true);
(3)发送请求
xhr.send(); //发送请求到服务器
(4)监听readystate值的变化来决定执行的操作。
xhr.onreadystatechange =function(){}
(1)当readystate值从一个值变为另一个值时,都会触发readystatechange事件。
(2)当readystate==4时,表示已经接收到全部响应数据。
(3)当status ==200时,表示服务器成功返回页面和数据。
(4)如果(2)和(3)内容同时满足,则可以通过xhr.responseText,获得服务器返回的内容。
- 1 和 Number(1)的区别
首先数字的1是基本类型里面的数字类型,而Number(1)则时将基本类型的数据变成包装对象,变成了对象。那么包装对象有什么用?我们平时使用的一些常见的类型转换,比如:
1.toString();
3..fixed(2);
上面的代码是在一个基本类型数据上面调用了一个方法,可是,基本类型数据哪来的方法可以调用?其实这个过程就隐式的进行了上面说的包装对象的建立。将1变为带了值为1的包装对象,而这个对象是继承自Number这个对象,因而而可以调用Number的所有方法。PS:包装对象不是真的对象,不信用typeof检查 一下Number(1) 和 new Number(1)
- 添加、移除、移动、复制、创建和查找节点
appendChild() //添加
removeChild() //删除
replaceChild() //替换
insertBefore() //插入
createElement() //创建
createTextNode() //创建一个文本节点
getElementById() //按id查找
getElementsByTagName() //按标签名查找
getElementsByName() //通过name属性查找
- JS原型,和原型链
原型和原型链是在继承的知识点里面的。
原型可以理解成类似于我们其他编程语言里面的class一样的存在,如果我们构造调用一个函数(即像是val obj = new Person,称为构造调用),每一个新构造出来的对象他们都有一个原型属性[[protype]]指向他们的原型对象,如果new 一个上面说的Number类型的对象,那么它的原型对象就是Number,而Number则是他的构造函数。Number原型对象有一个Constructor属性指向它的构造函数。
- 数组扁平化
近日接触到数组扁平化这个问题,也就是说把像 [1,[2,2,[3],],4] 这样的数组变为像 [1,2,2,3,4] 这样的数组,方法有
①递归操作,判断数组元素是否为数组,是就继续递归
②toString(),使用toString()方法,可以直接将数组变为字符串,但是缺点是还需要用split方法转换为数组,但是注意一下,转化之后的数组元素实际上都是字符串而不是我们想要的数字
③使用reduce方法,数组的reduce方法接受前后两个元素,该方法还是递归,判断后一个元素的类型,用concat连接
④扩展运算符:ES6新增的...运算符,可以打开一层的数组,只要多次打开,就能把数组扁平化
- arguments是什么?
首先我们要明白它其实是个对象,重点强调是类数组对象,而不是数组!除了按索引可以读取函数实际传入参数之外,还有个arguments.length代表我们实际传入参数的个数,包括未曾声明但实际上有传入的参数。arguments的一个callee属性,指向的是拥有这个arguments对象的函数,即是函数本身,但是在严格模式下这个用法会报错。
- 函数又有哪些属性?
①函数名.caller,这个属性指向调用这个函数的函数,如果没有则指向当前函数。
②函数名.length,这个属性和上面的arguments.length别混淆了,函数的这个属性表示函数期待收到的参数个数,也就是指有声明的参数的个数。而arguments的是表示实际上传入的参数。(砸门应该知道JS函数的参数个数实际上没有限制吧?)
③函数名.prototype,指向函数的原型对象,如果使用构造调用函数,这个原型对象和我讲对象的原型对象就是用一个东西。(构造调用是啥?就是新建对象时。用new关键字的那种操作呀,忘记了请往上翻)
④函数名.bind(),bind大家估计很熟悉了吧,和call,apply并为改变this指向的三种方法。bind的第一个参数就是this的值,从第二个参数起,都算是传给函数的普通参数。(话说call和apply的区别是啥?)
- new.target???
你没看错,new关键字也开始有它的属性了,真是匪夷所思。new.target保存着new操作符所作用的那个函数或类,一般用在构造函数里,详情可以参考ES6的class部分。
function ff(){
console.log(new.target); //ff
};
let obj = new ff();
- Array.of()和Array.from()
①Array.of():为了弥补new Array()行为不一致的问题,而新增的方法,将传入的参数作为新数组的项
//行为不一致
let arr = new Array(10) //arr是length为10的数组
let arr1 = new Array(2,1) //arr1是[2,1]
let arr2 = Array.of(10) //arr2是[10]
②Array.from():用于将类数组对象和具有iterator接口的对象,转为真正的对象
- 判断一个变量是不是数组的方法
//使用instanceof
value instanceof Array
//使用Array.isArray
Array.isArray(value)
//使用Object.prototype.toString.call()
Object.prototype.toString.call() === '[object Array]'
//注意typeof [] === 'object'
- 数组的slice和splice方法
说实话我到现在才算是有点分的请了,slice是截取数组的一部分,但不改变数组;接受两个参数,表示起始和终止的位置。splice则是对原数组进行修改,接受三个参数,第一个表示修改起始位置,第二个参数表示往后去除的元素个数,第三个参数起则表示在起始位置插入元素。
let arr = [1,2,3,4,5,6];
let arr1 = arr.slice(0,1); //arr1==[1],arr不变
let arr2 = arr.splice(0,2,7,8,9) //arr == arr2 [7,8,9,3,4,5,6]
- 数据结构Set
set类似于数组,但是里面的元素都是唯一的,也就是说不存在重复的元素。值得注意的是,set里面,NaN是自等的,而两个对象总是不相等的(变量储存引用类型数据的时候,存的是内存地址的引用,因此就算两个对象属性和值都一模一样,也不会被认为是同个对象)。此外将数组或者其他具有iterable接口的数据结构作为参数转化为set的时候也不会改变每个元素的类型。
Set实例的属性有两个,一个是构造函数,一个是size表示实例里面成员的总数。
Set的操作方法有:①add(val):添加一个值,返回set本身;②delete(val)删除某个值,返回一个布尔值;③has(val)查看set里面是否有这个值;④clear():清除所有的成员,没有返回值。
Set的遍历方法有:①keys():返回键名的遍历器;②values():返回键值的遍历器;③entries():返回键值对的遍历器;④forEach():同数组的forEach。注意:Set结构没有键名,或者说,键名和值完全一致。所以keys()和values()的表现完全一致;Set本身也有遍历器,可以直接被for...of消费,实际上,keys和values方法其实都是指向了Set.prototype[Symbol.iterator]
- Map
object本质上是键值对的集合(哈希结构),但是只能用字符串作为它的健(字符串——值),这样限制了它的使用。Map就不一样了,Map类似于对象,但确实真正的键值对集合,它的健不局限于字符串,各种类型的值,包括对象都能作为它的健(值——值)。同Set一样,Map中,两个对象作为健值会被认为是不同键值,NaN也被视为是自等的。
Map属性有:size,同Set
Map操作方法:Map.set(key,value);Map.get(key);Map.has(key);Map.delete(key);clear();
Map的遍历方法和Set类似
- 创建对象的几种方法
①工厂模式:可以简单的创建一个对象,但是这只是将普通创建对象的过程进行了封装,并无法识别对象的类型(新建的对象都是Object)
function createObj(name, age, job) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.job = job;
obj.sayName = function(){
alert(this.name);
};
return obj;
}
var person = createObj("hhh", 12, "job");
//优点:封装了创建对象的步骤
//缺点:无法标识对象是哪种类型的实例
②构造函数模式:没有显示的创建对象、直接将属性和方法赋给了this对象,没有return语句。使用这种方法可以将对象实例标记为一种特定的类型。注意,所谓的构造函数实际上也是函数,它只是和普通函数的调用方式不同而已。
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
}
}
let person = new Person("hhh", 12, "job");
//优点:可以对新建的实例的类型进行标记,person.constructor == Person
//缺点:Person的方法要在每个对象上面实例化一遍。也就是说每个实例的sayName实际上是指向自己独立的匿名函数。我们原意是只需要一个sayName方法。
③原型模式:每个函数都有一个prototype属性,指向一个原型对象,上面包含了所有可以共享的属性和方法。
function Person(){
}
Person.prototype.name = "hhh";
Person.prototype.age = 12;
Person.prototype.job = "job";
Person.prototype.sayName = function(){
alert(this.name);
};
let person1 = new Person();
person1.name; //hhh
let person2 = new Person();
person2.name; //hhh
person2.name = "aaa"; //可以修改person2的属性,不影响原型对象上的属性
//优点:对象的属性和方法都可以被共享,也即是一份副本
//缺点:每个实例化的对象都应该有自己的属性,像上面的name。
// 虽然这个方法可以在实例上面修改我们想要的方法,但还是太繁琐了
④组合使用构造函数模式和原型模式:两种方式都各有各的优点和缺点,但是组合起来却是最符合我们想法的方式。属性独立,方法共享。
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.friends = ["shelby", "court"];
};
Person.prototype.sayName = function() {
alert(this.name);
}
let person1 = new Person("hhh", 20, "job");
//最常见的创建自定义类型的方式
⑤动态原型模式
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
if(typeof this.sayName != "function"){
Person.prototype.sayName = function(){
alert(this.name);
};
}
}
//创建对象的时候检查原型是否存在我们想要的方法,不存在则初始化
⑥寄生构造函数模式:除了使用 new 操作符并把使用的包装函数叫做构造函数之外,这个模式跟工厂模式其实
是一模一样的。但是构造函数有自己的返回值的时候,会改变new操作符最后返回的对象。
function Person(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o;
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName(); //"Nicholas"
//缺点:返回的对象o,和函数Person以及Person.prototype没有任何关系。也就是说实际上这样的写法只是封装了创建对象的操作而已。
⑦稳妥构造函数模式:实例对象没有属性,新创建对象的实例方法不引用 this;不使用 new 操作符调用构造函数。
function Person(name, age, job){
//创建要返回的对象
var o = new Object();
//可以在这里定义私有变量和函数
//添加方法
o.sayName = function(){
alert(name);
};
//返回对象
return o;
}
//优点:除了使用函数之外,没有任何方法能访问name和age等
- Object.create()方法和Object.assign()
//Object.create(obj),这个方法个人觉得是作为简单继承的一个快速方法。
//它的作用就是创建一个新对象,并且新对象的原型对象是作为参数传入的对象。
let person = {
name:"哈哈哈",
age:16
};
let child = Object.create(person);
child.__proto__ == person; //true
//Object.assign(tag, source),方法用于将所有可枚举属性的值从一个或多个源对象(source)复制到目标对象(tag)。它将返回目标对象。
let tag = {a:1, b:2};
let source = {b:4, c:5};
let returnObj = Object.assign(tag, source);
tag; //{a:1, b:4, c:5}
returnObj; //{a:1, b:4, c:5}
tag == returnObj; //true
/**PS:①如果目标的属性名与源对象的属性名出现重复,那么目标对象的属性值会被覆盖
* ②多个源对象时,如果出现属性名重复,那么后传入的源对象的属性值将会覆盖写在前面的源对象的属性值。
* ③此方法只会拷贝源对象自身的,且能被枚举的属性
* ④此方法仅能进行浅克隆
*/
- 正则表达式RegExp对象的方法
1.test():test方法用来检测一个字符串是否符合正则表达式,符合返回true,否则返回false
2.exec():exec方法
3.compile
- 宿舍
Vue相关
- 计算(computed)和监听(watch)的区别
我就不赘述什么是计算和监听啦,讲这些的一搜一大堆文章(不过还是推荐文档,原汁原味)。很多人可能会像我一样一开始觉得这两个东西好相似。但是你再仔细阅读以下官方文档就会发现:
计算(computed),它就是为了计算而生的呀!首先,计算是依据别的数据或者其他的什么计算得到的,但是,它能缓存呀,能缓存就意味着,我要是用的多了,我不用每次都计算啊。这样是不是很省代码和性能?(小的计算看不出好处,但是遇到了超级大的计算量,而且计算出来的东西又是另一个要计算出来的东西B的依赖,那你就知道他的好处的)
监听(watch),看名字就知道它侧重在哪啦。它的用途更多是偏向于重点关注某个对象,然后执行一些逻辑,这些逻辑有可能是发送请求啊,修改数据啥的,可以但不一定非得是计算。
- MVVM模型
(上个图,摘自https://www.jianshu.com/p/9fda134cf998)
计网
- TCP连接三次握手
第一次握手:客户端发起,将标志位SYN标志为1,seq值i则是随机产生,然后将该数据包发送给Server,客户端等待Server的回复。
第二次握手:服务器回应第一次握手,从SYN位知道客户端想要建立连接。服务器将SYN标志为1,ACK也为1,ack则是上面的seq的值加1,为i+1,也生成自己的seq,值为 j,并将包发给客户端,此后等待客户端回应。
第三次握手:客户端检查收到的包,ack是否为之前的 i+1,ACK是否为 1,如果都是,那么则将ACK标志为1,ack则是j+1。
经过三次握手之后,客户端和服务器端就建立连接了。
- TCP断开四次挥手
第一次挥手:客户端发起,带FIN关键字的包,表示想要断开连接。
第二次挥手:服务器端收到客户端的FIN包之后,发送一个ACK答复给客户端。此时,TCP已经是单向接通(服务器到客户端)
第三次挥手:服务器留着单向通道也没用,于是他也发送FIN告诉客户端断开连接。
第四次挥手:客户端接收到FIN包之后,发送一个ACK确认给服务器,确认断开连接
至此,双向连接通道关闭。
- 为什么一定要三次握手和四次挥手
假设握手次数只有两次:那么服务器端实际上在答复客户端之后就认为建立了连接,维持通道畅通。但是这个回复可能会出现丢失的情况,这时候客户端方面是认为服务器没有答复,没有建立连接就不会有接下来的请求。而服务器端依旧维持通道等待接受请求,这样浪费了一定资源。
四次挥手除了和三次握手相似的确保两端收到信息的意思之外,还有因为TCP是双向连接的,因此断开的话也需要双向确认断开。
- TCP是可靠的字节流传输服务
TCP面向连接,可靠的原因:
①数据包校验,用过seq和ack序列号来确认双方都能接收到的包到底是哪个,如果序列号有问题则能发现传输出现了问题。
②对序号出现问题的包重排序:数据包传输的时候,由于网络情况不同可能造成先发后至的情况,此时接受顺序出现了乱序,TCP连接能对这种情况重新排序。
③丢失包/超时重发:这里的丢失包指的不仅仅是丢失,也指超过规定时间还没收到答复的数据包。双方如果出现这种情况则会进行重发数据包的操作,确保数据不丢失。
④流量控制:通过接受和发送窗口的大小(滑动窗口协议)来控制一段时间内发送数据包的数量
- POST和GET方法的区别
①语义上不同:get表示从服务器上面获取资源,而POST表示向服务器提交资源。
②GET方法规定是幂等的,意思是不管请求多少次,得到的结果是一样的(实际上不一定)。POST则不是。
③安全性而言:get只是获取资源,相对于post提交资源来说,get比较安全
④
- 常见的HTTP状态码
2开头表示成功处理了请求
200 服务器已成功处理了请求
201 请求成功并且服务器创建了新的资源
202 服务器已经接受请求,但尚未开始处理
203 服务器已经成功处理信息,但返回的信息可能来自于另一来源
204 服务器已经处理了请求,但没有返回任何内容
3开头的表示要完成请求得进一步操作(重定向)
300 要处理请求有多种操作,请客户端选择
301 请求的内容已经永久移动到新位置
302 临时移动,服务器从不同的URL返回结果,并且要求客户端继续使用原先地址
303 查看其他位置,
304 未修改,自从上次请求后,网页没有修改过,可以使用缓存
4开头表示请求出现了错误
400 错误请求,服务器不理解请求的语法
401 未授权,要求客户端进行身份验证
403 禁止,服务器拒绝请求
404 未找到,服务器找不到请求的资源
5开头表示服务器出现了错误
500 服务器内部错误,服务器在处理请求过程中遇到了错误,无法完成请求
501 尚未实施,服务器不具备完成请求的能力。
502 错误网关,服务器作为网管或代理,从上游服务器收到无效响应
503 服务不可用,服务器由于超载或停机暂时无法给用户提供服务
504 网关超时,服务器作为网关或者代理,没有及时收到上游服务器的响应
- 常见的首部字段
HTTP首部字段包括了四种字段,分别是通用首部字段、请求首部字段、响应首部字段和实体首部字段。
1、通用首部字段:
Cache-Control字段:通过设置该字段的一些列指令,可以控制缓存的工作,指令有no-cache(强制向服务器再次验证)、no-store(不缓存请求或响应的任何内容)
Connection字段:管理持久连接,close指令为断开,而keep-alive为持久连接
Data字段:首部字段表明创建HTTP报文的日期和时间
Transfer-Encoding字段:规定了传输报文主体时采用的编码方式。
2、请求首部字段:
Accept字段:通知浏览器用户能处理的文件格式
Accept-charset:客户端能接受的字符集
Accept-Encoding:客户端能接收的编码格式
Accept-language:客户端接收的语言
3、实体首部字段
content-type:主体的内容
content-Encoding:主体的编码格式
content-language:主体使用的语言
- HTTPS秘钥交换过程
1、客户端首先使用HTTP请求服务端的证书
2、服务器将证书及公钥发送给客户端,自己保留该公钥对应的私钥
3、客户端对证书的时间和信息等进行检验,确认之后生成一串随机数,使用服务器给的公钥进行加密,然后将其发送到服务器。
4、服务器对收到的随机数进行解密,这个就是以后两端通信对称加密的秘钥。
PS:中间还涉及摘要和数字签名的验证信息,这里为了突出秘钥交换的步骤就省略不写
- 一次完整的HTTP请求过程
- Cache-Control指令
指令 | 参数 | 说明 |
---|---|---|
no-cache | 无 | 强制向源服务器再次验证 |
no-store | 无 | 不缓存请求或响应的任何内容 |
max-age=[秒] | 必需 | 响应的最大Age值 |
max-stake(=[秒]) | 可省略 | 接收已经过期的西安银行 |
min-fresh=[秒] | 必需 | 期望在制定时间内的响应仍有效 |
no-transform | 无 | 代理不可更改媒体类型 |
only-if-cached | 无 | 从缓存获取资源 |
cache-extension | - | 新指令标记(token) |
指令 | 参数 | 说明 |
---|---|---|
public | 无 | 可向任意方提供响应的缓存 |
private | 可省略 | 仅向特定用户返回响应 |
no-cache | 可省略 | 缓存前必须先确认其有效性 |
no-storage | 无 | 不缓存请求或响应的任何内容 |
no-transform | 无 | 代理不可更改媒体类型 |
must-revalidate | 无 | 可缓存但必须再向元服务器进行确认 |
proxy-revalidate | 无 | 要求中间缓存服务器对缓存的响应有效性进行确认 |
max-age=[秒] | 必需 | 响应的最大Age值 |
s-maxage=[秒] | 必需 | 公共缓存服务器响应的最大Age值 |
cache-extension | - | 新指令标记(token) |
- 是是是
其他
- 常见排序算法
https://blog.csdn.net/weixin_42003972/article/details/100855944
- 浏览器工作原理(这里简单搬运一下,剩下的编译原理方面的知识有兴趣可以查看大佬写的文章:https://kb.cnblogs.com/page/129756/)
浏览器是我前端的好伙伴,不管代码运行或者调试等方面基本上在浏览器上面运行,我们确实应该花点时间学习下浏览器的相关情况了。
一、浏览器的组成:
①用户界面,就是浏览器的菜单,前进后退地址栏等;
②浏览器引擎:用来查询和渲染引擎的接口。
③渲染引擎:用来显示请求的内容,也就是页面,负责解析html和css
④网络:浏览器上网肯定离不开网络部分的功能啊,毕竟总得请求数据和页面嘛
⑤UI后端:用来绘制基本组件,底层和操作系统交互
⑥JS解释器:注意,是解释器而不是编译器。相信大部分人在学JavaScript之前都是学c、java等语言,他们有编译器,但是js没有,js是弱语言。
⑦数据存储:持久层的内容,在硬盘中保存各种数据
二、渲染引擎
渲染引擎就是负责渲染,在浏览器窗口显示所请求的内容。不同浏览器的渲染引擎不一样,火狐的是Mozilla,Safari和Chrome使用的是webkit,引擎不一样,那么实现的方式和支持的东西就不一样,因此才会引出兼容性这样的问题。
渲染引擎的工作流程为:构建DOM树==》构建渲染树==》布局渲染树==》绘制
解析html文件,将每个标签转化为DOM树的节点。接着解析各种css代码中的样式信息,来构建渲染树。渲染树包含有颜色和大小等属性的矩形组成,然后按照正确的顺序显示到屏幕上。渲染树构建好了之后,将会进行布局过程,确定每个节点在屏幕上面的位置,再下一步就是绘制即是遍历渲染树,使用UI后端绘制每个节点。
这个过程其实不是严格按照顺序执行的,为了用户体验,可能在渲染第一个节点的时候,还在同时解析html和css代码,也就是说边绘制边继续解析。
- 输入一个网址到页面显示的过程发生了什么
①域名解析:浏览器根据域名,查找对应的IP地址(DNS服务)。浏览器先查找自身的DNS缓存,然后是操作系统的缓存,然后是查找hosts文件,没有则是DNS服务器查找。
②TCP链接:HTTP请求是基于TCP实现的,在高层连接之前,要先经过三次握手连接TCP。上面拿到域名的IP地址之后,浏览器以电脑某个随机端口为基础,像服务器发送连接请求,经过TCP三次握手
③发送请求:浏览器发送HTTP请求相关的资源。客户端一次发送请求行和请求头(以空行表示结束),web服务器应答,发送应答头和数据
④服务器响应:服务器响应客户端的请求,然后返回相应的内容。(③和④其实还涉及到浏览器缓存的问题,具体可以查查看)
⑤解析资源:浏览器对得到的内容进行解析,构成DOM树及渲染树等
⑥页面呈现:浏览器的UI后端绘制页面,最终能显示页面。
- 前端性能优化
前端性能不佳的根本原因就是用户觉得等待时间太久了没有从浏览器上面得到回应,我们只要想办法不让用户等太久即可。常见的就是对代码进行优化,此外还有其他的方法
①减少HTTP请求:尽量将脚本和样式表合并,因为每引入一个脚本和样式表,就得请求一次。
②减小每次请求内容的大小:一个手段是精灵图,它将多个图片合成一张,这样总大小比一张一张的图片要小。还有就是压缩脚本和css文件等
③利用缓存:很多页面其实短时间内不会做出改变(请求得到的数据的改变不算在前端),那么可以利用缓存机制,将内容缓存起来,减少DNS查找也加快了返回速度。
④页面结构:阻塞浏览器解析的内容(如脚本)放在底部,而用户看得到的样式内容则放在顶部,这样能更快加载出页面。
⑤代码优化:代码优化不仅是常见的算法上的优化,还包括了减少DOM操作(这样能减少页面重排重绘的情况);css代码少用表达式
- 前端三大存储的区别
1.从与服务器间的交互上看:cookie数据会随着每次请求传递到服务器,服务器端可以写cookie,但是sessionStorage和localStorage仅在本地保存,不会发送给服务器。
2.从存储大小上看:由于每次都要往返客户端与服务器之间的缘故,所以cookie数据大小不超过4k,其他两个要原比cookie大,可以达到5M或者更多。
3.有效时间:localStorage假如不删除的话,将会永久有效;sessionStorage只在页面存活期间有效,也就是说关闭页面后被删除;cookie则是看设置的有效时长
- 渐进增强和优雅降级
渐进增强:由于每个用户的浏览器都不尽相同,所以给每个用户看到一模一样的界面是不太现实的,于是在保证核心功能的情况下,给用户提供他们所能支持的最好体验。这就是渐进增强。
优雅降级:给用户提供最好的体验,遇到低版本的浏览器就做兼容处理。
不同:①前者是向上兼容,后者是向下兼容;②前者从简单到复杂,后者从复杂到简单;③前者关注内容,后者关注体验。
- web worker
我们都知道JavaScript执行的时候是单线程运行,但是这样也会阻塞后面代码的运行。web worker则是运行在后台的另一个js,它会将结果返回主线程,这样子可以利用它来做些非常耗时计算和操作
- cookie和session的区别
1、cookie放在浏览器上,而session放在服务器上面
2、由于cookie可以通过前端文件进行读取,因而它不安丘
3、session在一定时间内保存在服务器上,这占用了浏览器的资源
- 懒加载和预加载
①懒加载:懒加载也叫延时加载,意思是延迟在家网络资源或者当符合条件的时候才加载资源,比如图片的延时加载。其主要目的是为了减少服务器负载,适用图片很多页面很长的电商网站。少量分批次加载能够减少用户等待的时间,减少了无效资源的加载;过多的资源加载容易阻塞js的加载。实现原理是监听页面滚动,当我们要加载的图片进入页面时,修改它的src属性
②预加载:预加载是提前加载图片,存放到本地缓存中,需要时可以直接进行渲染。这样做可以减少用户的等待时间,因为接下来的资源已经被加载好了。不过这样会增加前端服务器的压力
- 宿舍