Ajax
1、Ajax的原理是什么
- 实现原理:
- 其核心是 XMLHttpRequest对象
- IE浏览器使用ActiveXObject
- 常用属性:
xhr.onreadystatechange=function(){
}
- readyState属性
- 存储服务器响应的状态信息,每当readyState改变时,onreadystatechange函数就会被执行,readyState属性可能有的值

- 向这个onreadystatechange函数中添加一个判断语句,测试响应是否成功
xhr.onreadystatechange=function(){
if(xhr.readyState===4){
}
}
- responseText
- 可以通过responseText属性来获取服务器返回的数据
xhr.onreadystatechange=function(){
if(xhr.readyState===4){
document.myForm.time.value= xhr.reponseText
}
}
- 其它属性

- 常用方法:
- open()方法
- open()有三个参数,
第一个参数定义发送请求使用的方法
第二个参数规定服务器端脚本的URL,
,第三个参数规定应对当前请求进行异步处理
xhr.opne('GET',test.php,true)
- send()方法
- send()方法将请求发送服务器,假设HTML文件,和PHP文件位于相同目录,那么代码是以下形式
xhr.send(null)
- 其它方法

- 发送一个ajax-get请求
- 创建XMLHttpRequest对象
- 设置请求方式
- 调用回调函数
- 发送请求
let xhr =new XMLHttpRequest()
var url = `http://location:8080/ajaxGet/login`
xhr.opne('GET',url,true)
xhr.send()
xhr.onreadystatechange=function(){
if(xhr.readyState===4 && xhr.status===200){
var obj = document.getElementById('id')
obj.innerHTML= xml.responseText
} else{
alert('ajax服务器返回错误')
}
}
let xhr =new XMLHttpRequest()
var url = `http://location:8080/ajaxGet/login`
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.open('PSOT',url,true)
xhr.send()
xhr.onreadystatechange=function(){
if(xhr.readyState===4 && xhr.status === 200){
var obj = document.getElementById('id')
obj.innerHTML= xml.responseText
} else{
alert('ajax服务器返回错误')
}
}
2、Get和post请求方式的区别有哪些
- 用处
- 安全性
- get比post
相对安全
- get直接把参数暴露在Url地址栏后,post是把请求参数放到请求体中,get参数直接暴露,浏览器会缓存,如果把密码和用户名缓存,那么就会造成泄漏,导致不安全
- 请求参数
- querystring是url的一部分,get,post都可以带上,get的querystring(仅支持urlencode编码),post参数,是放在Body(支持多种编码)
- 请求参数长度限制
- get请求长度最多1024kb,post请求对数据没有限制
- 在http规范中,并没有对get请求方式进行大小限制,但是浏览器不同,对url长度有限制,对于Post理论上不受限制的
- TCP数据包
- get请求会产生一个TCP数据包,post请求会产生两个TCP数据包
3、请解释一下 JavaScript 的同源策略
- 含义
- 同源策略指的是,一下三者必须要统一,一者不同,就产生跨域
- 域名
- 协议
- 端口

