JS面试题

  • 事件代理
    • “事件代理(事件委托)”即是把原本需要绑定在子元素的响应事件(click、keydown......)委托给父元素,让父元素担当事件监听的职务,多用于子元素个数不确定或者量很大的情况。通过事件冒泡触发父元素绑定的事件,再根据e.target.nodeName或者e.target.matches获取触发事件的具体子元素,对子元素进行进一步处理
    • 代码简洁
    • 减少浏览器内存占用
    • 但是,不要滥用
<button id='btn'>添加按钮</button>
<ul id='uls'>
	<li>1</li>
	<li>2</li>
	<li>3</li>
</ul>
<script>
var lis = document.getElementsByTagName("li"),
	btn = document.getElementById("btn"),
	uls = document.getElementById("uls");

btn.onclick = function(){
	var len = lis.length;
	var li = document.createElement("li");
	li.innerHTML = len;
	uls.appendChild(li);
}
uls.onclick = function(e){
	var e = window.event || e;
	var tar = e.target || e.srcElement;
	if(tar.nodeName=='LI'){
		tar.style.background='red';
	}
}
//本身是给li添加事件,现在委托在ul身上

</script>
</body>
</html>

ajax

题目:

  • 手写一个简易的ajax

    //XMLHttpRequest 对象用于在后台与服务器交换数据。
    //get请求
    const xhr = new XMLHttpRequest();
    xhr.open('GET','./data/test.json',true);//true 异步请求
    xhr.onreadystatechange = function () {
      if (xhr.readyState===4){
        if(xhr.status === 200){
          // console.log(JSON.parse(xhr.responseText))
          alert(xhr.responseText)
        }else if(xhr.status === 404){
          console.log('404 not found')
        }
      }
    }
    xhr.send(null)
    //post请求
    const xhr = new XMLHttpRequest();
    xhr.open('POST','./login',true);
    xhr.onreadystatechange = function () {
      if (xhr.readyState===4){
        if(xhr.status === 200){
          // console.log(JSON.parse(xhr.responseText))
          alert(xhr.responseText)
        }
      }
    }
    const postData = {
      userName:'zhangsan',
      password:'xxx'
    }
    xhr.send(JSON.stringify(postData));//必须发送字符串类型
    
    //promise形式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))
    
    
  • 跨域的常用实现方式

    • JSONP
    • CORS

知识点:

  • XMLHttpRequest

  • 状态码

    • xhr.readyState

      • 0 (未初始化)还没有调用send()方法
      • 1(载入)已调用send()方法,正在发送请求
      • 2(载入完成)send()方法执行完成,已经收到全部响应内容
      • 3(交互)正在解析响应内容
      • 4(完成)响应内容解析完成,可以在客户端调用(只需要这一种)
    • xhr.status(**)

      • 2xx -表示成功处理请求,如200
      • 3xx 需要走重定向,浏览器直接跳转,如301(永久重定向),302(临时重定向),304(资源为改变,使用缓存资源)
      • 4xx 客户端请求错误,如404(找不到地址),403(客户端没有权限)
      • 5xx 服务器端错误
  • 跨域:同源策略,跨域解决方案

    • 什么是跨域(同源策略)
      • ajax请求时,浏览器要求当前网页和server必须同源(安全)
      • 同源:协议(http,https),域名(xxx.com),端口(80port),三者必须一致
      • 前端:http://a.com:8080/;服务端:https://b.com/api/xxx(端口默认是80)不能跨域
      • 所有跨域,都必须经过server端允许和配合
      • 未经server端允许就实现跨域,说明浏览器有漏洞,危险信号
    • JSONP
    • CORS(服务端支持)
  • 加载图片css,js可无视同源策略(浏览器不限制)

    • <img src="跨域的图片地址"/>
      • <img/>可以用于统计打点,可以使用第三方统计服务
      • <link/><script>可以使用CDN,CDN一般都是外域
      • <script>可以实现JSONP
    • <link href="跨域的css地址"/>
    • <script src="跨域的js地址"></script>

解答:

JSONP

  • 访问http://imooc.com/,服务端一定返回一个html文件吗?

  • 服务器可以任意动态拼接数据返回,只要符合html格式要求

  • 同理于<script src="https://imooc.com/getData.js">

  • <script>可以绕过跨域限制

  • 服务器可以任意动态拼接数据返回

  • 所以,<script>就可以获得跨域的数据,只要服务端愿意返回

    image-20210412141141473
<body>
<p>一段文字 1</p>

<script>
    window.abc = function (data) {
        console.log(data)
    }
</script>
<!--html端口和访问的jsonp.js端口不同,实现了跨域-->
<script src="http://localhost:8002/data/jsonp.js?username=xxx&callback=abc"></script>
<!--
<script src="http://localhost:8002/data/jsonp.js?username=xxx"></script>
服务器端可以动态拼接前端传过去的数据返回,例如username

<script src="http://localhost:8002/data/jsonp.js?username=xxx&callback=abc"></script>
可以修改全局函数名
-->
</body>
//jsonp文件
abc(
    { name: 'xxxgfhdfgh' }
)