前端點滴(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表示同步請求。