目录
1.ajax(Async JavaScript and XML)的原理
2.通过XMLHttpRequest对象的open()方法与服务器端建立连接
3.构建请求所需的数据内容,并通过XMLHttpRequest对象的send()方法发送到服务器端
4.通过XMLHttpRequest对象提供的onreadystatechange事件监听服务器端的通信状态
1.判断一个属性是属于实例对象还是继承于构造函数
1.通过hasOwnProperty()
检测一个属性是否属于自身对象,还是继承于原型链上的。
function Person (name, age) {
this.name = name
this.age = age
}
// 在构造函数原型上面添加属性
Person.prototype.sex = 'nan'
// 实例化对象
var p = new Person('zz', 11)
// 针对p添加属性
p.phone = 674886576
console.log(p)
console.log(p.hasOwnProperty('phone'))//true,是属于它自身的
console.log(p.hasOwnProperty('sex'))//false,是继承于原型链上的
// 会都打印出来
for (let i in p) {
console.log(p[i])//zz 11 674886576 nan
}
// 可以先检查一下,把属于自身对象的打印出来
for (let i in p) {
if (p.hasOwnProperty(i))
console.log(p[i])//zz 11 674886576
}
2.bind和call,apply的作用以及区别
1.作用:
它们都是:改变函数运行时this的指向。
var uname='zz'
var obj={
uname:'ls',
say:function(){
console.log(this.uname);
}
}
obj.say()//ls
// obj.say作为一个回调函数来执行的,当回调函数回到主栈来执行的时候,他是在全局执行上下文的环境里执行的,所以this指向的是window。
setTimeout(obj.say,0)//zz
// 需要改变一下this指向,让它指向函数obj
setTimeout(obj.say.bind(obj),0)//ls
2.区别:
1.apply:
两个参数,第一个是this指向,第二个是函数接收的参数,以数组的形式传入。
function fun (...argus) {
console.log(this)
console.log(...argus)
}
var person = {
myname: 'zz'
}
// apply:传入的参数必须是一个数组
fun.apply(person, [1, 2, 3])//{myname: 'zz'} 1 2 3
fun(1, 2, 3, 4)//Window 1 2 3 4
// 如果第一个参数为null或者undefined,this默认指向window
fun.apply(null, [7, 7])//Window 7 7
fun.apply(undefined, [7, 7])//Window 7 7
2.call:
两个参数,第一个是this指向,第二个是参数列表。
fun.call(person, 1, 2, 3)//{myname: 'zz'} 1 2 3
fun(1, 2, 3, 4)//Window 1 2 3 4
call和apply改变this指向,原函数立即执行。临时改变this指向一次。
3.bind:
两个参数,第一个是this指向,第二个是参数列表。
fun.bind(person)//没有打印,是会返回一个函数,所以需要接收一下
var bindFun = fun.bind(person)//接收一下
bindFun()//{myname: 'zz'}
bindFun()//{myname: 'zz'},不管执行多少次,都是指向obj对象
bindFun(1, 2, 3)//1 2 3
bind改变this指向,不会立即执行,是会返回一个永久改变this指向的函数。
3.总结:
三者第一个参数都是this指向,第二个参数就不一样。
3.ES6中Promise的认识
是异步编程的一种解决方案。
// 多个串联的异步操作形成的回调地狱
setTimeout(()=>{
console.log(111);
setTimeout(()=>{
console.log(222);
setTimeout(()=>{
console.log(333);
},3000)
},2000)
},1000)
// 第一个异步操作逻辑
function fun (ms, val, nextval) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222)
console.log(111)
}, ms)
})
}
// 第二个异步操作逻辑
fun(1000).then((value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(value)
resolve(333)
}, 2000)
})
})
// 第三个异步操作逻辑
.then((value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(value)
}, 3000)
})
})
1.三种状态:
pending(进行中),fulfilled(已成功),rejected(已失败)
2.特点:
状态不受外界的影响,只有异步操作的结果,决定当前是哪一种状态,一旦状态改变就不会再变(pending-->fufilled,pending-->rejected)
3.用法:
Promise是一个构造函数,用来生成Promise实例。
- Promise构造函数接收一个函数作为参数,这个函数有两个参数
- resolve函数:将Promise对象的状态从未完成变成成功,在异步操作成功的时候调用
- reject函数:将Promise对象的状态从未完成变成失败,在异步操作失败的时候调用
const p=new Promise(function(resolve,reject){
resolve()//返回异步操作的结果,作为参数传递出去
reject()//返回异步操作的结果,作为参数传递出去
})
4.ES6中Promise实例的方法
1.then()
当实例状态发生改变的时候的回调函数,返回的是一个新的Promise实例,也就是Promise可以链式书写的原因。
const p = new Promise(function (resolve, reject) {
setTimeout(() => {
const time = new Date().getTime()
// 如果时间未偶数,返回成功态
if (time % 2 == 0) {
resolve('返回成功的数据' + time)
} else {
reject('失败的数据' + time)
}
}, 1000)
})
p.then((value) => {//resolve(已成功)的状态
console.log('成功的' +value)//返回成功的数据1660321080130
}, (reason) => {//rejected(已失败)的状态
console.log('失败的' +reason)//失败的数据1660321047941
})
2.catch()
用来指定发生错误的回调函数。一般来说通过catch替代then中的第二个参数。
。。。
reject('失败的数据' + time)
。。。
p.catch((value) => {
console.log(value)//失败的数据1660321582654
})
const p = new Promise(function (resolve, reject) {
setTimeout(() => {
const time = new Date().getTime()
// 如果时间未偶数,返回成功态
if (time % 2 == 0) {
resolve('返回成功的数据' + time)
} else {
reject('失败的数据' + time)
}
}, 1000)
})
p.then((value) => {//resolve(已成功)的状态
console.log('成功的' +value)//返回成功的数据1660321080130
}).catch((value) => {
console.log(value)
})
)
3.finally()
用来指定不管Promise对象状态最后如何,它都是会执行的操作。
const p = new Promise(function (resolve, reject) {
setTimeout(() => {
const time = new Date().getTime()
// 如果时间未偶数,返回成功态
if (time % 2 == 0) {
resolve('返回成功的数据' + time)
} else {
reject('失败的数据' + time)
}
}, 1000)
})
p.then((value) => {
console.log(value)
}).catch((value) => {
console.log(value)
})
.finally(() => {
// 不管最终都结果是什么,都会执行这一步
console.log('最后的结果')
})
5.ES6中回调地狱及如何使用Promise解决
回调地狱:多个串联的异步操作。
解决回调地狱关键:then()链式调用。
// 获取歌单数据-->再获取歌单列表数据-->歌曲的信息
// 需求:一秒钟之后输出1,然后两秒钟之后输出2,然后三秒钟之后输出3
// 1.用定时器
setTimeout(() => {
console.log(1)
setTimeout(() => {
console.log(2)
setTimeout(() => {
console.log(3)
}, 3000)
}, 2000)
}, 1000)
//用Promise代码信息更加清晰,后期维护更加方便
// 2.用Promise解决回调地狱的问题
// 歌单id-->歌单列表-->歌单的信息
function getData () {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(1)//拿到歌单数据
resolve(2)//传歌单id过去
}, 1000)
})
}
getData().then((value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(value)//拿到id,歌单列表
resolve(3)//歌曲id传过去
}, 2000)
})
}).then((value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(value)//歌曲信息
}, 3000)
})
})
// 1 2 3
6.ES6中Promise.all的理解及应用场景
1.理解
用于将多个Promise实例,包装成一个新的Promise实例。
let p1 = new Promise((resolve, reject) => {
resolve('成功01')
})
let p2 = new Promise((resolve, reject) => {
resolve('成功02')
})
let p3 = new Promise((resolve, reject) => {
resolve('成功03')
})
// 参数可以不是数组,但是必须是iterator接口
let pAll = Promise.all([p1, p2, p3])
console.log(pAll)
//pAll的状态,由p1,p2,p3来决定,只有当这三个都为成功状态,pAll才会为成功;但是由一个是失败,那么就是失败
有一个失败,那么就是失败。这个时候第一个失败的实例的返回值,会传递给pAll的回调函数。
只有拿到02的失败数据,拿到的失败数据是第一个失败的数据。
let p2 = new Promise((resolve, reject) => {
reject('失败02')
})
let p3 = new Promise((resolve, reject) => {
reject('失败03')
})
pAll.then((value) => {
console.log(value)
}).catch((reason) => {
console.log(reason)//失败02
})
如果作为参数的实例,自己定义了catch方法,那么它一旦rejected,不会触发pAll的catch() 方法。
let p2 = new Promise((resolve, reject) => {
reject('失败02')
}).catch((reason => console.log(reason)))
let p3 = new Promise((resolve, reject) => {
resolve('成功03')
})
let pAll = Promise.all([p1, p2, p3])
pAll.then((value) => {
console.log(value)//(3) ['成功01', undefined, '成功03']
}).catch((reason) => {
console.log(reason)
})
2.应用场景
多个请求结果合并在一起,在根据这个结果来渲染页面。
//想要等所有数据全获取之后,再渲染页面
function getBannerList () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('轮播图的数据')
}, 1000)
})
}
function getMusicList () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('歌曲列表的数据')
}, 2000)
})
}
function getCateList () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('歌曲分类的数据')
}, 3000)
})
}
function initLoad () {
let All = Promise.all([getBannerList(), getMusicList(), getCateList()])
console.log(All)
All.then((value) => {
// 没有立即出现,因为有定时器
console.log(value)//(3) ['轮播图的数据', '歌曲列表的数据', '歌曲分类的数据']
})
}
initLoad()
7.ES6中Promise.race的用法及应用场景
将多个Promise实例包装成一个新的Promise实例。
1.区别:
Promise.race区别于Promise.all:只要实例中有一个先改变状态,就会把这个实例的参数的返回值传给prace的回调函数。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1成功')
}, 2000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2成功')
}, 1000)
})
// 调用
const prace = Promise.race([p1, p2])
console.log(prace);//p2成功,因为p2先改变
2.应用场景
请求超时时显示。提示用户时网络超时造成的,而不是应用问题。
function request () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('请求成功')
}, 4000)
})
}
// 模拟请求时间超时
function timeout () {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('网络不佳,请求超时')
}, 3000)
})
}
Promise.race([request(), timeout()]).then((value) => {
console.log(value)
}).catch((reason) => {
console.log(reason)//网络不佳,请求超时
})
8.使用Promise封装ajax
先运行网易云API,网易云音乐 NodeJS 版 API
function getJSON (url) {
return new Promise((resolve, reject) => {
// 创建一个实例对象
let xhr = new XMLHttpRequest()
// 新建一个http请求
// 执行什么操作;url传参;是否执行异步操作true执行
xhr.open('GET', url, true)
// 发送http请求.为post里面放post参数,get里面为null即可
xhr.send(null)
// 设置状态的监听函数
xhr.onreadystatechange = function () {
// 判断请求是否完成了
if (xhr.readyState !== 4) return//表示请求成功
// 当请求成功或者失败,需要改变promise实例的状态
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response)//请求结果
} else {
reject(new Error(this.statusText))
}
}
// 设置错误的监听函数
xhr.oneerror = function () {
reject(new Error(xhr.statusText))
}
// 设置响应数据类型
xhr.responseType = 'json'
})
}
// http://localhost:3000/personalized?limit=10,先运行网易云API
getJSON('http://localhost:3000/personalized?limit=10').then((value) => {
console.log(value)
}).catch((reason) => {
console.log(reason)
})
如果没有给json,则给responseText,他就会返回json格式;后面还需要转换为对象。
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.responseText)//请求结果
}
// xhr.responseType = 'json'
getJSON('http://localhost:3000/personalized?limit=10').then((value) => {
console.log(JSON.parse(value))
})
9.ajax的原理及如何实现
1.ajax(Async JavaScript and XML)的原理
通过XMLHttpRequest对象来向服务器发送异步请求,从服务器获取数据,然后用js来操作DOM去更新页面。
2.实现过程
1.创建Ajax的核心对象XMLHttpRequest对象
new XMLHttpRequest()实例化对象
2.通过XMLHttpRequest对象的open()方法与服务器端建立连接
new XMLHttpRequest().open(method:表示请求方式,url:服务器的地址) (method和url必选的)
3.构建请求所需的数据内容,并通过XMLHttpRequest对象的send()方法发送到服务器端
new XMLHttpRequest().send(body:发送的数据)
如果使用get请求发送数据,send()参数设置为null
4.通过XMLHttpRequest对象提供的onreadystatechange事件监听服务器端的通信状态
new XMLHttpRequest().onreadystatechange 主要监听的属性是实例化对象中的readyState(五个状态)
0:未打开,open()未调用;
1:open()调用了,send()方法未调用,还没有发送请求;
2 :send()调用了,并且响应头和响应状态已经返回;
3:响应体正在下载,responseText属性(接收服务端响应的结果)获取到了部分数据;
4:整个请求过程已经完毕,此时获取的数据才是完整的数据。
只要readyState属性值发生了改变,那么onreadyStatechange就会被触发。
5.接受并处理服务端向客户端响应的数据结果
6.将处理结果更新到HTML页面中
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://localhost:3000/personalized?limit=10')
xhr.send(null)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {//表示获取成功
if (xhr.status >= 200 && xhr.status < 300) { //判断是否获取成功
// console.log(xhr.responseText)//json格式
// 转换一下为对象
let obj = JSON.parse(xhr.responseText)
console.log(obj)
obj.result.forEach(item => {
// 创建一个dom节点
var div = document.createElement('div')
// 写入内容
div.innerHTML = item.name
// 获取body元素
document.querySelector('body').appendChild(div)
})
} else if (xhr.status >= 400) {
console.log('错误信息' + xhr.status)
}
}
}
拿到json格式
转换为对象
渲染HTML
10.JS中如何封装一个ajax请求
1.封装需要:
1.请求方式
2.请求地址
3.请求参数
4.请求参数的类型
5.请求返回的结果
function ajax (options) {
// 创建XMLHttpResquest对象
const xhr = new XMLHttpRequest
// 1.初始化参数的内容
options = options || {}
// 有传就给自己,没有传就给默认的(get);同时把值都传为大写
options.type = (options.type || 'GET').toUpperCase()
// 参数类型
options.dataType = options.dataType || 'json'
// 参数
const params = options.data
// 2.发送请求
if (options.type === 'GET') {
// 第三个参数async:布尔值,表示是否异步执行操作
xhr.open('GET', options.url + "?" + params, true)
// send发送
xhr.send(null)
} else if (options.type === 'POST') {
xhr.open('POST', options.url, true)
xhr.send(params)
}
// 3.接收请求
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
// responseText字符串形式的响应数据
// reponseXML XML形式的响应数据
options.success(xhr.responseText, xhr.responseXML)
} else {
options.fail("参数错误" + status)
}
}
}
}
ajax({
type: 'get',
dataType: 'json',
// 以网易云为案例
data: {
limit: 10
},
url: 'http://localhost:3000/personalized',
success: function (text, xml) {//请求成功之后的回调函数
// console.log(text)
console.log(JSON.parse(text))
},
fail: function (status) {//请求失败的回调函数
console.log(status)
}
})
拿到json格式
转换为对象
注意点:参数的处理,如果有别的参数也要传的话,就不能这样拼接。
xhr.open('GET', options.url + "?" + getParams(params), true)
//对参数做处理
function getParams (data) {
let arr = []
// url = 'limit=10&aage=19'
for (let key in data) {
arr.push(`${key}=${data[key]}`)
}
//console.log(arr)//['limit=10']
// ['limit=10', 'age=10']
//console.log(arr.join('&'))//limit=10,它是字符串
// limit=10&age=10
return arr.join('&')
}
getParams({ limit: 10, age: 10 })
数据一样的也可以拿到,data中的limit是没有起到作用的,因为没有对这个参数做处理,是把所有参数都返回了。