前端点滴(JS核心)(一)----倾尽所有
一、回调函数
1. 函数也是对象
JavaScript 中处处皆对象,函数也不例外。
那么如何理解函数也是对象呢?这里主要要表达的是函数也可以使用对象那样的点语法。比如前面学习的Person.prototype;
比如在函数内部,可以使用“函数.length”来表示函数的形参个数,可以使用“函数.name”来获取当前的函数名。
function Person(x,y){
console.log(Person.length); //=> 2
console.log(Person.name); //=> Person
}
Person(1,2);
2. 函数也是值
JavaScript 语言将函数看作一种 值,与其它值(数值、字符串、布尔值等等)地位相同。凡是可以使用值的地方,就能使用函数。比如,可以把函数赋值给变量或者对象的属性值,也可以当作参数传入其他函数,或者作为函数的结果返回。函数只是一个可以执行的值,此外并无特殊之处。
由于函数与其他数据类型地位平等,所以在 JavaScript 语言中又称函数为 第一等公民。
/* 当作一个值,赋值给一个变量 */
function a(){
console.log(1);
}
var b = a; // 将函数当作一个值,赋值给一个变量
b(); //=> 1
var c = function(){ // 将函数当作一个值,赋值给一个变量
console.log(1);
}
c(); //=> 1
/* 当作一个对象成员的成员值 */
var obj = {
name:'chen',
say:function(){ // 将函数当作一个对象属性的值
console.log(1);
}
}
obj.say(); //=> 1
/* 当作一个返回值 */
function fn1(){
var b = 1;
function fn2(){
console.log(b++);
}
return fn2
}
var fn = fn1();
fn(); //=> 1
fn(); //=> 2
fn(); //=> 3
/* 当作一个参数进行传递 */
function callback(a){
console.log(a);
}
function fn(callback){ // 将函数当作一个参数进行传递(回调函数)
var a = 1;
callback(a);
}
fn(callback); //=> 1
3. 函数可以作为参数传递(回调函数)
在JavaScript中,回调函数具体的定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A。我们就说函数A叫做回调函数。如果没有名称(函数表达式),就叫做匿名回调函数。
来一个具体的实例:
function callback(a){
console.log(a);
}
function fn(callback){
var a = 1;
callback(a);
}
fn(callback); //=> 1
其中,下述函数可以称为获取函数(通过参数a,带有获取功能)
function callback(a){
console.log(a);
}
而下述函数被称为资源函数(函数内自带资源,或者通过某些方法获得的资源,通过参数引入获取函数,使得函数与函数间具有通讯功能)
function fn(callback){
var a = 1;
callback(a);
}
资源函数中引入获取函数,获取资源
fn(callback);
匿名回调函数
非匿名函数,传递的是函数名的应用。
而匿名函数就是在传参过程中直接传递函数,因为函数可以作为参数传递。
function fn(callback){
var a = 1;
callback(a);
}
fn(function (a){console.log(a)}) // 匿名回调函数,回调函数不带名字。
4. 回调函数的执行时机
回调函数,一般在同步情境下是最后执行的,而在异步情境下有可能不执行,因为事件没有被触发或者条件不满足。
5. 回调函数应用
(1)同步中的回调
callback 不一定用于异步,一般同步(阻塞)的场景下也经常用到回调,比如要求执行某些操作后执行回调函数。
同步(阻塞)中使用回调的例子:
var func1=function(callback){
//do something...(同步任务)
(callback && typeof(callback) === "function") && callback();
}
var func2=function(){
/* 定义func2 */
//do something...
}
func1(func2); //fun1执行完后执行fun2
(2)异步中的回调
异步回调的例子:
/* 定时器中使用回调,模拟异步 */
function callback(data){
if(data.username === 'admin'){
console.log('验证成功');
}
}
function fn(callback){
setTimeout(function(){
var obj = {
username:'admin',
password:123456
}
callback(obj)
},1000)
}
fn(callback) //=> 1s后,'验证成功' 。
总结:
- 资源加载:动态加载js文件后执行回调,加载iframe后执行回调,ajax操作回调,图片加载完成执行回调,等异步操作。
- 事件:DOM事件及Node.js事件基于回调机制 (Node.js回调可能会出现多层回调嵌套的问题)。
- setTimeout的延迟时间为0,这个hack经常被用到,settimeout调用的函数其实就是一个callback的体现
- 链式调用:链式调用的时候,在赋值器(setter)方法中(或者本身没有返回值的方法中)很容易实现链式调用,而取值器(getter)相对来说不好实现链式调用,因为你需要取值器返回你需要的数据而不是this指针,如果要实现链式方法,可以用回调函数来实现【不太能理解】
- setTimeout、setInterval的函数调用得到其返回值。由于两个函数都是异步的,即:他们的调用时序和程序的主流程是相对独立的,所以没有办法在主体里面等待它们的返回值,它们被打开的时候程序也不会停下来等待,否则也就失去了setTimeout及setInterval的意义了,所以用return已经没有意义,只能使用callback。【不太理解】callback的意义在于将timer执行的结果通知给代理函数进行及时处理。
二、Ajax
前言
下载 wampserver 、apache 服务器。
下载 postman 请求抓包工具
安装方法:
参考:https://blog.csdn.net/qq_34195507/article/details/94851028
参考:https://blog.csdn.net/weixin_43738701/article/details/86607148
Ajax 概述
1. 什么是 Ajax
Ajax中的第一个A是Asynchronous [eɪˈsɪŋkrənəs]
(异步)JavaScript and XML的缩写。可以看出它不是一种技术,而是多种技术的综合体。
其中有JavaScript、有xml、有json、有html、有css、有dom、有XMLHttpRequest对象等等。
XMLHttpRequest对象,也叫做Ajax对象,浏览器中自带的对象。
Ajax的工作也是基于http协议的,用于传输。
2. Ajax 能做什么
- 从服务器中加载资源、上传资源到服务器。
- 提高用户的体验。
- 表单的验证。
- 引入百度地图、谷歌地图。
- 网页版的聊天室。
- 无刷新分页。
- …
3. Ajax 工作原理
1)创建Ajax 对象 var xhr = new XMLHttpRequest();
2)准备发送资源以及发送地址,请求方式,确定同步发送还是异步发送。
3)调用open() 方法对资源进行发送xhr.open('请求方法','请求地址',同步或异步)
4)监听服务器返回的结果xhr.onreadystatechange = function(){/* 监听函数 */}
5)发送请求,调用Ajax 对象的send() 方法。xhr.send()
4. 主要成员属性以及方法
属性:
- readyState:表示xhr 工作到何种情况。
- onreadystatechange:事件,表示 readyState 改变时触发的事件。
- status:http 状态码。
- responseText:用来接收返回的文本类型的数据
- responseXML:用来接收返回的是XML格式的数据
方法:
- open():设置(定义)一个请求,比如(get请求、post请求…)
- send():发送设置好的请求,还可以用来发送请求资源。
- setRequestHeader():设置ajax请求头信息
5. Ajax 的基本使用
完成验证用户名案例,要求用户名唯一,就是不能有重复。
页面中有一个文本框,当失去焦点的时候,验证输出的内容是否已经存在。
HTML
<input type="text" name="username" id="username"> <span id="msg"></span>
JS
/* GET请求 */
document.getElementById('username').onblur = function(){
/* 1.创建Ajax 对象实例 */
var xhr = new XMLHttpRequest();
/* 2.准备发送资源 */
var uname = this.value;
/* 3. 备发送资源以及发送地址,请求方式,确定同步发送还是异步发送*/
/* 注意:发送get请求,资源写在请求路径上以 ?连接 */
xhr.open('get','checkusername.php?u='+uname,true);
/* 4.发送请求 */
xhr.send();
/* 5.监听服务器返回的结果 */
xhr.onreadystatechange = function(){
if(xhr.readyState == 4&& xhr.status == 200){
/* 处理返回的结果 */
var res = xhr.responseText;
if(res == 1){
document.getElementById('msg').innerHTML = '<font color="red">sorry,用户名已存在</font>'
}else{
document.getElementById('msg').innerHTML = '<font color="green">恭喜用户成功</font>'
}
}
}
}
PHP
/* checkusername.php */
/* 后台服务器进行逻辑判断 */
<?php
$arr = ['zhangsan','lishi','wangwu'];
$u = $_GET['u'];
if(in_array($u,$arr)){
echo 1;
}else{
echo 0;
}
>
注意点:
- 用get方式请求,所以参数直接写到url上即可。服务器端获取地址栏的参数,同样使用$_GET来获取。
- 接受服务器返回的数据时要对Ajax进程进行监听。
如果没有进行Ajax 进程监听,无法得到服务器返回的数据。
/* GET请求 */
document.getElementById('username').onblur = function(){
var xhr = new XMLHttpRequest();
var uname = this.value;
xhr.open('get','checkusername.php?u='+uname,true);
xhr.send();
var res = xhr.responeText;
console.log(res); //=> 无法获取返回数据
if(res == 1){
document.getElementById('msg').innerHTML = '<font color="red">sorry,用户名已存在</font>'
}else{
document.getElementById('msg').innerHTML = '<font color="green">恭喜用户成功</font>'
}
}
原因就是因为Ajax 请求存在过程问题,由于send()
后数据进行传输,如果传输数据过大需要的时间就越长,而JavaScript并不会等待有数据了它才返回(异步问题)。所以需要监听Ajax 进程,当Ajax 进程发生改变就调用事件,当 readyState==4
时表示数据接收完毕可以通过某些方法属性返回数据了。
6. 细节问题
(1)对字符进行编码
默认情况下传输数据是什么,url 上的地址拼接就是什么。
例如上代码的输出:
解决的办法就是对用户输入的内容进行编码。
- encodeURI() — 不能对“:/=&”进行编码,能对汉字进行编码
- encodeURIComponent() — 能对“:/=&”进行编码,也能对汉字进行编码
一般情况下,JS编码后发送到服务器,PHP会自动解码,如果没有自动解码,用PHP的函数urldecode来解码。
(2)缓存处理
什么是Ajax缓存原理?
Ajax在发送的数据成功后,会把请求的URL和返回的响应结果保存在浏览器缓存内,当下一次调用Ajax发送相同的请求时,它会直接从缓存中把数据取出来,这是为了提高页面的响应速度和用户体验。当前这两次请求URL完全相同,包括参数。这个时候,浏览器就不会与服务器交互。
两次请求的地址完全一致(包括参数),那么IE就会从缓存中取服务器上一次返回的结果。而不会从新向服务器发送请求。
如何解决IE缓存的问题:
- 在ajax对象.send()前加上
xhr.setRequestHeader("If-Modified-Since","0");
//实测可用 - 在服务器端加
header("Cache-Control:no-cache");
header("Pragma:no-cache");
header("Expires:-1");
加入三个header,目的是让所有的浏览器都不缓存。 - Ajax 的 URL 参数后加上
"?fresh=" + Math.random()
//当然这里参数 fresh 可以任意取了 - 第种方法和第3种类似,在 URL 参数后加上
"?timestamp=" + new Date().getTime()
- 使用POST 请求替代GET 请求。
7. Ajax 中使用GET请求与POST请求的区别
请求写法上的区别:
区别一:请求方式不同。
区别二:GET请求将传递参数写在请求地址中(与地址拼接),POST请求则将参数放入send()中进行发送。
区别三:POST 请求需要设置请求头。
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
区别四:服务器端用$_GET
对GET请求参数进行获取,使用$_POST
对POST请求参数进行获取。
本质区别:
参考博客:https://blog.csdn.net/Errrl/article/details/103467472
对ajax中的get和post的一些说明:
①、用post请求,不会产生缓存。
②、用post请求的时候,能不能也用get,即post和get请求同时使用。答案是能,只不过get请求的参数用$_GET
获取,post请求的参数用$_POST
获取。
③、用$_REQUEST
获取get和post方式提交的参数,如果参数名相同,获取的是谁?获取的是post的内容。
8. Ajax 中的同步与异步说明
同步请求,在同一个时间点上,只能有一个进程;其他进程只能等待。
异步请求,在同一个时间点上,可以同时进行多个进程。
open方法的第三个参数表示同步或者是异步请求。默认值true表示异步请求,false表示同步请求。