Web前端高频面试题解析(javascript篇)--- 每日十题(4)

目录

1.判断一个属性是属于实例对象还是继承于构造函数

1.通过hasOwnProperty()

2.bind和call,apply的作用以及区别

1.作用:

2.区别:

1.apply:

2.call:

3.bind:

3.总结:

3.ES6中Promise的认识

1.三种状态:

2.特点:

3.用法:

4.ES6中Promise实例的方法

1.then()

2.catch()

3.finally()

5.ES6中回调地狱及如何使用Promise解决

6.ES6中Promise.all的理解及应用场景

1.理解

2.应用场景

7.ES6中Promise.race的用法及应用场景

1.区别:

 2.应用场景

8.使用Promise封装ajax

9.ajax的原理及如何实现

1.ajax(Async JavaScript and XML)的原理

2.实现过程

1.创建Ajax的核心对象XMLHttpRequest对象

2.通过XMLHttpRequest对象的open()方法与服务器端建立连接

3.构建请求所需的数据内容,并通过XMLHttpRequest对象的send()方法发送到服务器端

4.通过XMLHttpRequest对象提供的onreadystatechange事件监听服务器端的通信状态

5.接受并处理服务端向客户端响应的数据结果

6.将处理结果更新到HTML页面中

10.JS中如何封装一个ajax请求

1.封装需要:


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实例。

  1. Promise构造函数接收一个函数作为参数,这个函数有两个参数
  2. resolve函数:将Promise对象的状态从未完成变成成功,在异步操作成功的时候调用
  3. 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是没有起到作用的,因为没有对这个参数做处理,是把所有参数都返回了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值