04JavaScript面试必备JS Web API

JS Web API知识点

vue和React框架应用广泛,封装了DOM操作。但DOM操作一直都是前端必备基础。
JS基础知识,规定语法(ECMA 262标准)
JS Web API,网页操作的API(W3C标准)
DOM  BOM   事件绑定   ajax  存储


DOM

问题:
	DOM是哪种数据结构
	DOM操作的常用API
	attr和property的区别
	一次性插入多个DOM节点,考虑性能
知识点:
	DOM本质:从html语言解析出来的一个文档树
	DOM节点操作
	DOM结构操作
	DOM性能

DOM节点操作

获取DOM节点

const div1 = document.getElementById('div1')
const divList = document.getElementsByTagName('div') // 集合
const containerList = document.getElementsByClassName('container') // 集合
const pList = document.querySelectorAll('p')

DOM节点的property

const pList = document.querySelectorAll('p')
const p1 = pList[0]

// property 形式
p1.style.width = '100px'
console.log(p1.style.width)
p1.className = 'red'
console.log(p1.className)
console.log(p1.nodeName)
console.log(p1.nodeType) // 1

DOM节点的attribute

const pList = document.querySelectorAll('p')
const p1 = pList[0]
// attribute
p1.setAttribute('data-name', 'imooc')
console.log(p1.getAttribute('data-name'))
p1.setAttribute('style', 'font-size: 50px;')
console.log(p1.getAttribute('style'))

property和attribute

property:修改对象属性,不会体现到html结构中
attribute:修改html属性,会改变html结构
两者都有可能引起DOM重新渲染
尽量使用property

DOM结构操作

新增/插入节点
获取子元素列表,获取父元素
删除子元素

const div1 = document.getElementById('div1')
const div2 = document.getElementById('div2')

// 新建节点
const newP = document.createElement('p')
newP.innerHTML = 'this is newP'
// 插入节点
div1.appendChild(newP)

// 移动节点  p1从div1移动到div2
//对于已有节点,appendChild()会移动该节点
const p1 = document.getElementById('p1')
div2.appendChild(p1)

// 获取p1的父元素
console.log( p1.parentNode )

// 获取子元素列表
const div1ChildNodes = div1.childNodes
console.log( div1.childNodes )
const div1ChildNodesP = Array.prototype.slice.call(div1.childNodes).filter(child => {
    if (child.nodeType === 1) {
        return true
    }
    return false
})
console.log('div1ChildNodesP', div1ChildNodesP)


//删除子元素
div1.removeChild( div1ChildNodesP[0] )

DOM性能

DOM操作非常昂贵,避免频繁的DOM操作
对DOM查询做缓存
将频繁操作改为一次性操作

//DOM性能 对DOM查询做缓存
//不缓存DOM查询结果
for (let i = 0; i < document.getElementsByTagName('p').length; i++) {
  //每次循环,都会计算length,频繁进行DOM查询
}

//缓存DOM查询结果
const pList = document.getElementsByTagName('p')
const length = pList.length
for (let i = 0; i < length; i++) {
  //缓存length,只进行一次DOM查询
}

//DOM性能  将频繁操作改为一次性操作
const list = document.getElementById('list')

// 创建一个文档片段,此时还没有插入到 DOM 结构中
const frag = document.createDocumentFragment()

for (let i = 0; i < 20; i++) {
    const li = document.createElement('li')
    li.innerHTML = `List item ${i}`

    // 先插入文档片段中
    frag.appendChild(li)
}

// 都完成之后,再统一插入到 DOM 结构中
list.appendChild(frag)

console.log(list)

BOM

题目
	1.如何识别浏览器的类型
		navigator.userAgent
	2.分析拆解url各个部分
	url组成:protocol :// hostname[:port] / path / [;parameters][?query]#fragment
		location.href
		location.protocol
		location.pathname
		location.search
		location.hash

事件

题目
	编写一个通用的事件监听函数
	描述事件冒泡的流程
	无限下拉的图片列表,如何监听每个图片的点击?
知识点
	事件绑定 事件冒泡 事件代理

事件绑定

//普通写法
const btn=document.getElementById('btn1')
btn.addEventListener('click',event=>{
	console.log('clicked')
})

//通用的绑定函数
function bindEvent(elem, type, fn) {
    elem.addEventListener(type, fn)
}
const a = document.getElementById('link1')
bindEvent(a, 'click', e => {
    e.preventDefault()//阻止默认行为
    alert('clicked')
})

阻止冒泡

/*body下有p1,当点击p1时,运行结果打印:激活,取消。
触发body监听事件,我们要阻止p1向上冒泡。event.stopPropagation
*/
const p1 = document.getElementById('p1')
bindEvent(p1, 'click', event => {
    event.stopPropagation() // 阻止冒泡
    console.log('激活')
})
const body = document.body
bindEvent(body, 'click', event => {
    console.log('取消')
    // console.log(event.target)
})

代理绑定

//改进 通用的事件监听函数
<button id="btn1">一个按钮</button>
<div id="div3">
    <a href="#">a1</a><br>
    <a href="#">a2</a><br>
    <a href="#">a3</a><br>
    <a href="#">a4</a><br>
    <button>加载更多...</button>
