每日一题
- 2020-08-04
- 2020-08-05
- 2020-08-06
- 2020-08-07
- 2020-08-08
- 2020-08-09
- 2020-08-10
- 2020-08-11
- 2020-08-12
- 2020-08-13
- 2020-08-14
- 2020-08-15
- 2020-08-16
- 2020-08-17
- 2020-08-18
- 2020-08-19
- 2020-08-20
- 2020-08-21
- 2020-08-22
- 2020-08-23
- 2020-08-24
- 2020-08-25
- 2020-08-26
- 2020-08-27
- 2020-08-28
- 2020-08-29
- 2020-08-30
- 2020-08-31
- 2020-09-01
- 2020-09-02
2020-08-04
Object.defineProperty(object, propertyName, descriptorObject)
在ES中有两种属性,一种是数据属性,一种是访问器属性。
1. 数据属性
- configurable:表示能否通过delete删除属性从而重新定义属性。默认值为true。
- enumerable:表示能否通过for-in循环返回属性。默认值为true。
- writable:表示能否修改属性的值。默认值为true。
- value:包含这个属性的数据值。默认值为undefined。
2. 访问器属性
- configurable:表示能否通过delete删除属性从而重新定义属性。默认值为true。
- enumerable:表示能否通过for-in循环返回属性。默认值为true。
- get:在读取属性时调用的函数。默认值为undefined。
- set:在写入属性时调用的函数。默认值为undefined。
想要修改属性默认的特性都得通过ES5的Object.defineProperty()方法。这个方法接收三个参数:
- object:属性所在的对象;
- propertyName:属性的名字;
- descriptorObject:描述符对象;
// 像这样直接在对象上定义属性时,其数据属性的特性除value外都为true,value的值为"Lgowen"
var person = {
name: "Lgowen"
};
----------------------------------------------------
var obj = {};
Object.defineProperty(obj, "name", {
configurable:false, //当设置configuable属性为false时,则无法删除属性name的值,且设置为false之后则无法将其修改为true。
writable:false,
value:"Lgowen"
})
delete obj.name; // 在严格模式下会导致错误
obj.name = "lgowen";
console.log(obj.name) //依然可以打印出 "Lgowen" 而没有删除掉且没有被修改成lgowen
var obj = {};
Object.defineProperty(obj, "name", {
enumerable:false, //当设置enumerable属性为false时,则无法枚举
value:"Lgowen"
})
----------------------------------------------------
var personOne = {};
Object.defineProperty(personOne, "name", {
enumerable: false,
value:"Lgowen"
})
for(var i in personOne){
console.log(personOne[i]); //不会有打印
}
var personTwo = {};
Object.defineProperty(personTwo, "name", {
enumerable: true,
value:"Lgowen"
})
for(var i in personTwo){
console.log(personTwo[i]); // "Lgowen"
}
----------------------------------------------------
// 使用访问器属性的常见方式,即设置一个属性的值会导致其他属性发生变化。
// 如果一个对象的普通数据属性与访问器属性同名时,则会访问器属性则会覆盖这个普通数据属性。
var obj = {
_year: 2004,
edition: 2
}
// 为obj对象定义了一个访问器属性year,getter和setter函数不是必要。
// 在读取访问器属性时,会调用其getter函数,这个函数负责返回有效的值。若无定义,则这个访问器属性的值为undefined。
// 在写入访问器属性时,会调用其setter函数,这个函数负责决定如何处理数据。
Object.defineProperty(obj, "year", {
get: function () {
return this._year
},
set: function (newValue) {
if (newValue > 2004) {
this._year = newValue;
this.edition += 1;
}
}
})
console.log(obj.year); //访问obj对象中的year访问器属性时,在读取该属性时调用了其get方法,返回了obj._year的值,即2004。
obj.year = 2005; //修改obj对象中的year访问器属性的值时,调用了set方法,修改了year值的同时,将其值赋值给了_year,且edition的值也发生了改变。
2020-08-05
function中的toString()方法
//实现一个累加函数
//add(1) -> 1
//add(1,2) -> 3
//add(1)(2) -> 3
//add(1,2)(3) -> 6
//以此类推
首先我们应该想到,这一个函数应该是一个不定参的函数,每次可接收的参数不一定,所以我们不应该写死,因此我们容易可以想到利用函数中的arguments类数组来实现不定参的累加。
function add() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
}
到这里我们应该可以想到这一个函数的返回值必须也是一个函数,才能在函数调用之后继续调用。返回的这个函数是干嘛的呢,我们应该也容易想到干的事是跟上一次调用是一样的事情。
function add() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return function () {
var _sum = 0;
for (var j = 0; j < arguments.length; j++) {
_sum += arguments[j];
}
}
}
那这个函数要怎么出结果呢?我们从第一次调用开始入手,既然这一个函数的返回值也是一个函数,那么我们怎么得到我们想要的第一次 的结果。这时候函数的toString()方法会自动调用,我们可以通过重写toString()方法来改变其返回结果。但是由于我们返回的函数是一个匿名函数,无法重写其toString()方法,因此我们可以有下面操作。
function add() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
function _add() {
var _sum = 0;
for (var j = 0; j < arguments.length; j++) {
_sum += arguments[j];
}
}
_add.toString = function () {
return sum
}
return _add
}
上面的方法已经能够得到我们第一次调用想要的结果,接下来我们只需要递归重复实现以上操作则可以实现我们的需求。则在第二次调用的时候返回前两次相加的结果即为sum + _sum。反复进行自身调用当最后返回值为函数时停止。
function add() {
// 得到第一次调用的和
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
function _add() {
// 得到第二次调用的和
var _sum = 0;
for (var j = 0; j < arguments.length; j++) {
_sum += arguments[j];
}
return add(sum + _sum) // 递归调用
}
// 返回结果
_add.toString = function () {
return sum
}
return _add
}
2020-08-06
京东校招前端笔试
- 正则表达式
- JS特点
- 双重散列探查法 (hi=(h(key)+di)%m 1≤i≤m-1)
- http状态码
- http请求头格式
- && 和 || 运算符
- 二叉树
- http与https的区别
- 连通图
- 时间复杂度
- 顺序查找算法
- 项目工程中的package.json文件
- overflow
- setInterval
- linux中文件权限-rwxr–rw-
- DOM对象模型(第二层)
- HTML中的链接
- CSS样式优先级
- 求和函数
- 最长公共子序列
2020-08-07
什么是HTTP
超文本传输协议(Hypertext Transfer Protocol)
1.超文本(Hypertext)
在以前我们无法和别的电脑进行交互的时候,我们的数据信息只能保存在本地,通常是以文本这种简单的形式存在。而文本是一种能够被计算机解析的有意义的二进制数据包随着发展,当两台电脑能够进行数据传输交互的时候,人们不满足于简单的文字传输,也就有了后面的图片、音频、视频或者点击文字或者图片会进行超链接的跳转,这个时候扩大后语义的文本也就成为了现在的超文本。
2.传输(Transfer):包括超文本
由传输载体(例如电话线、光缆)负责把生成的二进制数据包由一个计算机终端传输到另一个计算机终端的过程,可以称为传输。
通常我们把传输数据包的一方称为请求方,接收数据包的一方称为应答方。当然请求方也可以作为应答方接受数据,应答方可以作为请求方发送数据。
3.协议(Protocol):包括传输和超文本
协议的前提条件必须是一个多人约定,自己跟自己的约定不属于协议。
那么网络协议是什么?
网络协议就是网络中(包括互联网)传递、管理信息的一些规范。计算机的相互通信需要共同遵守一定的规则,那么这些规则就叫做网络协议。
简单总结之后,我们可以理解HTTP是计算机里用于两点之间传输超文本数据的约定和协议
与HTTP相关的组件
网络模型
为了给网络协议的设计提供一个结构,网络设计者以分层(layer)的方式组织协议。每一层都是向它的上一层提供服务(service),即所谓的服务模型(service)。每个分层中所有的协议称为协议栈(protocol stack)。因特网的协议栈由五个部分组成:物理层、链路层、网络层、运输层和应用层。
应用层
应用层是网络应用程序和网络协议存放的分层,因特网的应用层包括许多协议,例如我们学web离不开的HTTP,电子邮件传送协议SMTP、端系统文件上传协议FTP、还有为我们进行域名解析的DNS协议。应用层协议分布在多个端系统上,一个端系统应用程序与另外一个端系统应用程序交换信息分组,我们把位于应用层的信息分组称为报文(message)。
运输层
因特网的运输层在应用程序断电之间传送应用程序报文,在这一层主要有两种传输协议TCP和UDP,利用这两者中的任何一个都能够传输报文,不过这两种协议有巨大的不同。
TCP向它的应用程序提供了面向连接的服务,它能够控制并确认报文是否到达,并提供了拥塞机制来控制网络传输,因此当网络拥塞时,会抑制其传输速率。
UDP协议向它的应用程序提供了无连接服务。它不具备可靠性的特征,没有流量控制,也没有拥塞控制。我们把运输层的分组称为报文段(segment)。
网络层
因特网的网络层负责将称为数据报(datagram)的网络分层从一台主机移动到另一台主机。网络层一个非常重要的协议是IP协议,所有具有网络层的因特网组件都必须运行IP协议,IP协议是一种网际协议,除了IP协议外,网络层还包括其他一些网际协议和路由选择协议,一般把网络层就称为IP层,由此可知IP协议的重要性。
链路层
现在我们有了应用程序通信的协议,有了给应用程序提供运输的协议,还有了用于约定发送位置的IP协议,那么如何才能真正的发送数据呢?为了将分组从一个节点(主机或路由器)运输到另一个节点。网络层必须依靠链路层提供服务。链路层的例子包括以太网、WIFI和电缆接入的DOCSIS协议,因为数据从源目的地传送通常需要经过几条链路,一个数据包可能被沿途不同的链路层协议处理,我们把链路层的分组称为帧(frame)
物理层
虽然链路层的作用是将帧从一个端系统运输到另一个端系统,而物理层的作用是将帧中的一个个比特从一个节点运输到另一个节点,物理层的协议仍然使用链路层协议,这些协议与实习的物理传输介质有关,例如,以太网有很多物理层协议:关于双绞铜线、关于同轴电缆、关于光纤等等。
五层网络的示意图如下
OSI 模型
我们上面讨论的计算机网络协议模型不是唯一的协议栈,ISO(国际标准化组织)提出来计算机网络应该按照7层来组织,那么7层网络协议栈与5层的区别在哪里?
容易看出,OSI模型要比网络模型多了表示层和会话层,其他层基本一致。表示层主要包括数据压缩和数据加密以及数据描述,数据描述使得应用程序不必担心计算机内部存储格式的问题,而会话层提供了数据交换的定界和同步功能,包括建立检查点和恢复方案。
浏览器
就如同各大邮箱使用电子邮件传送协议SMTP一样,浏览器是使用HTTP协议的主要载体。浏览器正式的名字叫做Web Broser,顾名思义,就是检索、查看互联网上网页资源的应用程序,名字里的Web,实际上指的就是World Wide Web,也就是万维网。
我们在地址栏输入URL(即网址),浏览器会向DNS(域名服务器)提供网址,由它来完成URL到IP地址的映射。然后将请求你的请求提交给具体的服务器,再由服务器返回我们想要的结果(以HTML编码格式返回给浏览器),浏览器执行HTML编码,将结果显示在浏览器的正文。这就是一个浏览器发送请求和接受响应的过程。
Web服务器
Web服务器的正式名称叫做Web Server,Web服务器一般指的是网站服务器,上面说到浏览器是HTTP请求的发起方,那么Web服务器就是HTTP请求的应答方,Web服务器可以向浏览器等Web客户端提供文档,也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载。目前最主流的三个+Web服务器是Apache、Nginx、IIS。
CDN
CDN的全称是Content Delivery Network,即内容分发网络,它应用了HTTP协议里的缓存和代理技术,代替源站响应客户端的请求。CDN是构建在现有网络基础之上的网络,它依靠部署在各地的边缘服务器 ,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络阻塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。
WAF
WAF是一种Web应用程序防护系统(Web Application Firewall,简称WAF),它是一种通过执行一系列针对HTTP/HTTPS安全策略来专门为Web应用提供保护的一款产品,它是应用层面的防火墙,专门检测HTTP流量,是防护Web应用的安全技术。
WAF通过位于Web服务器之前,可以阻止如SQL注入、跨站脚本等攻击,目前应用较多的一个开源项目是ModSecurity,它能够完全集成进Apache或Nginx
HTML
HTML称为超文本标记语言,是一种标识性的语言,它包括一系列标签,通过这些标签可以将网络上的文档格式统一,使分散的Internet资料连接为一个逻辑整体。HTML文本是由HTML命令组成的描述性文本,HTML命令可以说明文字,图形、动画、声音、表格、链接等。
Web 页面构成
Web页面(Web page)也叫做文档,是由一个个对象组成的。一个对象(Object)只是一个文件,比如一个HTML文件、一个JPEG图形、一个Java小程序或一个视频片段,它们在网络中可以通过URL地址寻址。多数的Web页面含有一个HTML基本文件以及几个引用对象。
与HTTP相关的协议
在互联网中,任何协议都不会单独的完成信息交换,HTTP也一样。虽然HTTP属于应用层的协议,但是它仍然需要其他层次协议的配合完成信息的交换,那么在完成一次HTTP请求和响应的过程中,需要哪些协议的配合。
TCP/IP
TCP/IP协议你一定听过,TCP/IP我们一般称之为协议簇,什么意思呢?就是TCP/IP协议簇中不仅仅只有TCP协议和IP协议,它是一系列网络通信协议的统称。而其中最核心的两个协议就是TCP/IP协议,其他的还有UDP、ICMP、ARP等等,共同构成了一个复杂但有层次的协议栈。
TCP协议的全称是Transmission Control Protocol的缩写,意思是传输控制协议,HTTP使用TCP作为通信协议,这是因为TCP是一种可靠的协议,而可靠能保证数据不丢失。
IP协议的全称Internet Protocol的缩写,它主要解决的是通信双方寻址的问题。IP协议使用IP地址来标识互联网上的每一台计算机,可以把IP地址想象成为你手机的电话号码,你要与他人通话必须先要知道他人的手机号码,计算机网络中信息交换必须先要知道对方的IP地址。
DNS
计算机网络中的每个端系统都有一个IP地址存在,而把IP地址转换为便于人类记忆的协议就是DNS协议。
DNS的全称是域名系统(Domain Name System,缩写:DNS),它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。
URI / URL
例如我们可以通过输出www.baidu.com地址来访问百度,那么这个地址我们是可以随便输入吗?还是说有什么规定。我们输入的地址格式必须要满足URI的规范。
URI的全称是(Uniform Resource Identifier),中文名称是统一资源标识符,使用它就能够唯一地标记互联网上资源。
URL的全称是(Uniform Resource Locator),中文名称是统一资源定位符,也就是我们俗称的网址,它实际上是URI的一个子集。
URI不仅包括URL,还包括URN(统一资源名称),它们之间的关系如下:
HTTPS
HTTP一般是明文传输,很容易被攻击者窃取重要信息,鉴于此,就有了HTTPS。HTTPS的全称为(Hyper Text Transfer Protocol over SecureSocket Layer),它和HTTP有很大的不同在于HTTPS是以安全为目标的HTTP通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。HTTPS在HTTP的基础上增加了SSL层,也就是说HTTPS = HTTP + SSL。
2020-08-08
跟谁学、网易校招笔试
- HTML5不支持哪个元素
- table表格中的rowspan colspan
- TCP和UDP
- 获取元素属性值
- 二叉树 最大高度 之类的
- BFC
- nth-of-type
- 修改哪些属性会导致回流
- 元素节点的获取
- 前端性能优化 合并文件 雪碧图 将样式表写在头部
- 查看本地所有分支的命令 (git branch
- 五层网络模型
- http状态码
- 浏览器缓存的两种方式
- 浏览器的重绘和重排 改变元素背景颜色会造成什么
- ‘’ a.b.c’’ .replace(/(.).(.).(.)/, ‘2.2.1.$0’) 的执行结果
- 优雅降级和渐进增强
- 计算css选择器权重
- ++ 和 - -
- es5实现深克隆
- arr:[2,7,11,5] target:9 return [0, 1] 力扣算法第一题
// 如果某个单词出现在单词总数中概率大于1%的话,则为合格,求合格单词数量
// 第一行表示单词总数 接下来的每一行为一个单词
// 输入
// 5
// I
// I
// am
// a
// boy
// 输出
// 4
// 问最多有多少种方法可以排出E M H的组合
// E EM M MH H
// 输入 2 2 1 2 2 (表示有2个E,2个EM,1个M ~~)
// 输出 3 (表示最多有三种情况)
// E + EM + H
// EM + M + MH
// E + MH + H
// 若A -> B,B -> C,则会有A -> C的关系 求存在多少种相互关系例如(A -> B B -> A) 那么A B 之间就有相互关系
// 第一行的5代表人的个数例如A B C D E, 6代表 存在6种单向关系
// 第二行开始为单向关系
// 输入
// 5 6
// 1 3
// 3 2
// 2 1
// 3 5
// 5 4
// 4 5
// 输出
// 4
// 一共有(1和3 1和2 2和3 4和5)
// 有一块2 * n的地砖 和足够多的1 * 2 和 2 * 3可以旋转的地毯 不能重叠空隙贴满 有多少种不同的的放案
// 4 T组数据 接下来的每一行为当前的n
// 1
// 2
// 3
// 5
// 1 从上面的第二行开始对应
// 2
// 4
// 13
2020-08-09
浅谈this指向
1.函数是否在new中调用,如果是的话this指向的是新创建的对象。
var obj = new foo(); this -> obj
2.函数是否通过call、apply绑定,或者通过bind硬绑定调用,如果是的话,this绑定的是制定的对象。
foo.call(obj1); this -> obj1
3.函数是否在某个上下文对象中调用,如果是的话,this指向的是那个上下文对象。
bar.foo() this -> bar
4.如果都不是的话,使用默认绑定。在严格模式下,就绑定到undefined,否则绑定到全局。
foo();
'use strict': this -> undefined
否则: this-> window
2020-08-10
聊聊创建对象的几种方式
1.Object构造函数
var obj = new Object();
obj.name = "Lgowen";
obj.age = 21;
console.log(obj);
// { name: "Lgowen", age: 21 }
2.对象字面量
var person = {
name: "Lgowen",
age: 21
};
console.log(person);
// { name: "Lgowen", age: 21 }
3.工厂模式
function createPerson(name, age){
var person = new Object();
person.name = name;
person.age = age;
return person;
}
console.log(createPerson("Lgowen",21));
// { name: "Lgowen", age: 21 }
4.自定义构造函数
function Person(name, age){
this.name = name;
this.age = age;
this.sayName = function (){
console.log(this.name);
}
}
var person = new Person("Lgowen",21);
console.log(person);
// { name: 'Lgowen', age: 21, sayName: [Function] }
5.原型模式
function Person(){
}
Person.prototype.name = "Lgowen";
Person.prototype.age = 21;
var person = new Person();
console.log(person); // {}
console.log(person.name); // "Lgowen"
console.log(person.age); // 21
6.组合使用构造函数和原型模式
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function () {
console.log(this.name);
}
var person1 = new Person("Lgowen",21);
var person2 = new Person("Clares",88);
console.log(person1.name , person2.name); // "Lgowen" "Chares"
console.log(person1.age , person2.age); // 21 88
console.log(person1.sayName(),person2.sayName()); // "Lgowen" "Chares"
7.动态原型模式
function Person(name, age){
this.name = name;
this.age = age;
// 当这个实例身上没有 sayName()方法时 , 给其构造函数的原型上添加 sayName()方法
if( typeof(this.sayName !== "function") ){
Person.prototype.sayName = function (){
console.log(this.name);
}
}
}
var person = new Person("Lgowen", 21);
console.log(person); // { name: "Lgowen", age: 21}
console.log(person.sayName()); // "Lgowen"
8.寄生构造函数模式
function Person(name,age){
var person = new Object();
person.name = name;
person.age = age;
return person; //通过重写构造函数的返回值
}
var person = new Person("Lgowen",21);
console.log(person); // { name: "Lgowen", age: 21}
9.稳妥构造函数模式
function Person(name,age){
var person = new Object();
person.sayName = function(){
console.log(name);
}
return person;
}
//返回的person对象除了通过sayName()方法去访问name外,没有别的访问可以访问或修改.
var person = Person("Lgowen");
person.sayName(); // "Lgowen"
2020-08-11
vuex
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
Vue生命周期中的created和mounted
created:
这个时候实例已经创建完成,数据观测 (data observer),property 和方法的运算,watch/event 事件回调。但是$el属性还没有挂载,即用不到具体的DOM。
mounted:
这个时候实例已经被挂载了,这时 el 被新创建的vm.el替换了。如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm.el 也在文档内,数据和DOM都已被渲染出来.
注意 mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick。
nextTick():
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
var vm = new Vue({
el: '#example',
data: {
message: '123'
}
})
vm.message = 'new message' // 更改数据
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
vm.$el.textContent === 'new message' // true
})
为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。
Vue中v-for中的key
我们在使用v-for,都推荐给使用的元素或者组件加上一个:key,但是为什么需要加这一个属性呢,简单的来说就是为了高效的更新虚拟DOM。(涉及到diff算法以及数据结构中的链表)
我们绑定的这个key是需要跟我们当前元素是一一对应的,要是将这个key值绑定为当前元素下标时即index,当我们v-for遍历的列表中元素发生改变时,相对应的index也会发生改变,则没有一一对应了。
没有绑定key时的数据,比如:
v-for遍历的是["A","B","C","D","E"]
// 在没有key值的情况下(从头开始对应)
比如说:
0 -> A
1 -> B
2 -> C
3 -> D
4 -> E
当我们想在B跟C之间加入一个F时,我们理想中的操作是直接在之前一一对应的情况下找到B跟C然后在其中间加入一个F,在绑定key值的情况下就会直接这么操作了。
0 -> A
1 -> B
5 -> F
2 -> C
3 -> D
4 -> E
但实际上
0 -> A
1 -> B
2 -> F
3 -> C
4 -> D
5 -> E
也就是说会先把放置C的位置替换成F,D的位置替换成C,然后再添加一个E,性能就没有这么好。如果将key值绑定为index索引的话,那么在数据源改变时,它们将不会像没有改变的时候那样一一对应。
2020-08-12
京东校招前端一面(秒挂)
- 自我介绍(简单的提了一下自己的项目及学习过程)
- 从项目开始聊起
- 提到小程序用户的登录验证,跳转页面,数据更新(这些没有没有回去巩固一遍项目啥都不记得了害)
- h5 c3 讲一下有什么新特性 有用过什么
- flex 布局
- cookie session Web Storage
- 自己项目中为什么选择用Web Storage而不用cookie
- 浏览器缓存机制(啥也不会,寻思着网络是硬伤)
- 有没有用过git 常用命令
2020-08-13
promise经典题
let p = new Promise( resolve => {
console.log(4); // 首先执行创建promise实例中的除回调外的代码
resolve(5); // 成功的回调
})
function fn1(){
console.log(1);
}
function fn2(){
setTimeout( () => {
console.log(2); //
},0)
fn1(); // 执行fn1函数 打印1
console.log(3); // 打印3
p.then(res => {
console.log(res); // 在这里打印成功回调的值5
}).then( () => {
console.log(6); // 打印6
})
}
fn2(); //执行fn2函数
// 4 1 3 5 6 2
2020-08-14
flex布局
如下有这样的布局,我们可以给外层盒子添加display:flex属性。
<div class="box">
<div class="a">1</div>
<div class="b">2</div>
<div class="c">3</div>
<div class="d">4</div>
</div>
.box{
width: 100%;
background-color: lightblue;
display: flex; /* 将父元素设置为弹性布局*/
flex-direction: row;
}
.box div{
width: 200px;
height: 200px;
font-size: 32px;
text-align: center;
line-height: 200px;
}
.a{
background-color: #f00;
}
.b{
background-color: #0f0;
}
.c{
background-color: #00f;
}
.d{
background-color: #ff0;
}
flex-direction
-
row:默认值。设置子元素按顺序从左到右水平排列,相当于元素左浮动,但不影响文档流。
-
row-reverse:设置子元素按顺序从右到左水平排列,相当于元素右浮动,但不影响文档流。
-
column:设置子元素按顺序从上到下垂直排列。
-
column-reverse:设置子元素按顺序从下到上垂直排列。
flex-wrap
<div class="box">
<div class="a">1</div>
<div class="b">2</div>
<div class="c">3</div>
<div class="d">4</div>
<div class="a">5</div>
<div class="b">6</div>
<div class="c">7</div>
<div class="d">8</div>
</div>
.box{
width: 75%;
background-color: lightblue;
display: flex; /* 将父元素设置为弹性布局*/
flex-wrap: nowrap;
}
.box div{
width: 200px;
height: 200px;
font-size: 32px;
text-align: center;
line-height: 200px;
}
.a{
background-color: #f00;
}
.b{
background-color: #0f0;
}
.c{
background-color: #00f;
}
.d{
background-color: #ff0;
}
-
nowrap:默认值。设置子元素不换行显示,当子元素总宽度大于父元素宽度时,则会以父元素宽度平分给每一个子元素,从而覆盖掉子元素本身的宽度。
-
wrap:设置子元素换行显示,当子元素总宽度大于父元素宽度时,则会将子元素换行显示。
-
wrap-reverse:设置子元素换行显示,且以将第一行从下方开始显示。
flex-flow : flex-direction和flex-wrap的复合属性简写形式,第一个值为flex-direction属性,第二个值为flex-wrap属性
例如 flex-flow:row-reverse wrap
设置子元素从右到左水平排列,且换行显示。
justify-content:
子元素如果是水平方向排列的话,它作用于水平方向。
子元素如果是垂直方向排列的话,它作用于垂直方向。
<div class="box">
<div class="a">1</div>
<div class="b">2</div>
</div>
.box{
width: 100%;
background-color: lightblue;
height: 600px;
display: flex; /* 将父元素设置为弹性布局*/
flex-direction: row;
justify-content: flex-start;
}
.box div{
width: 200px;
height: 200px;
font-size: 32px;
text-align: center;
line-height: 200px;
}
.a{
background-color: #f00;
}
.b{
background-color: #0f0;
}
-
flex-start:默认值。设置子元素位于父元素水平(垂直)方向上的左边(上边)。
-
flex-end:设置子元素位于父元素水平(垂直)方向上的的右边(下边)。
-
-
center:设置子元素要是水平方向则为水平居中,垂直方向则为垂直居中。
-
space-between:设置子元素之间的间距相同。且两边与父元素没有间距。
-
space-around:设置子元素之间的间距相同,且两边与父元素有相同的间距。
align-item
子元素如果是水平方向排列的话,它作用于垂直方向
子元素如果是垂直方向排列的话,它作用于水平方向
-
flex-start:设置子元素位于子元素位于父元素的垂直方向上方位置。
-
flex-end:
设置子元素位于父元素的垂直方向下方位置(水平排列)。
设置子元素位于父元素的水平方向右方位置(垂直排列)。 -
center:
设置子元素居中显示,如果水平排列则垂直居中显示。
设置子元素居中显示,如果垂直排列则水平居中显示。
三栏布局
<div class="box">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
</div>
.box{
margin: 0 auto;
width: 300px;
height: 50px;
display: flex;
}
.left , .right{
width: 60px;
background-color: blue;
}
.center{
background-color: red;
flex: 1; /* 给子元素设置flex属性为1表示剩余空间给其撑满 */
}
2020-08-15
多益网络、科大讯飞笔试
- promise
- function *
- 定时器
- 对象中的ValueOf()和toString()
- ==
- 实现渲染模板
- 解决span标签之间有空格的方法
- 说一下前端路由
- 找出字符串中出现次数最多且记录出现的位置
- 闭包、立即实行函数、作用域
- 字符串左移
- 一个数的2进制里有多少个1
- n * m矩阵里不同行的最大相乘数
- 反正考了很多很多基础啦 我都忘了 基础扎实很重要
2020-08-16
valueOf()和toString()
var arr = [];
var obj = {};
console.log(arr.toString()) // "" 返回值是空字符串
console.log(arr.valueOf()) // [] 返回值是数组本身
console.log(obj.toString()) // "[object Object]"
console.log(obj.valueOf()) // {} 返回值是对象本身
2020-08-17
前端跨域
一次http请求对应一个页面
浏览器的同源策略。默认情况下,js在发送ajax请求的时候,url的域名必须和当前页面完全一致。
域名要相同:www.example.com和example.com不同
协议要相同:http协议和https协议不同
端口号要相同::80和:8080不同
前端跨域 flash 发送http请求,可以绕过浏览器的安全限制,必须安装flash,并且和flash交互。
在同源域名下设置一个代理服务器,通过js发送请求给这个代理服务器,再从这个代理服务器上拿到相应结果。麻烦之处需要在服务器端额外做开发。
jsonp,只能用get请求,并且要求返回js。这个方式利用了浏览器允许跨域引用js资源
cors:如果浏览器支持h5,cross-origin resource sharing
Origin表示本域,当js向外域发起请求后,浏览器收到响应后,首先检查Access-Control-Allow-Origin是否包含本域,如果有,则跨域请求成功,如果没有,则请求失败。
跨域能否成功,取决于对方服务器是否愿意给我设置一个正确的Access-Control-Allow-Origin
简单请求: GET POST(Content-Type类型仅限application/x-www-form-urlencoded、multipart/foem-data和text/plain)HEAD ,并且不能出现任何自定义头。
在引用外域资源时,除了js和css外,都要验证cors。例如引入三方CDN字体文件。
2020-08-18
从浏览器输入url地址到渲染页面
解析域名网址的时候,在发送请求最开始的时候,dns解析会把www.baidu.com解析出一个ip地址,解析完成后,向这个ip地址对应的服务器发送http请求。请求的时候有一次tcp协议,tcp协议下有三次握手,四次挥手,链接的时候先通过三次握手,保证本次链接的安全性,这一次与服务器建立可靠的链接,建立完链接之后,服务器会根据你的请求,响应给你一些资源,拿到资源之后有四次挥手,断开这个链接。然后拿回这个资源到浏览器,然后浏览器可以根据这些资源渲染出页面。
为什么要四次挥手:资源请求完成,链接没有用,链接一直保持着不安全,有可能会受到别的请求的攻击,所以请求完资源最好断开。
2020-08-19
Promise
参考阮一峰ES6教程https://es6.ruanyifeng.com/#docs/promise
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
Promise对象的状态不受外界影响。代表一个异步操作,它有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
只有异步操作的结果才可以决定当前的状态。而且状态一旦改变,就不会再变。从pending变为fulfilled或pending变为fulfilled。
Promise对象可以将异步操作以同步操作的流程表达出来,但是它也有缺点。
- 无法取消,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,内部抛出的错误不会反应到外部。
- 当处于pending状态时,无法知道当前进展到哪一个阶段。
一般怎么用呢。ES6规定Promise是一个构造函数,用来生成Promise实例。
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done');
// 这里第一个参数以promise的成功回调函数作为回调函数
// 第二个参数以timeout形参的方式进行传值,表示这个时间过后执行(前提是等js主线程同步任务执行完)
// 第三个参数'done'是作为回调函数的参数,在这里也就是resolve函数的参数,相当于resolve('done'),将Promise对象的状态从'未完成'变为'完成'
});
}
timeout(100).then((value) => {
//then方法这里使用了第一个回调函数:即Promise对象的状态变为resolved时执行的函数
// 打印的结果即为上面传的'done'
console.log(value); // 'done'
});
2020-08-20
4399笔试
- 二叉树
- CDN
- XHR对象
- 重绘重排及优化
- 三栏布局
- HTTP缺点及改善方法
- 编程抽奖函数挺复杂的
- 函数声明和函数表达式
- jq选择器
- vue3.0与vue2.0的区别,及其各自特点
- html5废除的标签
- css选择器
- 具体想不起来了哈哈哈真的忘了太多了 没有及时记下来
- 闭包
- 作用域
- 原型
- 主要还是前端基础知识多
- 最后还有聊自己人生的论述题。惊呆了。
2020-08-21
滴滴笔试
- 进程
- IPV4 和 IPV6
- 内存管理
- 贝叶斯算法
- 欧几里得算法
- H5 写摇一摇的方法
- 栈
- 益智类题目
- H5废除标签
- jq选择器
- 两数求和编程( 一个正整数n(100<n<2000,第一行输出有多少对满足要求的数字,接下来每一行输出一对abc和acc,以空格分隔。如果没有一对abc和acc的话,则直接输出0即可。如果有多对,请按照abc升序的次序输出。)
// 我自己暴力求解的100%通过
var arr = [];
arr.push([123,456],[985,211],[365,654])
console.log(arr[0][0]);
console.log(arr[0][1]);
console.log(arr.sort(function(a,b){
return a[0] - b[0];
}));
console.log(arr);
const n = readInt();
var arr = [];
var count = 0;
for(var a = 1; a <= 9 ; a++){
for(var b = 0; b <= 9; b++){
for(var c = 0; c <= 9; c++){
if(a !== b && a !== c && b !== c){
var abc = (a * 100 + b * 10 + c);
var acc = (a * 100 + c * 10 + c);
if(abc + acc === n ){
arr.push([abc,acc]);
count++;
}
}
}
}
}
if(count === 0){
print(count);
}else{
arr.sort(function(a,b){
return a[0] - b[0];
})
print(count);
var newArr = [];
for(var i = 0;i < arr.length; i++){
newArr.push(arr[i][0] + ' ' + arr[i][1]);
}
for(var j = 0; j < newArr.length; j ++){
print(newArr[j]);
}
}
- 求排名(一年一度的X星人田径运动会隆重开幕。小小X报名参加了跳跃比赛,这可是小小X最擅长的项目!
跳跃比赛分为两轮,一轮是跳高,一轮是跳远。
最终成绩将综合两轮比赛的成绩来确定,并且两轮比赛成绩在最终成绩的计算中各占一半权重。
现在已经知道小小X在跳高和跳远两轮比赛中分别的排名情况,
现在请你编写一个程序帮小小X计算一下在最终成绩排名中小小X可以获得的最好名次和最差名次。)
// 没有写完 现在回想起来还是感觉会有bug
var heightArr = ['A','B','C','D','E','F','X','H','I','J']
var hIndex = heightArr.findIndex(function(i){
return i === 'X'
})
// console.log(hIndex);
var longArr = ['A','C','I','X','E','F','J','H','D','B'];
var lIndex = longArr.findIndex(function(i){
return i == 'X'
})
var arr = [];
for(let i = 0; i < hIndex; i++){
for(let j = 0; j < lIndex; j++){
if(heightArr[i] === longArr[j]){
arr.push(heightArr[i]);
}
}
}
var arr1 = []
for(let i = hIndex + 1 ; i < heightArr.length; i++){
for(let j = lIndex + 1; j < longArr.length; j++){
if(heightArr[i] === longArr[j]){
arr1.push(heightArr[i]);
}
}
}
console.log(arr);
// console.log(heightArr.findIndex( i => {
// return arr[arr.length - 1] === i
// }));
var p = heightArr.findIndex( i => {
return arr[arr.length - 1] === i
}) + 1
console.log(arr1);
2020-08-22
js中的同步任务和异步任务的执行机制
说到js我们可以容易想到js是单线程的,也就是说一般情况下按代码顺序来执行代码,所以是在执行同步任务。但是我们在页面渲染的时候,要是整段代码都是在同步执行的话,那么可能会出现页面加载到某个资源的时候卡的死死的,因为要等到这个资源被拿请求下来,才会继续下面的渲染,这样大大的影响了用户的体验。
因此我们有了异步编程。
常见的异步任务有定时器,发送ajax请求,promise。
首先上一段代码吧。
console.log(1);
setTimeout( funciton() {
console.log(2);
},0)
console.log(3);
按照我们正常的理解,js是单线程语言,所以执行顺序就应该是按照代码执行正常输出1 2 3 。但事实上却是1 3 2。并且我们设置定时器的时间为0ms,为什么还是会先执行后面的代码呢?
是因为在js的执行机制中,存在着同步任务与异步任务的不同执行场所,同步任务在主线程中按顺序执行,异步任务先将任务放入Event table事件列表,并将其回调函数注册进Event Queue事件队列中,等待主线程执行完毕调用。当主线程中的同步任务执行完毕后,由于js引擎中存在monitoring process进程,会持续的不断检查主线程执行栈是否为空,一旦为空就会去事件队列中去检查是否有等待被调用的函数(即异步任务中的回调函数)。然后会重复上述过程,即Event Loop事件循环。
除了同步任务和异步任务。对于任务还有更加细致的划分。
宏任务和微任务。
宏任务一般包括整体代码script、setTImeout、setInterval。
微任务一般包括Promise,process.nextTick(callback)。
在从整体代码script进入每一次的事件循环中,在执行完主线程所有的同步任务后,会首先从事件队列中寻找微任务队列,在所有微任务队列执行完毕后,再去顺序执行每一个宏任务,但是在宏任务中又可能存在着另外的事件循环,因此会重复上述的步骤,直到所有的宏任务执行完毕。
2020-08-23
腾讯笔试
- 字符串截取(42%)
- 次数最少得到合适水温(没思路)
- 操作dom(有思路没写出来)
- 实现栈(100%)
- 正则匹配合法的颜色值
2020-08-24
toString()和praseInt()
我们平常所理解的toString方法和parseInt方法常用于转换为字符串格式和转换为整型数字类型。
var num = 123;
console.log(num.toString()); // "123"
上述代码是将一个普通的Number类型的数字转换为String类型的数字
var num = 123.123;
var num2 = "123a";
parseInt(num); // 123
parseInt(num2); // 123
即会截断非数字前的部分并转换为Number类型输出。
但我们可能还忽略了它们还会有别的用法,而且有时候还挺实用。
parseInt(101,2) // 将101看作2进制的数字转换成10进制的数字
var num = 123;
num.toString(2); // 将num看作10进制的数字转换成2进制的字符串类型数字
2020-08-25
完美世界笔试
- 异步
- HTML元元素
- 块级元素
- 跨域
- CSS层级
- CSS继承属性
- Ajax
// 0:请求未初始化(还没有调用open())
// 1:请求已经建立,但是还没有发送(还没有调用send())
// 2:请求已经发送(已经调用了send())
// 3:请求正在处理中,正在接收服务器响应的数据
// 4:响应已经完成,可以获取并使用服务器的响应了
- CSS样式优先级
- 对象
- 定时器
- 预编译
- HTML元素全局属性
- 合法变量名
- 优先级选择器
- 闭包
- HTTP
- CSS简写属性
- 本地存储
- 媒体查询
- BFC
- 伪类
- React生命周期
- HTTP协议请求方法
- 浏览器userAgent
- 隐藏元素
- 找出数组中出现次数最多的元素
- 页面中动态显示当前年所剩余时间(xxxx年还剩xx天xx时xx秒)
2020-08-26
本地存储
对于一个数据请求来说,可以分为发起网络请求、后端处理、浏览器响应三个步骤。浏览器缓存可以帮助我们在第一和第三步骤中优化性能。比如说直接使用缓存而不发起请求,或者发起了请求但后端存储的数据和前端一致,那么就没有必要再将数据回传回来,这样就减少了响应数据。
减少网络流量:一旦数据保存在本地后,就可以避免再向服务器请求数据,因此减少不必要的数据请求,减少数据在浏览器和服务器间不必要地来回传递。快速显示数据
性能好,从本地读数据比通过网络从服务器获得数据快得多,本地数据可以即时获得。再加上网页本身也可以有缓存,因此整个页面和数据都在本地的话,可以立即显示。
临时存储:很多时候数据只需要在用户浏览一组页面期间使用,关闭窗口后数据就可以丢弃了,这种情况使用sessionStorage非常方便
essionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大
作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的
2020-08-27
浏览器缓存
浏览器在第一次发送HTTP请求的时候会现在浏览器缓存中寻找是否有缓存结果和缓存标识,如果有,则从缓存中获取资源。如果没有,则发送HTTP请求给服务器,服务器响应结果和缓存规则,浏览器收到响应结果后将请求结果和缓存标识存入浏览器缓存中。
service worker
注册Service Worker
坚听install事件
缓存需要的文件
在下次访问时通过拦截请求查询是否存在缓存,存在则读取缓存文件,否则请求数据
Memory Cache 内存缓存
主要包含页面中已经抓取到的资源
读取高效,持续性短。页面关闭则消失。
preloader相关指令 linkrel = “prefetch”
一边解析css/js文件 一边网络请求下一个资源
Dusk Cache 硬盘缓存
读取速度慢,胜在容量和存储时效性
会根据HTTP Header中的字段判断哪些资源需要缓存 哪些资源不请求直接使用 哪些资源已经过期需要重新请求 。
并且在跨域的情况下,相同地址的资源一旦背硬盘缓存下来,就不会再次去请求数据,绝大部分缓存来自硬盘缓存
Push Cache 推送缓存
2020-08-28
异步相关
ES6将异步场景分为两个阶段和三种状态
两个阶段:unsettled(未决) 和 settled(已决)
三种状态:pending(挂起)、resolved(完成)、rejected(失败)
他们的关系图如下:
当任务处于未决阶段时,它一定是 pending 挂起状态,表示任务从开始到拿到结果之间的过程。比如:网络完成了各种配置,也发送了请求,但是请求结果还没有拿到。
当任务处于 已决阶段时,它只能是 resolved 和 rejected两种状态的一种,表示任务有了一个结果。比如:从服务器拿到了数据(resolved)、网络不好没有拿到数据(rejected)
任务开始时,始终是未决阶段,那任务如何才能走向已决阶段呢?
ES6认为,任务在未决阶段的时候,有能力将其推向已决。比如,当从服务器拿到数据后,我们就从未决阶段推向已决的resolved状态,如果网络不好,导致出错了,我们就从未决阶段推向已决的rejected状态
我们把从未决推向已决的resolved状态的过程,叫做resolve,从未决推向已决的rejected状态的过程,叫做reject,如下图所示
这种状态和阶段的变化是不可逆的,也就是说,一旦推向了已决,就无法重新改变状态
任务从未决到已决时,可能附带一些数据,比如:跑步完成后的用时、网络请求后从服务器拿到的数据
任务已决后(有了结果),可能需要进一步做后续处理,如果任务成功了(resolved),有后续处理,如果任务失败了(rejected),仍然可能有后续处理
我们把针对resolved的后续处理,称之为thenable,针对rejected的后续处理,称之为catchable
Promise的基本使用
ES官方制定了一个全新的API来适配上面提到的异步模型,这个API即Promise
Promise是一个构造函数,通过new Promise()
可以创建一个任务对象,构造函数的参数是一个函数,用于处理未决阶段的事务,该函数的执行是立即同步执行的。在函数中,可以通过两个参数自主的在合适的时候将任务推向已决阶段
var pro = new Promise((resolve, reject)=>{
//未决阶段的代码,这些代码将立即执行
//...
//在合适的时候,将任务推向已决
//resolve(数据):将任务推向resovled状态,并附加一些数据
//reject(数据):将任务推向rejected状态,并附加一些数据
})
注意
- 任务一旦进入已决后,所有企图改变任务状态的代码都将失效
- 以下代码可以让任务到达rejected状态
- 调用reject
- 代码执行报错
- 抛出错误
拿到Promise对象后,可以通过then方法指定后续处理
pro.then(thenable, catchable)
//或
pro.then(thenable)
pro.catch(catchable)
无论是thenable还是catchable,均是下面格式的函数
function (data){
//data为状态数据
}
注意:后续处理函数一定是异步函数,并且放到微队列中
2020-08-29
网络相关
如何访问服务器
服务器程序可能在本机,也可能在远程,它一定运行在某一台计算机上
要在茫茫互联网中访问到服务器程序,就必须:
- 精确的定位到服务器所在的计算机
- 精确定位到计算机中的服务器程序
- 精确定位到程序中的某个功能
通常,我们使用url地址来描述以上3个信息
url地址全称为Uniform Resource Locator,统一资源定位符,是一个字符串,它的格式如下:
protocol://hostname:port/path?query#hash
- protocal: 使用的协议,选择不同的协议,会导致和服务器之间消息交互格式、连接方式不同,大部分都服务器支持 http 和 https 两种协议。如果选择了服务器不支持的协议,会导致访问失败。
- hostname:主机名,可以是 ip、域名
- ip:每台计算机在网络中的唯一编号,127.0.0.1表示本机
- 域名:网络中容易记忆的唯一单词,通过DNS服务器可以将域名解析成IP,localhost会被解析为127.0.0.1
- port:端口号,0~65535之间的数字,相当于服务器计算机上的房号,使用不同的端口号相当于敲不同房间的门。计算机上的程序可以监听一个或多个端口号,如果访问的端口号有程序被监听,则计算机会将到达的网络访问交给对应的程序来处理
- 端口号可以不写,使用默认值
- http协议默认值80
- https协议默认值443
- path: 一个普通的字符串,该字符串会交给web服务器处理,主要用于定位服务
- 如果path为
/
,则表示根路径,如http://www.baidu.com/
的path就是/
- 如果path为
- query: 一种特殊格式的字符串,该字符串会交给web服务器处理,主要用于向服务器某个服务传递一些信息
- 格式为:
属性名=属性值&属性名=属性值
- 格式为:
- hash:一个普通的字符串,在浏览器的地址栏中,如果url其他位置的信息保持不变,仅变动hash,浏览器不会重新访问服务器,因此通常用于不刷新的页面内跳转
可以看出:
- hostname是用于精准定位计算机的
- port是用于精准定位服务器的
- protocal是用于告诉服务器使用哪种协议进行传输数据
- path是用于精准定位服务器上的服务的
- query是在使用服务的时候传递的额外信息,具体看服务器要求
- hash是一些额外信息,服务器要不要用具体看服务器要求
示例:分析出下面url地址的各部分内容
https://baike.baidu.com/item/HTML?a=1#1
注意:url仅支持ASCII字符,如果是包含非ASCII字符,会被现代浏览器自动进行编码
例如:
https://www.baidu.com/s?wd=王思聪
会被编码为
https://www.baidu.com/s?wd=%E7%8E%8B%E6%80%9D%E8%81%AA
url地址不能过长,因为很多浏览器对url地址长度是有限制的,chrome对url的长度限制为8182个ASCII字符
http协议
我们可以通过url地址访问服务器,但是,浏览器和服务器之间的数据到底是怎么交互的,数据的格式是什么,这取决于使用什么协议
最常见的协议,就是http协议
http协议将和服务器的一次交互看作是两段简单的过程组成:请求 request和响应 response
- 请求:客户端通过url地址发送数据到服务器的过程
- 响应:服务器收到请求数据后回馈数据给客户端的过程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LIupsywO-1598891725010)(assets/2019-12-26-18-21-28.png)]
当 请求-响应 完成后,本次交互结束,如果需要得到额外的服务,则需要重新发送新的请求
同时,http协议约定了请求的消息格式和响应的消息格式
请求消息格式
请求消息格式有两部分组成:请求头 request headers 和 请求体 request body
请求头
请求头是一个多行文本的字符串
比如我们请求 http://www.baidu.com/s?wd=html, 得到的请求头可能如下:
GET /s?wd=html HTTP/1.1
Host: www.baidu.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
...
可以看出,该字符串有两个部分组成
- 请求行:请求方法 path 协议
- 请求方法:一个普通的字符串,会被服务器读取到。常见的请求方法:GET、POST
- path:即url中的 path + search + hash,服务器可能会用到path中的信息
- 协议:协议以及版本号,目前固定为 HTTP/1.1
- 键值对:大量的属性名和属性值组合,可以自定义。
- Host:url地址中的hostname
- User-Agent:客户端信息描述
- 其他键值对
请求头描述了请求的元数据信息,这里的元数据信息是指与业务无关的额外信息
当我们在浏览器地址栏输入一个url按下回车后,浏览器会自动构建一个请求头,请求方法为GET,然后向服务器发送请求
请求体
包含业务数据的字符串
理论上,请求体可以是任意格式的字符串,但习惯上,服务器普遍能识别以下格式:
- application/x-www-form-urlencoded:
属性名=属性值&属性名=属性值...
- application/json:
{"属性名":"属性值", "属性名":"属性值"}
- multipart/form-data:使用某个随机字符串作为属性之间的分隔符,通常用于文件上传
由于请求体格式的多样性,服务器在分析请求体时可能无法知晓具体的格式,从而不知道如何解析请求体,因此,服务器往往要求在请求头中附带一个属性Content-Type
来描述请求体使用的格式
例如
Content-Type: application/x-www-form-urlencoded
Content-Type: application/json
Content-Type: multipart/form-data
GET 和 POST
虽然http协议并没有规定请求方法必须是什么,但随意的请求方法服务器可能无法识别
服务器一般都能识别GET和POST请求,并做出以下的差异化处理
- 如果是GET请求,不读取请求体,业务数据从path的search或hash中读取
- 如果是POST请求,读取请求体,业务数据从请求体中获取,关于请求体的格式,不同的服务器、同一个服务器的不同服务要求不同
在浏览器地址栏中输入url地址是不能产生POST请求的,可以使用表单提交产生POST请求
由于服务器对GET和POST处理的差异,造成了GET和POST请求的差异:
- GET请求一般没有请求体,POST请求有
- GET请求的业务数据放在地址中,安全性较差(误分享、被偷窥)
- GET请求传递的业务数据量是有限的,POST是无限的(除非服务器限制)
- GET请求利于分享页面结果,POST不行
- 在浏览器中刷新或回退页面时,会按照该页面之前的请求方式重新发送请求,如果是GET请求,浏览器会重新发送GET请求;如果是POST请求,浏览器会重新构建之前的消息体数据,通常会弹出提示
响应消息格式
和请求类似,响应消息也分为响应头(response headers)和响应体(response body)
响应头
比如我们请求 http://www.baidu.com/s?wd=html, 得到的响应头可能如下:
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Server: BWS/1.1
...
可以看出,该字符串有两个部分组成
- 响应行:协议 状态码 状态文本
- 协议:协议以及版本号,目前固定为 HTTP/1.1
- 状态码和状态文本:一个数字和数字对应的单词,来描述服务器的响应状态,浏览器会根据该状态码做不同的处理。
- 200 OK:一切正常。你好,
我好,大家好。
- 301 Moved Permanently:资源已被永久重定向。
你的请求我收到了,但是呢,你要的东西不在这个地址了,我已经永远的把它移动到了一个新的地址,麻烦你取请求新的地址,地址我放到了请求头的Location中了
- 302 Found:资源已被临时重定向。
你的请求我收到了,但是呢,你要的东西不在这个地址了,我临时的把它移动到了一个新的地址,麻烦你取请求新的地址,地址我放到了请求头的Location中了
- 304 Not Modified:文档内容未被修改。
你的请求我收到了,你要的东西跟之前是一样的,没有任何的变化,所以我就不给你结果了,你自己就用以前的吧。啥?你没有缓存以前的内容,关我啥事
- 400 Bad Request:语义有误,当前请求无法被服务器理解。
你给我发的是个啥啊,我听都听不懂
- 403 Forbidden:服务器拒绝执行。
你的请求我已收到,但是我就是不给你东西
- 404 Not Found:资源不存在。
你的请求我收到了,但我没有你要的东西
- 500 Internal Server Error:服务器内部错误。
你的请求我已收到,但这道题我不会,解不出来,先睡了
- 通常认为,0~399之间的状态码都是正常的,其他是不正常的
- 200 OK:一切正常。你好,
- 键值对:大量的属性名和属性值组合,可以在服务器响应的时候自定义。
- Content-Type:响应体中的数据格式,常见格式如下
- text/plain: 普通的纯文本,浏览器通常会将响应体原封不动的显示到页面上
- text/html:html文档,浏览器通常会将响应体作为页面进行渲染
- text/javascript:js代码,浏览器通常会使用JS执行引擎将它解析执行
- text/css:css代码,浏览器会将它视为样式
- image/jpeg:浏览器会将它视为jpg图片
- attachment:附件,浏览器看到这个类型,通常会触发下载功能
- 其他MIME类型
- Server:web服务器类型
- Content-Type:响应体中的数据格式,常见格式如下
响应体
响应消息的正文
在浏览器地址栏中输入一个页面地址,按下回车键后发生了什么?
- 浏览器将url地址补充完整:没有书写协议,添加上协议
- 浏览器对url地址进行url编码:如果url地址中出现非ASCII字符,则浏览器会对其进行编码
- 浏览器构造一个没有消息体的GET请求,发送至服务器,等待服务器的响应,此时浏览器标签页往往会出现一个等待的图标
- 服务器接收到请求,将一个HTML页面代码组装到消息体中,响应给浏览器
- 浏览器拿到服务器的响应后,丢弃掉当前页面,开始渲染消息体的html代码。浏览器之所以直到这是一个html代码,是因为服务器的响应头指定了消息类型为text/html
- 浏览器在渲染页面的过程中,发现有其他的嵌入资源,如CSS、JS、图片等
- 浏览器使用不阻塞渲染的方式,重新向服务器发送对该资源的请求,拿到响应结果后根据Content-Type做相应处理
- 当所有的资源都已下载并处理后,浏览器触发window.onload事件
ajax
不仅仅是浏览器可以发出请求并获得响应,任何具有网络通信能力的程序均可以这样做。
过去,在浏览器中,只有浏览器本身有发送请求的能力,直到ajax的出现。
ajax是一种技术,让JS语言在浏览器环境中获得了新的API,通过该API,JS代码拥有了和服务器通信的能力
传统的ajax代码如下
var xhr = new XMLHttpRequest(); //创建发送请求的对象
xhr.onreadystatechange = function(){ //当请求状态发生改变时运行的函数
// xhr.readyState: 一个数字,用于判断请求到了哪个阶段
// 0: 刚刚创建好了请求对象,但还未配置请求(未调用open方法)
// 1: open方法已被调用
// 2: send方法已被调用
// 3: 正在接收服务器的响应消息体
// 4: 服务器响应的所有内容均已接收完毕
// xhr.responseText: 获取服务器响应的消息体文本
// xhr.getResponseHeader("Content-Type") 获取响应头Content-Type
}
xhr.setRequestHeader("Content-Type", "application/json"); //设置请求头
xhr.open("请求方法", "url地址"); //配置请求
xhr.send("请求体内容"); //构建请求体,发送到服务器
2020-08-30
前端基础问题
盒模型
标准盒子:width/height + padding + border + margin
怪异盒模型: width/height(包括内边距和边框) + margin
水平垂直居中
- 父元素相对定位,子元素绝对定位,已知宽高情况下top:50%,left:50%,margin-top:-(自身高度的一半),margin-left:-(自身宽度的一半)
- 父元素相对定位,子元素绝对定位,不知道宽高情况下top:50%,left:50%,transform:translate(-50%,-50%)
- 父元素设置属性display:flex,子元素设置justify-content:center,align-items:center
2020-08-31
58同城笔试
- 隐世类型转换 “123abc” - 123
- 行内元素
- 跨域
- 函数声明和函数表达式
- HTML5标签
- CSS选择器
- HTTP状态码
- cookie
- 预编译
- 可见元素 display overflow z-index visibility
- 原型
- 对象
- 定时器(块级作用域)
- js特点
- js任务执行机制
- 对象的遍历
- arr.fill
- 垂直居中
- 数组去重