- 目的
- 同源策略,为了保证用户信息安全,防止恶意网站窃取数据,假设用户在A网站登录,然后去其它网站浏览,但是B网站,可以获取A网站的cookie,那么此时就会造成用户信息泄露
- 限制
- cookie,LocalStorage和indexDB无法获取
- DOM无法获得
- Ajax请求不能发送
- 规避限制
- cookie
- cookie是服务器写入浏览器的一段信息,只有同源的网页才能共享,但是两个网页一级域名相同,只是二级域名不同,浏览器允许设置
document.domain
共享cookie信息
- 两个网页不同源: 无法获取对方的DOM,使用
Iframe
和window.opne
方法打开窗口
- LocalStorage
- 通过postMessage()方法,允许跨窗口通信,无论是否两个是不是同源,该方法两个参数,参数1具体信息内容,参数2接收窗口的源(协议+域名+端口)也可以设置为* 表示不受限制,向所有窗口发送
- ajax
4、解决跨域的方式有哪些
- jsonp
- 基本定义
- 通过添加一个script元素,向服务器请求json数据,这种做法不受同源策略限制,利用的是script中的src属性,服务器收到请求以后,将数据放到一个指定名字的回调函数中,传递回来
- 具体实现
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function () {
addScriptTag('http://example.com/ip?callback=foo');
}
function foo(data) {
console.log('Your public IP address is: ' + data.ip);
foo({
"ip": "8.8.8.8"
});
- 缺点
- 只能发送Get的请求方式,无法处理Post请求方式
- 只支持跨域HTTP请求的清空,不能解决不同域的两个页面之间进行js调用的问题
- jsonp在调用失败的时候,不会返回http状态码
- 存在一定的安全漏洞
- Cors
- 基本定义
- Cors是一个wc3认定的一个标准,跨域资源共享(Cross-origin resource sharing)解决了ajax只能同源使用的限制
- 目前浏览器和服务器都支持该种方式,浏览器版本不能低于IE10
- 实现方式(Cors分为简单请求和复杂请求)
- 简单请求方式,只要满足一下两大条件就可以

- 简单请求,只需要添加一个
origin
字段即可,浏览器发现是一个简单请求,就自动会在请求头中添加一个origin
字段
GET /cors HTTP/1.1
Origin: http:
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
- 如果`origin`指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应,浏览器发现这个回应头信息没有包含`Access-Control-Allow-Origin`字段,会抛出一个错误,被`XMLHttpRequest`的`onerror`回调函数捕获,这种错误,是无法通过状态码识别的,如果`Origin`指定的域名在许可范围内,服务器会返回响应,多出几个头信息字段
Access-Control-Allow-Origin: http:
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
- Access-Contronl-Allow-Origin
- 该字段是必须的,它的值要么是请求时`origin`字段,要么是一个`*`,表示接受任意域名的请求,如果发送cookie,`Access-Contronl-Allow-Origin`不能设置为星号,必须指定明确的,与请求网页一致的域名,同时cookie依然遵循同源政策,只有服务器域名设置的cookie才会上传,其它域名的cookie并不会上传,且(跨域)原网页代码中的`document.cookie`也无法读取服务器域名下的cookie信息
- Access-Control-Allow-Credentials
- 该字段是一个可选字段,表示是否允许发送Cookie,默认情况下,Cookir不包含在Cors的请求之中,true代表服务器明确许可,Cookie可以包含在请求中,是一个单选项,如果不设置true,那么删除该字段即可
- Access-Control-Ecpose-Headers
- 该字段可选。CORS请求时,`XMLHttpRequest`对象的`getResponseHeader()`方法只能拿到6个基本字段:`Cache-Control`、`Content-Language`、`Content-Type`、`Expires`、`Last-Modified`、`Pragma`。如果想拿到其他字段,就必须在`Access-Control-Expose-Headers`里面指定。上面的例子指定,`getResponseHeader('FooBar')`可以返回`FooBar`字段的值
- withCredentials属性
- Cors默认是不会发送Cookie信息,和http认证信息,如果要报Cookie发送到服务器,一方面要服务器统一,指定`Access-Control-Allow-Credentials`字段
Access-Control-Allow-Credentials: true
- 另一方面,开发者必须在Ajax请求中打开`withCredentials`属性,否则即使服务器统一发送cookie,浏览器也不会进行发送,如何省略`withCredentials`字段,有的浏览器还是会发送cookie信息,这个时候,可以显示的关闭`xhr.withCredentials = false
var xhr = new XMLHttpRequest()
xhr.withCredentials= true
- **非简单请求**
- 非简单请求是那种对服务器有特殊要求的请求,比如请求方法是`PUT`或`DELETE`,或者`Content-Type`字段的类型是`application/json`,非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight),浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段,只有得到肯定答复,浏览器才会发出正式的`XMLHttpRequest`请求,否则就报错
var url = 'http://api.alice.com/cors';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();
- 上面代码中,HTTP的请求方式,是一个PUT,并且发送一个自定义头信息X-Custom-Header,就自动发出一个"预检"请求,要求服务器确认可以这样请求。下面是这个"预检"请求的HTTP头信息
OPTIONS /cors HTTP/1.1
Origin: http:
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
- "预检"请求用的请求方法是`OPTIONS`,表示这个请求是用来询问的。头信息里面,关键字段是`Origin`,表示请求来自哪个源,除了`Origin`字段,"预检"请求头中的信息包含两个特殊的字段
- Access-Control-Request-Method
- 该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是`PUT`。
- Access-Control-Request-Headers
- 该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是`X-Custom-Header`
- 服务器通过了预检请求,每个浏览器都正常的CORS请求,就跟每个简单的请求一样,会产生一个`Origin`字段,服务器也会回应一个`Access-Control-Allow-Origin`头信息字段
PUT /cors HTTP/1.1
Origin: http:
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
- 服务器的正常反应('Access-Control-Allow-Origin'该字段每次回应都是必须包含的)
Access-Control-Allow-Origin: http:
Content-Type: text/html; charset=utf-8
5、什么是同步什么是异步
- 单线程
- JavaScript是一门单线程语言,因此,
JavaScript在同一个时间只能做一件事,单线程意味着,如果在同个时间有多个任务的话,这些任务就需要进行排队,前一个任务执行完,才会执行下一个任务
,因为javaScript是一个单线程执行过程,同时间内处理多个任务,所有任务都会排队,前一个任务执行完毕,下一个任务才会执行,如果上一个任务执行时间很长(比如ajax请求),那么就会造成下一个任务等待,严重影响用户体验,所以才会有同步任务
和异步任务
function fun1() {
console.log(1);
}
function fun2() {
console.log(2);
}
fun1();
fun2();
1
2

- 同步任务
- 同步任务是指,
主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务
,当我们打开网站时,网站的渲染过程,比如元素的渲染,就是一个同步任务
var num = 20;
console.log(num)
var arr = [12,3224,34]
for(var i =0; i<arr.length;i++){
console.log(arr[i])
}
- 异步任务
- 异步任务是指,
不进入主线程,而是进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程
,当我们打开网站时,例如图片的加载,音乐的加载,就是一个异步任务
function fun1() {
console.log(1);
}
function fun2() {
console.log(2);
}
function fun3() {
console.log(3);
}
fun1();
setTimeout(function(){
fun2();
},0);
fun3();
1
3
2
- 异步机制实现原理(EventLoop是一码事)
- javaScript中的异步如何实现的,需要知道
回调和事件循环
,异步任务是不会进入主线程中,会先进入到异步任务队列
,任务队列其实就是一个遵循先进后出,后进先出
的数据结构,也是一个事件队列,例如文件读取操作,是一个异步任务,该任务会先被添加到异步任务队列中
,等到IO完成,就会在任务队列中,添加一个事件
,表示异步任务已经完毕,可以进入执行栈了,但是此时,主线程未必有空处理,当主线程处理完其它任务后,才会读取异步任务队列
中的代码,单线程从任务队列中获取任务,这个过程是不断循环的,每次执行栈清空以后,都会在任务队列
中读取,如果没有任务,等到有新任务,如果存在任务,那么就会拿出来进行执行,这个循环的过程,就叫事件循环
- 总结来说
- 所有同步任务都在主线程上执行,行成一个执行栈
- 主线程之外,还存在一个任务队列,只要异步任务有了结果,就会在任务队列中放置一个事件
- 一旦执行栈中所有异步任务执行完毕,系统就会读取任务队列,查看是否还存在异步任务,结束等待状态,进入执行栈,开始执行
- 主线程不断重复以上三步
6、什么是HTTP协议 HTTP和HTTPS的区别(拓展需要掌握)
- 什么是HTTP协议
- 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础
- HHTTP是一个客户端终端(用户)和服务器端(网站)请求和应答的标准(TCP)。通过使用网页浏览器、网络爬虫或者其它的工具,客户端发起一个HTTP请求到服务器上指定端口(默认端口为80)我们称这个客户端为用户代理程序(user agent)。应答的服务器上存储着一些资源,比如HTML文件和图像。我们称这个应答服务器为源服务器(origin server)。在用户代理和源服务器中间可能存在多个“中间层”,比如代理服务器、网关或者隧道(tunnel)
- HTTP客户端发起一个请求,创建一个到服务器指定端口(默认是80端口)的TCP连接。HTTP服务器则在那个端口监听客户端的请求。一旦收到请求,服务器会向客户端返回一个状态,比如"HTTP/1.1 200 OK",以及返回的内容,如请求的文件、错误消息、或者其它信息
- HTTP和HTTPS的区别
- HTTP协议传输的数据都是未加密的,明文显示,因为使用HTTP传输的隐私信息,非常的不安全,为了保证信息能够加密进行传输,所以在HTTP基础上设计了SSL(Secure Sokets Layer)协议用于HTTP协议传输的数据进行加密处理,从而就诞生了HTTPS
- HTTPS协议是有SSL+HTTP协议构建的可进行加密传输,身份认证的网络协议,比HTTP协议要安全
- 区别如下
- HTTPS协议需要到CA申请证书,一般免费证书较少,需要一定费用
- HTTP是超文本传输协议,信息是明文显示,但是HTTPS具有安全性的SSL协议加密传输
- HTTP和HTTPS使用完全不同的连接方式,默认端口也不一样,前者是80后者是443
- HTTP的连接也很简单,是无状态的,HHTPS协议是有SSL+HTTP协议构建可进行加密传输,以身份认证的网络协议,比HTTP协议,更加安全
7、常见的HTTP状态码有哪些,分别代表什么含义
- 状态码种类
- 1xx:指示信息--表示请求已接收,继续处理
- 2xx:成功--表示请求已被成功接收、理解、接受
- 3xx:重定向--要完成请求必须进行更进一步的操作
- 4xx:客户端错误--请求有语法错误或请求无法实现
- 5xx:服务器端错误--服务器未能实现合法的请求
- 常见状态码及含义
200 OK //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
- 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)
- 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态
- 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手
ES6
1、Array拓展
- 扩展运算符
- Arrar.from()
- Arrar.of()
- 实例copyWithin()
- 实例find()和findIndex()
- 实例fill()
- 实例entrens()keys()values()
- 实例inculecs()
- 实例flat(),flatMap()
2、String拓展&方法
- for of遍历
- 可以使用下方的语法,进行遍历,同时,for of 可以遍历
oxFFF
的码点
for (let codeString of 'foo'){
console.log(codeString)
}
- 模板字符串(template string)
- 是一种增强版本的字符串,使用反引号(` )进行标识,可以当做普通的字符串使用,也可以定义多个字符串,同时也可以在字符串中嵌入变量
$('#result').append(`
There are <b>${basket.count}</b> items
in your basket, <em>${basket.onSale}</em>
are on sale!
`);
let s = 'Hello world!';
s.includes('o')
s.includes('o',6)
let s = 'Hello Word!';
s.startsWith('Hello')
s.endsWith('Hello', 5)
let s = 'Hello world!';
s.startsWith('world', 6)
s.endsWith('Hello', 5)
'x'.repeat(3)
'hello'.repeat(2)
'na'.repeat(2.9)
'na'.repeat(Infinity)
'na'.repeat(-1)
'na'.repeat(-0.9)
'na'.repeat(NaN)
'na'.repeat('na')
'na'.repeat('3')
3、Obejct拓展&方法
let obj = 'is object';
let objName = {obj}
objName
const objName = {obj:obj}
function fn (x,y){
return {x+y}
}
function fn (x,y){
return {x:x,y:y}
}
fn(1,2)
const Person={
sayHi(){
console.log('我是Person对象中的sayHi方法')
}
}
const Person={
sayHi:function(){
console.log('我是Person对象中的sayHi方法')
}
}
let url = 'htpps://www.baidu.com'
const ToUrl ={
url,
erros: (){ console.log('url is errors')}
}
let url = 'htpps://www.baidu.com'
const ToUrl ={
url,
erros: (){ console.log('url is errors')}
}
- 应用场景1(`commonJS中就可以采用这种方式`)
let ms = {};
function getItem (key) {
return key in ms ? ms[key] : null;
}
function setItem (key, value) {
ms[key] = value;
}
function clear () {
ms = {};
}
module.exports = { getItem, setItem, clear };
module.exports = {
getItem: getItem,
setItem: setItem,
clear: clear
};
- 应用场景2(
属性赋值器(getter)和属性取值期(setter)也可以采用此种方式
)
const cart = {
_wheels: 4,
get wheels () {
return this._wheels;
},
set wheels (value) {
if (value < this._wheels) {
throw new Error('数值太小了!');
}
this._wheels = value;
}
}
const obj = {
f() {
this.foo = 'bar';
}
};
new obj.f()
- 属性可枚举型
- 对象的每个属性都有一个描述对象,用来控制该属性的行为,obj.geyOwnPropertyDescriptor方法,可以获取该属性的描述对象,描述对象的eumerable属性,称为可枚举性,如果该属性为false,就表示某些操作会忽略当前属性
let obj = { foo : 123}
Object.getOwnPropertyDescriptor(obj, 'foo')
- 属性的遍历
- for in
for...in
循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)
- Object.keys
Object.keys
返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名
- Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames
返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名
- Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols
返回一个数组,包含对象自身的所有 Symbol 属性的键名
- Reflect.ownKeys(obj)
Reflect.ownKeys
返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举
- 注意事项:
- 以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则
- 首先遍历所有数值键,按照数值升序排列
- 其次遍历所有字符串键,按照加入时间升序排列
- 最后遍历所有 Symbol 键,按照加入时间升序排列
- 对象的拓展运算符
- 对象的拓展运算符,用于取出参数对象的所有可遍历属性,拷贝到当前对象之中
let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
x.a.b
- 由于数组是特殊的对象,所以对象的拓展运算符,也可以用于数组
let foo = {...['a','b','c']}
foo
- 如果拓展运算符后面是一个空对象,那么不会有任何效果
{...{}, a: 1}
- 如果拓展运算符后面不是一个对象,那么会自动转换为对象
{...1}
- 上面代码中,拓展运算符后面都是整数1,会自动转换为数值类型,由于该对象没有该属性,所以最后返回一个空对象
{...true}
{...undefined}
{...null}
- 如果运算符后面是一个字符串,会自动转换为一个类数组的对象,因此返回的不是一个空对象
{...'hello'}
- 对象的拓展运算符等同于使用
Object.assign()
方法
let aClone = { ...a };
let aClone = Object.assign({}, a);
const clone1 = {
__proto__: Object.getPrototypeOf(obj),
...obj
};
const clone2 = Object.assign(
Object.create(Object.getPrototypeOf(obj)),
obj
);
const clone3 = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
)
4、解构赋值
- 对象的解构赋值
- 对象的解构赋值用于从一个对象取值,相当于将目标对象自身的所有可以遍历,但尚未被读取的属性,分配到指定的对象上面,所有的键和他们的值,都会被拷贝到新对象上面
- 无法对
undefined
和null
进行转换,因为这两个无法转换为对象
let { ...z } = null;
let { ...z } = undefined;
let{ ...x, y, z } = someObject;
let { x, ...y, ...z } = someObject;
let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
x.a.b
5、Set和Map数据结构
- set
- 类似于数组的形式,但是成员都是唯一的,没有重复的值,Set本身是一个构造函数,用来生成Set数据结构
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
for (let i of s) {
console.log(i);
}
- 可以进行的遍历操作
Set.prototype.keys()
:返回键名的遍历器
Set.prototype.values()
:返回键值的遍历器
Set.prototype.entries()
:返回键值对的遍历器
Set.prototype.forEach()
:使用回调函数遍历每个成员
- map
- 本质上是键值对的结合(Hash结构),但是传统上只能用字符串当做键,这给其使用方式带来了很大的限制
const data = {};
const element = document.getElementById('myDiv');
data[element] = 'metadata';
data['[object HTMLDivElement]']
- 遍历方法
- Map 结构原生提供三个遍历器生成函数和一个遍历方法
Map.prototype.keys()
:返回键名的遍历器
Map.prototype.values()
:返回键值的遍历器
Map.prototype.entries()
:返回所有成员的遍历器
Map.prototype.forEach()
:遍历 Map 的所有成员