</div>

<script>
//事件代理
function bindEvent(elem, type, selector, fn) {
  if (fn == null) {
    fn = selector
    selector = null
  }
  elem.addEventListener(type, event => {
    const target = event.target
    if (selector) {
      // 代理绑定
      if (target.matches(selector)) {
        fn.call(target, event)
      }
    } else {
      // 普通绑定
      fn.call(target, event)
    }
  })
}
// 普通绑定
const btn1 = document.getElementById('btn1')
bindEvent(btn1, 'click', function (event) {
  // console.log(event.target) // 获取触发的元素
  event.preventDefault() // 阻止默认行为
  alert(this.innerHTML)
})

// 代理绑定
const div3 = document.getElementById('div3')
bindEvent(div3, 'click', 'a', function (event) {
  event.preventDefault()
  alert(this.innerHTML)
})
</script>

描述事件冒泡的流程

基于DOM树形结构
事件会顺着触发元素向上冒泡
应用场景:代理

无限下拉图片列表,如何监听每个图片的点击

事件代理
用e.target获取触发元素
用matche来判断是否是触发元素

Ajax

题目
	手写一个简易的ajax
	跨域的常用实现方式
知识点
	XMLHttpRequest
	状态码
	跨域:同源策略,跨域解决方案
//get请求
const xhr = new XMLHttpRequest()
xhr.open('GET', '/data/test.json', true)
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
        if (xhr.status === 200) {
            // console.log(
            //     JSON.parse(xhr.responseText) //变成json形式
            // )
            alert(xhr.responseText)
        } else if (xhr.status === 404) {
            console.log('404 not found')
        }
    }
}
xhr.send(null)

//post请求  此处代码无法请求 /login是请求的地址
const xhr = new XMLHttpRequest()
xhr.open('GET', "/login", false)
xhr.onreadystatechange = function () {
    //这里的函数异步执行
    if (xhr.readyState === 4) {
        if (xhr.status === 200) {
            alert(xhr.responseText)
        }
    }
}
const postData = {
    userName: 'zhangsan',
    password: 'xxx'
}
xhr.send(JSON.stringify(postData))

xhr.readyState

0-(未初始化)还没有调用send()方法
1-(载入)已调用send()方法,正在发送请求
2-(载入完成)send()方法执行完成,已经接收到全部响应内容
3-(交互)正在解析响应内容
4-(完成)响应内容解析完成,可以在客户端调用

xhr.status

2xx-表示成功处理请求,如200
3xx-需要重定向,浏览器直接跳转,如301 302 304
4xx-客户端请求错误,如404 403
5xx-服务端错误

跨域

跨域的实现方式

JOSNP
CORS

同源策略

ajax请求时,浏览器要求当前网页和server必须同源(安全)
同源:协议、域名、端口,三者必须一致
比如,前端:http://a.com:8080; server:https://b.com/api是不同源的
注意,此处针对浏览器。服务器仍可以向另一个服务器发送请求

加载图片css js可无视同源策略
<img src=跨域图片地址/>
<link href=跨域css地址/>
<script src=跨域js地址></script>
<img/>可用于统计打点,可使用第三方统计服务
<link /><script>可使用CDN,CDN一般都是外域
<script>可实现JSONP

所有的跨域,都必须进过server端允许配合
未经server端允许就实现的跨域,说明浏览器有漏洞

JSONP

了解实现原理
<script>可绕过跨域限制
服务器可以任意动态拼接数据返回
所以,<script>就可以获得跨域数据,只要服务端愿意返回
//Jquery实现jsonp
$.ajax({ 
	url:'http://localhost:8882/x.json',
	dataType:'jsonp'.
	jsonpCallback:'callback',
	success:function(data){
		console.log(data)
	}
})

CORS-服务器设置http header(通过服务端实现跨域,了解)


//手写简易ajax
function ajax(url) {
  const p = new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open('GET', url, true)
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          resolve(
            JSON.parse(xhr.responseText)
          )
        } else if (xhr.status === 404 || xhr.status === 500) {
          reject(new Error('404 not found'))
        }
      }
    }
    xhr.send(null)
  })
  return p
}

const url = '/data/test.json'
ajax(url)
  .then(res => console.log(res))
  .catch(err => console.error(err))

Cookie

本地和服务端通讯,但被“借用”到本地存储来
最初的设计并不是本地存储,而是服务端通讯
可用document.cookie='...'来修改

cookie的缺点
	存储大小,最大4kb
	http请求时需要发送到服务端,增加请求数据量(每次http请求都会带上cookie)
	只能用document.cookie='...'来修改,太过简陋

sessionStorage和localStorage

HTML5专门为存储而设计,最大可存5M
API简单易用 setItem  getItem
不会随着http请求被发送出去

localStorage数据会永久存储,除非代码或手动删除
sessionStorage数据只存在于当前会话,浏览器关闭则清空
一般用localStorage会更多一些
localStorage.setItem('a',100) //undefined
localStorage.getItem('a')  //'100'  以字符串形式存储

描述cookie localStorage sessionStorage区别

容量
API易用性
是否跟随http请求发送出去
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值