pi接口指的是應用程序編程接口(Application Programming Interface),是一些預先定義的函數,或指軟件系統不同組成部分銜接的約定。用來提供應用程序與開發人員基于某軟件或硬件得以訪問的一組例程,而又無需訪問原碼,或理解內部工作機制的細節。
function productClickHandler() {
var xhr=new XMLHttpRequest(); // 創建xhr對象
xhr.onreadystatechange=function() {
if(xhr.readyState==4) {
if((xhr.status >=200 && xhr.status < 300) || xhr.status==304) {
var result=JSON.parse(xhr.responseText); // 將字符串轉化為對象,然后才能獲取到返回字符串中的某一個值
console.log(result.totalCount); // 獲取返回字符串中的某一個值
} else {
alert('Request was unsuccessful: ' + xhr.status);
}
}
}
var url='http://study.163.com/webDev/couresByCategory.htm?' + "pageNo=1&psize=1&type=10"; // 獲取課程列表,帶參數的get請求
xhr.open('get', url, true); // 開啟一個請求,但還沒有向服務器端發起請求,執行后redayState的值變為1
xhr.send(null); // 向服務器端發起請求,執行后redayState的值變為2
// 補充:當服務器端開始返回請求數據的時候,瀏覽器端接收到這個數據,redayState的值變為3。
// 當瀏覽器端結束請求時,redayState的值變為4,status的值變為200(表示請求成功),responseText變為相應的返回值。
}
然后可以通過getElementById("id")等方法獲取到html元素,再使用.innerHTML將獲取到的值插入html。
止ES7規范,數組共包含33個標準的API方法和一個非標準的API方法,使用場景和使用方案紛繁復雜,其中有不少淺坑、深坑、甚至神坑。下面將從Array構造器及ES6新特性開始,逐步幫助你掌握數組。
聲明:以下未特別標明的方法均為ES5已實現的方法。
Array構造器
Array構造器用于創建一個新的數組。通常,我們推薦使用對象字面量創建數組,這是一個好習慣,但是總有對象字面量乏力的時候,比如說,我想創建一個長度為8的空數組。請比較如下兩種方式:
// 使用Array構造器 var a=Array(8); // [undefined × 8] // 使用對象字面量 var b=[]; b.length=8; // [undefined × 8]
Array構造器明顯要簡潔一些,當然你也許會說,對象字面量也不錯啊,那么我保持沉默。
如上,我使用了Array(8)而不是new Array(8),這會有影響嗎?實際上,并沒有影響,這得益于Array構造器內部對this指針的判斷,ELS5_HTML規范是這么說的:
When Array is called as a function rather than as a constructor, it creates and initialises a new Array object. Thus the function call Array(…) is equivalent to the object creation expression new Array(…) with the same arguments.
從規范來看,瀏覽器內部大致做了如下類似的實現:
function Array(){ // 如果this不是Array的實例,那就重新new一個實例 if(!(this instanceof arguments.callee)){ return new arguments.callee(); } }
ES6新增的構造函數方法
鑒于數組的常用性,ES6專門擴展了數組構造器Array ,新增2個方法:Array.of、Array.from。下面展開來聊。
Array.of
Array.of用于將參數依次轉化為數組中的一項,然后返回這個新數組,而不管這個參數是數字還是其它。它基本上與Array構造器功能一致,唯一的區別就在單個數字參數的處理上。如下
Array.of(8.0); // [8] Array(8.0); // [undefined × 8]
參數為多個,或單個參數不是數字時,Array.of 與 Array構造器等同。
Array.of(8.0, 5); // [8, 5] Array(8.0, 5); // [8, 5] Array.of('8'); // ["8"] Array('8'); // ["8"]
因此,若是需要使用數組包裹元素,推薦優先使用Array.of方法。以下版本瀏覽器提供了對Array.of的支持。
ChromeFirefoxEdgeSafari45+25+??9.0+
即使其他版本瀏覽器不支持也不必擔心,由于Array.of與Array構造器的這種高度相似性,實現一個polyfill十分簡單。如下:
if (!Array.of){ Array.of=function(){ return Array.prototype.slice.call(arguments); }; }
Array.from
語法:Array.from(arrayLike[, processingFn[, thisArg]])
Array.from的設計初衷是快速便捷的基于其他對象創建新數組,準確來說就是從一個類似數組的可迭代對象創建一個新的數組實例,說人話就是,只要一個對象有迭代器,Array.from就能把它變成一個數組(當然,是返回新的數組,不改變原對象)。
從語法上看,Array.from擁有3個形參
var obj={0: 'a', 1: 'b', 2:'c', length: 3}; Array.from(obj, function(value, index){ console.log(value, index, this, arguments.length); return value.repeat(3); //必須指定返回值,否則返回undefined }, obj);
可以看到加工函數的this作用域被obj對象取代,也可以看到加工函數默認擁有兩個形參,分別為迭代器當前元素的值和其索引。
注意,一旦使用加工函數,必須明確指定返回值,否則將隱式返回undefined,最終生成的數組也會變成一個只包含若干個undefined元素的空數組。
實際上,如果不需要指定this,加工函數完全可以是一個箭頭函數。上述代碼可以簡化如下:
Array.from(obj, (value)=> value.repeat(3));
除了上述obj對象以外,擁有迭代器的對象還包括這些:String,Set,Map,arguments 等,Array.from統統可以處理。如下所示:
// String Array.from('abc'); // ["a", "b", "c"] // Set Array.from(new Set(['abc', 'def'])); // ["abc", "def"] // Map Array.from(new Map([[1, 'abc'], [2, 'def']])); // [[1 , 'abc'], [2, 'def']] // 天生的類數組對象arguments function fn(){ return Array.from(arguments); } fn(1, 2, 3); // [1, 2, 3]
到這你可能以為Array.from就講完了,實際上還有一個重要的擴展場景必須提下。比如說生成一個從0到指定數字的新數組,Array.from就可以輕易的做到。
Array.from({length: 10}, (v, i)=> i); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
后面我們將會看到,利用數組的keys方法實現上述功能,可能還要簡單一些。目前,以下版本瀏覽器提供了對Array.from的支持。
ChromeFirefoxEdgeOperaSafari45+32+????9.0+
Array.isArray
顧名思義,Array.isArray用來判斷一個變量是否數組類型。JS的弱類型機制導致判斷變量類型是初級前端開發者面試時的必考題,一般我都會將其作為考察候選人第一題,然后基于此展開。在ES5提供該方法之前,我們至少有如下5種方式去判斷一個值是否數組
var a=[]; // 1.基于instanceof a instanceof Array; // 2.基于constructor a.constructor===Array; // 3.基于Object.prototype.isPrototypeOf Array.prototype.isPrototypeOf(a); // 4.基于getPrototypeOf Object.getPrototypeOf(a)===Array.prototype; // 5.基于Object.prototype.toString Object.prototype.toString.apply(a)==='[object Array]';
以上,除了Object.prototype.toString外,其它方法都不能正確判斷變量的類型。要知道,代碼的運行環境十分復雜,一個變量可能使用渾身解數去迷惑它的創造者。且看:
var a={ __proto__: Array.prototype }; // 分別在控制臺試運行以下代碼 // 1.基于instanceof a instanceof Array; // true // 2.基于constructor a.constructor===Array; // true // 3.基于Object.prototype.isPrototypeOf Array.prototype.isPrototypeOf(a); // true // 4.基于getPrototypeOf Object.getPrototypeOf(a)===Array.prototype; // true
以上,4種方法將全部返回true,為什么呢?我們只是手動指定了某個對象的__proto__屬性為Array.prototype,便導致了該對象繼承了Array對象,這種毫不負責任的繼承方式,使得基于繼承的判斷方案瞬間土崩瓦解。
不僅如此,我們還知道,Array是堆數據,變量指向的只是它的引用地址,因此每個頁面的Array對象引用的地址都是不一樣的。iframe中聲明的數組,它的構造函數是iframe中的Array對象。如果在iframe聲明了一個數組x,將其賦值給父頁面的變量y,那么在父頁面使用y instanceof Array ,結果一定是false的。而最后一種返回的是字符串,不會存在引用問題。實際上,多頁面或系統之間的交互只有字符串能夠暢行無阻。
相反,使用Array.isArray則非常簡單,如下:
Array.isArray([]); // true Array.isArray({0: 'a', length: 1}); // false
目前,以下版本瀏覽器提供了對Array.isArray的支持。
ChromeFirefoxIEOperaSafari5+4+9+10.5+5+
實際上,通過Object.prototype.toString去判斷一個值的類型,也是各大主流庫的標準。因此Array.isArray的polyfill通常長這樣:
if (!Array.isArray){ Array.isArray=function(arg){ return Object.prototype.toString.call(arg)==='[object Array]'; }; }
原型
繼承的常識告訴我們,js中所有的數組方法均來自于Array.prototype,和其他構造函數一樣,你可以通過擴展 Array 的 prototype 屬性上的方法來給所有數組實例增加方法。
值得一說的是,Array.prototype本身就是一個數組。
Array.isArray(Array.prototype); // true console.log(Array.prototype.length);// 0 console.log([].__proto__.length);// 0 console.log([].__proto__);// [Symbol(Symbol.unscopables): Object]
方法
數組原型提供的方法非常之多,主要分為三種,一種是會改變自身值的,一種是不會改變自身值的,另外一種是遍歷方法。
由于 Array.prototype 的某些屬性被設置為[[DontEnum]],因此不能用一般的方法進行遍歷,我們可以通過如下方式獲取 Array.prototype 的所有方法:
// Object.getOwnPropertyNames([].__proto__) Object.getOwnPropertyNames(Array.prototype); // ["length", "constructor", "toString", "toLocaleString", "join", "pop", "push", "reverse", "shift", "unshift", "slice", "splice", "sort", "filter", "forEach", "some", "every", "map", "indexOf", "lastIndexOf", "reduce", "reduceRight", "copyWithin", "find", "findIndex", "fill", "includes", "entries", "keys", "concat"]
改變自身值的方法(9個)
基于ES6,改變自身值的方法一共有9個,分別為pop、push、reverse、shift、sort、splice、unshift,以及兩個ES6新增的方法copyWithin 和 fill。
對于能改變自身值的數組方法,日常開發中需要特別注意,盡量避免在循環遍歷中去改變原數組的項。接下來,我們一起來深入地了解這些方法。
pop
pop() 方法刪除一個數組中的最后的一個元素,并且返回這個元素。如果是棧的話,這個過程就是棧頂彈出。
var array=["cat", "dog", "cow", "chicken", "mouse"]; var item=array.pop(); console.log(array); // ["cat", "dog", "cow", "chicken"] console.log(item); // mouse
由于設計上的巧妙,pop方法可以應用在類數組對象上,即 鴨式辨型. 如下:
var o={0:"cat", 1:"dog", 2:"cow", 3:"chicken", 4:"mouse", length:5} var item=Array.prototype.pop.call(o); console.log(o); // Object {0: "cat", 1: "dog", 2: "cow", 3: "chicken", length: 4} console.log(item); // mouse
但如果類數組對象不具有length屬性,那么該對象將被創建length屬性,length值為0。如下:
var o={0:"cat", 1:"dog", 2:"cow", 3:"chicken", 4:"mouse"} var item=Array.prototype.pop.call(o); console.log(o); // Object {0: "cat", 1: "dog", 2: "cow", 3: "chicken", 4: "mouse", length: 0} console.log(item); // undefined var o={0:"a", 1:"b", 2:"c", length:30}; var item=Array.prototype.pop.call(o); console.log(o); // Object {0:"a", 1:"b", 2:"c", length:29} console.log(item); // undefined
push
push()方法添加一個或者多個元素到數組末尾,并且返回數組新的長度。如果是棧的話,這個過程就是棧頂壓入。
語法:arr.push(element1, …, elementN)
var array=["football", "basketball", "volleyball", "Table tennis", "badminton"]; var i=array.push("golfball"); console.log(array); // ["football", "basketball", "volleyball", "Table tennis", "badminton", "golfball"] console.log(i); // 6
同pop方法一樣,push方法也可以應用到類數組對象上,如果length不能被轉成一個數值或者不存在length屬性時,則插入的元素索引為0,且length屬性不存在時,將會創建它。
var o={0:"football", 1:"basketball"}; var i=Array.prototype.push.call(o, "golfball"); console.log(o); // Object {0: "golfball", 1: "basketball", length: 1} console.log(i); // 1
實際上,push方法是根據length屬性來決定從哪里開始插入給定的值
var o={0:"football", 1:"basketball",length:1}; var i=Array.prototype.push.call(o,"golfball"); console.log(o); // Object {0: "football", 1: "golfball", length: 2} console.log(i); // 2
利用push根據length屬性插入元素這個特點,可以實現數組的合并,如下:
var array=["football", "basketball"]; var array2=["volleyball", "golfball"]; var i=Array.prototype.push.apply(array,array2); console.log(array); // ["football", "basketball", "volleyball", "golfball"] console.log(i); // 4
reverse
reverse()方法顛倒數組中元素的位置,第一個會成為最后一個,最后一個會成為第一個,該方法返回對數組的引用。
語法:arr.reverse()
var array=[1,2,3,4,5]; var array2=array.reverse(); console.log(array); // [5,4,3,2,1] console.log(array2===array); // true
同上,reverse 也是鴨式辨型的受益者,顛倒元素的范圍受length屬性制約。如下:
var o={0:"a", 1:"b", 2:"c", length:2}; var o2=Array.prototype.reverse.call(o); console.log(o); // Object {0: "b", 1: "a", 2: "c", length: 2} console.log(o===o2); // true
如果 length 屬性小于2 或者 length 屬性不為數值,那么原類數組對象將沒有變化。即使 length 屬性不存在,該對象也不會去創建 length 屬性。特別的是,當 length 屬性較大時,類數組對象的『索引』會盡可能的向 length 看齊。如下:
var o={0:"a", 1:"b", 2:"c",length:100}; var o2=Array.prototype.reverse.call(o); console.log(o); // Object {97: "c", 98: "b", 99: "a", length: 100} console.log(o===o2); // true
shift
shift()方法刪除數組的第一個元素,并返回這個元素。如果是棧的話,這個過程就是棧底彈出。
語法:arr.shift()
var array=[1,2,3,4,5]; var item=array.shift(); console.log(array); // [2,3,4,5] console.log(item); // 1
同樣受益于鴨式辨型,對于類數組對象,shift仍然能夠處理。如下:
var o={0:"a", 1:"b", 2:"c", length:3}; var item=Array.prototype.shift.call(o); console.log(o); // Object {0: "b", 1: "c", length: 2} console.log(item); // a
如果類數組對象length屬性不存在,將添加length屬性,并初始化為0。如下:
var o={0:"a", 1:"b", 2:"c"}; var item=Array.prototype.shift.call(o); console.log(o); // Object {0: "a", 1: "b", 2:"c" length: 0} console.log(item); // undefined
sort
sort()方法對數組元素進行排序,并返回這個數組。sort方法比較復雜,這里我將多花些篇幅來講這塊。
語法:arr.sort([comparefn])
comparefn是可選的,如果省略,數組元素將按照各自轉換為字符串的Unicode(萬國碼)位點順序排序,例如”Boy”將排到”apple”之前。當對數字排序的時候,25將會排到8之前,因為轉換為字符串后,”25”將比”8”靠前。例如:
var array=["apple","Boy","Cat","dog"]; var array2=array.sort(); console.log(array); // ["Boy", "Cat", "apple", "dog"] console.log(array2==array); // true array=[10, 1, 3, 20]; var array3=array.sort(); console.log(array3); // [1, 10, 20, 3]
如果指明了comparefn,數組將按照調用該函數的返回值來排序。若 a 和 b 是兩個將要比較的元素:
如果數組元素為數字,則排序函數comparefn格式如下所示:
function compare(a, b){ return a-b; }
如果數組元素為非ASCII字符的字符串(如包含類似 e、é、è、a、? 或中文字符等非英文字符的字符串),則需要使用String.localeCompare。下面這個函數將排到正確的順序。
var array=['互','聯','網','改','變','世','界']; var array2=array.sort(); var array=['互','聯','網','改','變','世','界']; // 重新賦值,避免干擾array2 var array3=array.sort(function (a, b) { return a.localeCompare(b); }); console.log(array2); // ["世", "互", "變", "改", "界", "網", "聯"] console.log(array3); // ["變", "改", "互", "界", "聯", "世", "網"]
如上,『互聯網改變世界』這個數組,sort函數默認按照數組元素unicode字符串形式進行排序,然而實際上,我們期望的是按照拼音先后順序進行排序,顯然String.localeCompare 幫助我們達到了這個目的。
為什么上面測試中需要重新給array賦值呢,這是因為sort每次排序時改變的是數組本身,并且返回數組引用。如果不這么做,經過連續兩次排序后,array2 和 array3 將指向同一個數組,最終影響我們測試。array重新賦值后就斷開了對原數組的引用。
同上,sort一樣受益于鴨式辨型,比如:
var o={0:'互',1:'聯',2:'網',3:'改',4:'變',5:'世',6:'界',length:7}; Array.prototype.sort.call(o,function(a, b){ return a.localeCompare(b); }); console.log(o); // Object {0: "變", 1: "改", 2: "互", 3: "界", 4: "聯", 5: "世", 6: "網", length: 7}, 可見同上述排序結果一致
注意:使用sort的鴨式辨型特性時,若類數組對象不具有length屬性,它并不會進行排序,也不會為其添加length屬性。
var o={0:'互',1:'聯',2:'網',3:'改',4:'變',5:'世',6:'界'}; Array.prototype.sort.call(o,function(a, b){ return a.localeCompare(b); }); console.log(o); // Object {0: "互", 1: "聯", 2: "網", 3: "改", 4: "變", 5: "世", 6: "界"}, 可見并未添加length屬性
使用映射改善排序
comparefn 如果需要對數組元素多次轉換以實現排序,那么使用map輔助排序將是個不錯的選擇?;舅枷刖褪菍到M中的每個元素實際比較的值取出來,排序后再將數組恢復。
// 需要被排序的數組 var array=['dog', 'Cat', 'Boy', 'apple']; // 對需要排序的數字和位置的臨時存儲 var mapped=array.map(function(el, i) { return { index: i, value: el.toLowerCase() }; }) // 按照多個值排序數組 mapped.sort(function(a, b) { return +(a.value > b.value) || +(a.value===b.value) - 1; }); // 根據索引得到排序的結果 var result=mapped.map(function(el){ return array[el.index]; }); console.log(result); // ["apple", "Boy", "Cat", "dog"]
splice
splice()方法用新元素替換舊元素的方式來修改數組。它是一個常用的方法,復雜的數組操作場景通常都會有它的身影,特別是需要維持原數組引用時,就地刪除或者新增元素,splice是最適合的。
語法:arr.splice(start,deleteCount[, item1[, item2[, …]]])
var array=["apple","boy"]; var splices=array.splice(1,1); console.log(array); // ["apple"] console.log(splices); // ["boy"] ,可見是從數組下標為1的元素開始刪除,并且刪除一個元素,由于itemN缺省,故此時該方法只刪除元素 array=["apple","boy"]; splices=array.splice(2,1,"cat"); console.log(array); // ["apple", "boy", "cat"] console.log(splices); // [], 可見由于start超過數組長度,此時從數組末尾開始添加元素,并且原數組不會發生刪除行為 array=["apple","boy"]; splices=array.splice(-2,1,"cat"); console.log(array); // ["cat", "boy"] console.log(splices); // ["apple"], 可見當start為負值時,是從數組末尾開始的第-start位開始刪除,刪除一個元素,并且從此處插入了一個元素 array=["apple","boy"]; splices=array.splice(-3,1,"cat"); console.log(array); // ["cat", "boy"] console.log(splices); // ["apple"], 可見即使-start超出數組長度,數組默認從首位開始刪除 array=["apple","boy"]; splices=array.splice(0,3,"cat"); console.log(array); // ["cat"] console.log(splices); // ["apple", "boy"], 可見當deleteCount大于數組start之后的元素總和時,start及之后的元素都將被刪除
splice一樣受益于鴨式辨型, 比如:
var o={0:"apple",1:"boy",length:2}; var splices=Array.prototype.splice.call(o,1,1); console.log(o); // Object {0: "apple", length: 1}, 可見對象o刪除了一個屬性,并且length-1 console.log(splices); // ["boy"]
注意:如果類數組對象沒有length屬性,splice將為該類數組對象添加length屬性,并初始化為0。
如果需要刪除數組中一個已存在的元素,可參考如下:
var array=['a','b','c']; array.splice(array.indexOf('b'),1);
unshift
unshift() 方法用于在數組開始處插入一些元素(就像是棧底插入),并返回數組新的長度。
語法:arr.unshift(element1, …, elementN)
var array=["red", "green", "blue"]; var length=array.unshift("yellow"); console.log(array); // ["yellow", "red", "green", "blue"] console.log(length); // 4
如果給unshift方法傳入一個數組呢?
var array=["red", "green", "blue"]; var length=array.unshift(["yellow"]); console.log(array); // [["yellow"], "red", "green", "blue"] console.log(length); // 4, 可見數組也能成功插入
同上,unshift也受益于鴨式辨型
var o={0:"red", 1:"green", 2:"blue",length:3}; var length=Array.prototype.unshift.call(o,"gray"); console.log(o); // Object {0: "gray", 1: "red", 2: "green", 3: "blue", length: 4} console.log(length); // 4
注意:如果類數組對象不指定length屬性,則返回結果是這樣的 Object {0: "gray", 1: "green", 2: "blue", length: 1},shift會認為數組長度為0,此時將從對象下標為0的位置開始插入,相應位置屬性將被替換,此時初始化類數組對象的length屬性為插入元素個數。
copyWithin(ES6)
copyWithin() 方法基于ECMAScript 2015(ES6)規范,用于數組內元素之間的替換,即替換元素和被替換元素均是數組內的元素。
語法:arr.copyWithin(target, start[, end=this.length])
var array=[1,2,3,4,5]; var array2=array.copyWithin(0,3); console.log(array===array2,array2); // true [4, 5, 3, 4, 5] var array=[1,2,3,4,5]; console.log(array.copyWithin(0,3,4)); // [4, 2, 3, 4, 5] var array=[1,2,3,4,5]; console.log(array.copyWithin(0,-2,-1)); // [4, 2, 3, 4, 5]
copyWithin一樣受益于鴨式辨型
var o={0:1, 1:2, 2:3, 3:4, 4:5,length:5} var o2=Array.prototype.copyWithin.call(o,0,3); console.log(o===o2,o2); // true Object { 0=4, 1=5, 2=3, 更多...}
如果未指定length,則不進行任何操作。上面的例子去掉length: 5,則返回的o===o2,未進行改變
fill(ES6)
fill() 方法基于ECMAScript 2015(ES6)規范,它同樣用于數組元素替換,但與copyWithin略有不同,它主要用于將數組指定區間內的元素替換為某個值。
語法:arr.fill(value, start[, end=this.length])
var array=[1,2,3,4,5]; var array2=array.fill(10,0,3); console.log(array===array2,array2); // true [10, 10, 10, 4, 5], 可見數組區間[0,3]的元素全部替換為10 // 其他的舉例請參考copyWithin
fill 一樣受益于鴨式辨型
var o={0:1, 1:2, 2:3, 3:4, 4:5,length:5} var o2=Array.prototype.fill.call(o,10,0,2); console.log(o===o2,o2); true Object { 0=10, 1=10, 2=3, 更多...}
如果未指定length,則不進行任何操作。上面的例子去掉length: 5,則返回的o===o2,未進行改變
不會改變自身的方法(9個)
基于ES7,不會改變自身的方法一共有9個,分別為concat、join、slice、toString、toLocateString、indexOf、lastIndexOf、未標準的toSource以及ES7新增的方法includes。
concat
concat() 方法將傳入的數組或者元素與原數組合并,組成一個新的數組并返回。
語法:arr.concat(value1, value2, …, valueN)
var array=[1, 2, 3]; var array2=array.concat(4,[5,6],[7,8,9]); console.log(array2); // [1, 2, 3, 4, 5, 6, 7, 8, 9] console.log(array); // [1, 2, 3], 可見原數組并未被修改
若concat方法中不傳入參數,那么將基于原數組淺復制生成一個一模一樣的新數組(指向新的地址空間)。
var array=[{a: 1}]; var array3=array.concat(); console.log(array3); // [{a: 1}] console.log(array3===array); // false console.log(array[0]===array3[0]); // true,新舊數組第一個元素依舊共用一個同一個對象的引用 array[0].a='sdd'; console.log(array3); // [{a: 'sdd}] 淺復制 var arr1=[1, 2, 3]; var arr2=arr1.concat(); console.log(arr2); // [1, 2, 3]; arr1[0]='122'; console.log(arr2); // [1, 2, 3]; 淺復制
concat 一樣受益于鴨式辨型,但其效果可能達不到我們的期望
var o={0:"a", 1:"b", 2:"c",length:3}; var o2=Array.prototype.concat.call(o,'d',{3:'e',4:'f',length:2},['g','h','i']); console.log(o2); // [{0:"a", 1:"b", 2:"c", length:3}, 'd', {3:'e', 4:'f', length:2}, 'g', 'h', 'i'] var o3=Array.prototype.concat.call(o); console.log(o3); // [{0:"a", 1:"b", 2:"c",length:3}]
可見,類數組對象合并后返回的是依然是數組,并不是我們期望的對象
join
join() 方法將數組中的所有元素連接成一個字符串。
語法:arr.join([separator=‘,’]) separator可選,缺省默認為逗號。
var array=['We', 'are', 'Chinese']; console.log(array.join()); // "We,are,Chinese" console.log(array.join('+')); // "We+are+Chinese" console.log(array.join('')); // "WeareChinese"
join 一樣受益于鴨式辨型
var o={0:"We", 1:"are", 2:"Chinese", length:3}; console.log(Array.prototype.join.call(o,'+')); // "We+are+Chinese" console.log(Array.prototype.join.call('abc')); // "a,b,c"
slice
slice() 方法將數組中一部分元素淺復制存入新的數組對象,并且返回這個數組對象。
語法:arr.slice([start[, end]])
參數 start 指定復制開始位置的索引,end如果有值則表示復制結束位置的索引(不包括此位置)。
如果 start 的值為負數,假如數組長度為 length,則表示從 length+start 的位置開始復制,此時參數 end 如果有值,只能是比 start 大的負數,否則將返回空數組。
slice方法參數為空時,同concat方法一樣,都是淺復制生成一個新數組。
var array=["one", "two", "three","four", "five"]; console.log(array.slice()); // ["one", "two", "three","four", "five"] console.log(array.slice(2,3)); // ["three"]
淺復制 是指當對象的被復制時,只是復制了對象的引用,指向的依然是同一個對象。下面來說明slice為什么是淺復制
var array=[{color:"yellow"}, 2, 3]; var array2=array.slice(0,1); console.log(array2); // [{color:"yellow"}] array[0]["color"]="blue"; console.log(array2); // [{color:"bule"}]
由于slice是淺復制,復制到的對象只是一個引用,改變原數組array的值,array2也隨之改變。
同時,稍微利用下 slice 方法第一個參數為負數時的特性,我們可以非常方便的拿到數組的最后一項元素,如下:
console.log([1,2,3].slice(-1));//[3]
slice 一樣受益于鴨式辨型
var o={0:{"color":"yellow"}, 1:2, 2:3, length:3}; var o2=Array.prototype.slice.call(o,0,1); console.log(o2); // [{color:"yellow"}] ,毫無違和感...
toString
toString() 方法返回數組的字符串形式,該字符串由數組中的每個元素的 toString() 返回值經調用 join() 方法連接(由逗號隔開)組成。
語法: arr.toString()
var array=['Jan', 'Feb', 'Mar', 'Apr']; var str=array.toString(); console.log(str); // Jan,Feb,Mar,Apr
當數組直接和字符串作連接操作時,將會自動調用其toString() 方法。
var str=['Jan', 'Feb', 'Mar', 'Apr'] + ',May'; console.log(str); // "Jan,Feb,Mar,Apr,May" // 下面我們來試試鴨式辨型 var o={0:'Jan', 1:'Feb', 2:'Mar', length:3}; var o2=Array.prototype.toString.call(o); console.log(o2); // [object Object] console.log(o.toString()==o2); // true
可見,Array.prototype.toString()方法處理類數組對象時,跟類數組對象直接調用Object.prototype.toString()方法結果完全一致
根據ES5語義,toString() 方法是通用的,可被用于任何對象。如果對象有一個join() 方法,將會被調用,其返回值將被返回,沒有則調用Object.prototype.toString(),為此,我們給o對象添加一個join方法。如下:
var o={ 0:'Jan', 1:'Feb', 2:'Mar', length:3, join:function(){ return Array.prototype.join.call(this); } }; console.log(Array.prototype.toString.call(o)); // "Jan,Feb,Mar"
toLocaleString
toLocaleString() 類似toString()的變型,該字符串由數組中的每個元素的 toLocaleString() 返回值經調用 join() 方法連接(由逗號隔開)組成。
語法:arr.toLocaleString()
數組中的元素將調用各自的 toLocaleString 方法:
var array=[{name:'zz'}, 123, "abc", new Date()]; var str=array.toLocaleString(); console.log(str); // [object Object],123,abc,2016/1/5 下午1:06:23
其鴨式辨型的寫法也同toString 保持一致,如下:
var o={ 0:123, 1:'abc', 2:new Date(), length:3, join:function(){ return Array.prototype.join.call(this); } }; console.log(Array.prototype.toLocaleString.call(o)); // 123,abc,2016/1/5 下午1:16:50
indexOf
indexOf() 方法用于查找元素在數組中第一次出現時的索引,如果沒有,則返回-1。
語法:arr.indexOf(element, fromIndex=0)
element 為需要查找的元素。
fromIndex 為開始查找的位置,缺省默認為0。如果超出數組長度,則返回-1。如果為負值,假設數組長度為length,則從數組的第 length + fromIndex項開始往數組末尾查找,如果length + fromIndex<0 則整個數組都會被查找。
indexOf使用嚴格相等(即使用===去匹配數組中的元素)
var array=['abc', 'def', 'ghi','123']; console.log(array.indexOf('def')); // 1 console.log(array.indexOf('def',-1)); // -1 此時表示從最后一個元素往后查找,因此查找失敗返回-1 console.log(array.indexOf('def',-4)); // 1 由于4大于數組長度,此時將查找整個數組,因此返回1 console.log(array.indexOf(123)); // -1, 由于是嚴格匹配,因此并不會匹配到字符串'123'
得益于鴨式辨型,indexOf 可以處理類數組對象
var o={0:'abc', 1:'def', 2:'ghi', length:3}; console.log(Array.prototype.indexOf.call(o,'ghi',-4));//2
然而該方法并不支持IE9以下版本,如需更好的支持低版本IE瀏覽器(IE6~8)
lastIndexOf
lastIndexOf() 方法用于查找元素在數組中最后一次出現時的索引,如果沒有,則返回-1。并且它是indexOf的逆向查找,即從數組最后一個往前查找。
語法:arr.lastIndexOf(element, fromIndex=length-1)
element 為需要查找的元素。
fromIndex 為開始查找的位置,缺省默認為數組長度length-1。如果超出數組長度,由于是逆向查找,則查找整個數組。如果為負值,則從數組的第 length + fromIndex項開始往數組開頭查找,如果length + fromIndex<0 則數組不會被查找。
同 indexOf 一樣,lastIndexOf 也是嚴格匹配數組元素。
舉例請參考 indexOf ,不再詳述,兼容低版本IE瀏覽器(IE6~8)
includes(ES7)
includes() 方法基于ECMAScript 2016(ES7)規范,它用來判斷當前數組是否包含某個指定的值,如果是,則返回 true,否則返回 false。
語法:arr.includes(element, fromIndex=0)
element 為需要查找的元素。
fromIndex 表示從該索引位置開始查找 element,缺省為0,它是正向查找,即從索引處往數組末尾查找。
var array=[-0, 1, 2]; console.log(array.includes(+0)); // true console.log(array.includes(1)); // true console.log(array.includes(2,-4)); // true
以上,includes似乎忽略了 -0 與 +0 的區別,這不是問題,因為JavaScript一直以來都是不區分 -0 和 +0 的。
你可能會問,既然有了indexOf方法,為什么又造一個includes方法,arr.indexOf(x)>-1不就等于arr.includes(x)?看起來是的,幾乎所有的時候它們都等同,唯一的區別就是includes能夠發現NaN,而indexOf不能。
var array=[NaN]; console.log(array.includes(NaN)); // true console.log(arra.indexOf(NaN)>-1); // false
該方法同樣受益于鴨式辨型
var o={0:'a', 1:'b', 2:'c', length:3}; var bool=Array.prototype.includes.call(o, 'a'); console.log(bool); // true
該方法只有在Chrome 47、opera 34、Safari 9版本及其更高版本中才被實現
toSource(非標準)
toSource() 方法是非標準的,該方法返回數組的源代碼,目前只有 Firefox 實現了它。
語法:arr.toSource()
var array=['a', 'b', 'c']; console.log(array.toSource()); // ["a", "b", "c"] // 測試鴨式辨型 var o={0:'a', 1:'b', 2:'c', length:3}; console.log(Array.prototype.toSource.call(o)); // ["a","b","c"]
基于ES6,不會改變自身的方法一共有12個,分別為forEach、every、some、filter、map、reduce、reduceRight 以及ES6新增的方法entries、find、findIndex、keys、values。
forEach
forEach() 方法指定數組的每項元素都執行一次傳入的函數,返回值為undefined。
語法:arr.forEach(fn, thisArg)
fn 表示在數組每一項上執行的函數,接受三個參數:
thisArg 可選,用來當做fn函數內的this對象。
forEach 將為數組中每一項執行一次 fn 函數,那些已刪除,新增或者從未賦值的項將被跳過(但不包括值為 undefined 的項)。
var array=[1, 3, 5]; var obj={name:'cc'}; var sReturn=array.forEach(function(value, index, array){ array[index]=value * value; console.log(this.name); // cc被打印了三次 },obj); console.log(array); // [1, 9, 25], 可見原數組改變了 console.log(sReturn); // undefined, 可見返回值為undefined
得益于鴨式辨型,雖然forEach不能直接遍歷對象,但它可以通過call方式遍歷類數組對象
var o={0:1, 1:3, 2:5, length:3}; Array.prototype.forEach.call(o,function(value, index, obj){ console.log(value,index,obj); obj[index]=value * value; },o); // 1 0 Object {0: 1, 1: 3, 2: 5, length: 3} // 3 1 Object {0: 1, 1: 3, 2: 5, length: 3} // 5 2 Object {0: 1, 1: 9, 2: 5, length: 3} console.log(o); // Object {0: 1, 1: 9, 2: 25, length: 3}
參考前面的文章 詳解JS遍歷 中 forEach的講解,我們知道,forEach無法直接退出循環,只能使用return 來達到for循環中continue的效果,并且forEach不能在低版本IE(6~8)中使用
every
every() 方法使用傳入的函數測試所有元素,只要其中有一個函數返回值為 false,那么該方法的結果為 false;如果全部返回 true,那么該方法的結果才為 true。
以下是鴨式辨型的寫法:
var o={0:10, 1:8, 2:25, length:3}; var bool=Array.prototype.every.call(o,function(value, index, obj){ return value >=8; },o); console.log(bool); // true
every 一樣不能在低版本IE(6~8)中使用
some
some() 方法剛好同 every() 方法相反,some 測試數組元素時,只要有一個函數返回值為 true,則該方法返回 true,若全部返回 false,則該方法返回 false。some 方法存在如下規律:
你注意到沒有,some方法與includes方法有著異曲同工之妙,他們都是探測數組中是否擁有滿足條件的元素,一旦找到,便返回true。多觀察和總結這種微妙的關聯關系,能夠幫助我們深入理解它們的原理。
some 的鴨式辨型寫法可以參照every,同樣它也不能在低版本IE(6~8)中使用
filter
filter() 方法使用傳入的函數測試所有元素,并返回所有通過測試的元素組成的新數組。它就好比一個過濾器,篩掉不符合條件的元素。
語法:arr.filter(fn, thisArg)
var array=[18, 9, 10, 35, 80]; var array2=array.filter(function(value, index, array){ return value > 20; }); console.log(array2); // [35, 80]
filter一樣支持鴨式辨型,具體請參考every方法鴨式辨型寫法。
map
map() 方法遍歷數組,使用傳入函數處理每個元素,并返回函數的返回值組成的新數組。
語法:arr.map(fn, thisArg)
參數介紹同 forEach 方法的參數介紹。
map 一樣支持鴨式辨型, 具體請參考every方法鴨式辨型寫法。
reduce
reduce() 方法接收一個方法作為累加器,數組中的每個值(從左至右) 開始合并,最終為一個值。
語法:arr.reduce(fn, initialValue)
fn 表示在數組每一項上執行的函數,接受四個參數:
initialValue 指定第一次調用 fn 的第一個參數。 當 fn 第一次執行時:
var array=[1, 2, 3, 4]; var s=array.reduce(function(previousValue, value, index, array){ return previousValue * value; },1); console.log(s); // 24 // ES6寫法更加簡潔 array.reduce((p, v)=> p * v); // 24
reduce 一樣支持鴨式辨型,具體請參考every方法鴨式辨型寫法。profill寫法:
When the reduce method is called with one or two arguments, the following steps are taken: 1、Let O be the result of calling ToObject passing the this value as the argument. 2、Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length". 3、Let len be ToUint32(lenValue ). 4、If IsCallable(callbackfn) is false, throw a TypeError exception. 5、If len is 0 and initialValue is not present, throw a TypeError exception. 6、Let k be 0. 7、If initialValue is present, then 7.1、Set accumulator to initialValue. 8、Else, initialValue is not present 8.1、Let kPresent be false. 8.2、Repeat, while kPresent is false and k < len 8.2.1、Let Pk be ToString(k). 8.2.2、Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk. 8.2.3、If kPresent is true, then 8.2.3.1、Let accumulator be the result of calling the [[Get]] internal method of O with argument Pk. 8.2.4、Increase k by 1. 8.3、If kPresent is false, throw a TypeError exception. 9、Repeat, while k < len 9.1、Let Pk be ToString(k). 9.2、Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk. 9.3、If kPresent is true, then 9.3.1、Let kValue be the result of calling the [[Get]] internal method of O with argument Pk. 9.3.2、Let accumulator be the result of calling the [[Call]] internal method of callbackfn with undefined as the this value and argument list containing accumulator, kValue, k, and O. 9.4、Increase k by 1. 10、Return accumulator. The length property of the reduce method is 1.
reduceRight
reduceRight() 方法接收一個方法作為累加器,數組中的每個值(從右至左)開始合并,最終為一個值。除了與reduce執行方向相反外,其他完全與其一致,請參考上述 reduce 方法介紹。
entries(ES6)
entries() 方法基于ECMAScript 2015(ES6)規范,返回一個數組迭代器對象,該對象包含數組中每個索引的鍵值對。
語法:arr.entries()
var array=["a", "b", "c"]; var iterator=array.entries(); console.log(iterator.next().value); // [0, "a"] console.log(iterator.next().value); // [1, "b"] console.log(iterator.next().value); // [2, "c"] console.log(iterator.next().value); // undefined, 迭代器處于數組末尾時, 再迭代就會返回undefined
很明顯,entries 也受益于鴨式辨型
var o={0:"a", 1:"b", 2:"c", length:3}; var iterator=Array.prototype.entries.call(o); console.log(iterator.next().value); // [0, "a"] console.log(iterator.next().value); // [1, "b"] console.log(iterator.next().value); // [2, "c"]
由于該方法基于ES6,因此目前并不支持所有瀏覽器
find&findIndex(ES6)
find() 方法基于ECMAScript 2015(ES6)規范,返回數組中第一個滿足條件的元素(如果有的話), 如果沒有,則返回undefined。
findIndex() 方法也基于ECMAScript 2015(ES6)規范,它返回數組中第一個滿足條件的元素的索引(如果有的話)否則返回-1。
語法:arr.find(fn, thisArg),arr.findIndex(fn, thisArg)
我們發現它們的語法與forEach等十分相似,其實不光語法,find(或findIndex)在參數及其使用注意事項上,均與forEach一致。因此此處將略去 find(或findIndex)的參數介紹。下面我們來看個例子
var array=[1, 3, 5, 7, 8, 9, 10]; function f(value, index, array){ return value%2==0; // 返回偶數 } function f2(value, index, array){ return value > 20; // 返回大于20的數 } console.log(array.find(f)); // 8 console.log(array.find(f2)); // undefined console.log(array.findIndex(f)); // 4 console.log(array.findIndex(f2)); // -1
其鴨式辨型寫法也與forEach方法一致
keys(ES6)
keys() 方法基于ECMAScript 2015(ES6)規范,返回一個數組索引的迭代器。(瀏覽器實際實現可能會有調整)
語法:arr.keys()
var array=["abc", "xyz"]; var iterator=array.keys(); console.log(iterator.next()); // Object {value: 0, done: false} console.log(iterator.next()); // Object {value: 1, done: false} console.log(iterator.next()); // Object {value: undefined, done: false}
索引迭代器會包含那些沒有對應元素的索引
var array=["abc", , "xyz"]; var sparseKeys=Object.keys(array); var denseKeys=[...array.keys()]; // 類似Array.from(array.keys()) console.log(sparseKeys); // ["0", "2"] console.log(denseKeys); // [0, 1, 2]
其鴨式辨型寫法請參考上述 entries 方法
前面我們用Array.from生成一個從0到指定數字的新數組,利用keys也很容易實現。
[...Array(10).keys()]; // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [...new Array(10).keys()]; // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] Array.from({length: 10}, (v, i)=> i); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
keys基于ES6,并未完全支持
values(ES6)
values() 方法基于ECMAScript 2015(ES6)規范,返回一個數組迭代器對象,該對象包含數組中每個索引的值。其用法基本與上述 entries 方法一致。
語法:arr.values()
var array=["abc", "xyz"]; var iterator=array.values(); console.log(iterator.next().value);//abc console.log(iterator.next().value);//xyz
Symbol.iterator(ES6)
該方法基于ECMAScript 2015(ES6)規范,同 values 方法功能相同。
語法:arrSymbol.iterator
var array=["abc", "xyz"]; var iterator=array[Symbol.iterator](); console.log(iterator.next().value); // abc console.log(iterator.next().value); // xyz
由于該方法基于ES6,并未完全支持
小結
以上,Array.prototype 的各方法基本介紹完畢,這些方法之間存在很多共性。比如:
例如 javascript 中一個純天然的類數組對象字符串(String),像join方法(不改變當前對象自身)就完全適用,可惜的是 Array.prototype 中很多方法均會去試圖修改當前對象的 length 屬性,比如說 pop、push、shift, unshift 方法,操作 String 對象時,由于String對象的長度本身不可更改,這將導致拋出TypeError錯誤。
還記得么,Array.prototype本身就是一個數組,并且它的長度為0。
參考文章
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array
https://juejin.im/post/5902d56e1b69e60058c634d6
文共2678字,預計學習時長15分鐘
圖源:unsplash
使用JavaScript時,總會有各種需要發出調用請求的情況,進行ajax調用什么技術更適合呢?
最初,盡管有一些方法可以在不刷新頁面的情況下從服務器提取數據,但它們通常依賴于笨拙的技術。直到微軟為Outlook電子郵件客戶端的替代瀏覽器開發了XMLHttpRequest。它在2006年成為了Web標準。
2015年,Fetch API隨ES6引入。通用的Request和Response接口提供了一致性,而Promises允許更容易的鏈接和沒有回調的異步/等待。Fetch簡潔,優雅且易于理解,但是還有其他不錯的選擇,本文將簡要的含義、語法以及利弊。
以下代碼展示了使用不同替代方法的基本HTTP GET和POST示例?,F在開始吧~
XMLHttpRequest對象可用于從Web服務器請求數據。它是這次比較中最早的方法,盡管其他選擇都優于它,但由于其向后兼容性和成熟度,它仍然有效且有用。
得到:
var req=new XMLHttpRequest();//The onreadystatechange property
//specifies a function to be
//executed every time the status
//of the XMLHttpRequest changes
req.onreadystatechange=function() {
if (this.readyState==4 &&this.status==200) {
//The responseText property
//returns a text string
console.log(xhttp.responseText)
//Do some stuff
}
};req.open("GET", "http://dataserver/users", true);
req.send();
發送:
varformData=new FormData();
formData.append("name", "Murdock");
var req=new XMLHttpRequest();
req.open("POST", "http://dataserver/update");
req.send(formData);
優點:
· 不需要從外部源加載
· 向后兼容性
· 成熟/穩定
· 在所有瀏覽器中均可使用
· 是原生瀏覽器API
缺點:
· 支持回調地獄
· 笨拙冗長的語法
· Fetch能自然地替代它
圖源:unsplash
Qwest是一個基于Promise的簡單ajax庫,它支持XmlHttpRequest2的獨立數據,例如ArrayBuffer,Blob和FormData。
得到:
qwest.get('http://dataserver/data.json')
.then(function(xhr, response) {
// ...do some stuff whith data
});
發送:
qwest.post('http://dataserver/update',{
firstname: 'Murdock',
age: 30
})
.then(function(xhr, response) {
// Make some useful actions
})
.catch(function(e, xhr, response) {
// Process the error
});
優點:
· 可以建立請求限制
· 基于Promise
缺點:
· 并非所有瀏覽器上都可使用XmlHttpRequest2
· 非原生
· 必須從外部源加載
該庫在不久前被廣泛用于發出HTTP異步請求。jQuery的所有Ajax方法都返回XMLHTTPRequest對象的超集
得到:
$.ajax({
url: 'http://dataserver/data.json'
}).done(function(data) {
// ...do some stuff whith data
}).fail(function() {
// Handle error
});
發送:
$.ajax({
type: "POST",
url: 'http://dataserver/update',
data: data,
success: successCallBack,
error: errorCallBack,
dataType: dataType
});
優點:
· 良好的支持和文檔
· 可配置的對象
· 在許多項目中使用
· 學習曲線低
· 它返回XMLHttpRequest對象,因此可以中止請求
缺點:
· 非原生
· 必須從外部源加載
· 沒有與Promises結合
· 對于原生ES6 Fetch不是必需的。
圖源:unsplash
基于Promise的HTTP庫,用于在瀏覽器和Nodejs上執行HTTP請求。
得到:
axios({
url: 'http://dataserver/data.json',
method: 'get'
})
發送:
axios.post('http://dataserver/update',{
name: 'Murdock'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
優點:
· 使用promise避免回調地獄
· 在瀏覽器和Nodejs上均可使用
· 支持上傳進度
· 可以設置響應超時
· 通過簡單地向其傳遞配置對象即可配置請求
· Axios已實現可撤銷的promise提議
· 自動將數據轉換為JSON
缺點:
· 非原生
· 必須從外部源加載
SuperAgent是ajax API,旨在提供靈活性,可讀性和較低的學習曲線。它也可以與Node.js一起使用。
得到:
request('GET','http://dataserver/data.json').then(
success, failure);
.query()方法接受對象,這些對象與GET方法一起使用時將形成查詢字符串。以下代碼將產生路徑/ dataserver / search?name=Manny&lastName=Peck&order=desc。
request
.get('/dataserver/search')
.query({ name: 'Templeton' })
.query({ lastname: 'Peck' })
.query({ order: 'desc' })
.then(res=> {console.dir(res)}
});
發送:
request
.post('http://dataserver/update')
.send({ name: 'Murdock' })
.set('Accept', 'application/json')
.then(res=> {
console.log('result' +JSON.stringify(res.body));
});
優點:
· 基于Promise
· 在Node.js和瀏覽器中均可使用
· 可以調用request.abort()方法中止請求
· 社區的知名庫
· 發出HTTP請求的無縫接口
· 出現故障時支持重試請求
缺點:
· 它不支持以XMLHttpRequest的形式監視加載進度
· 非原生
· 必須從外部源加載
圖源:unsplash
Http-client允許使用JavaScript的訪存API組成HTTP客戶端。
得到:
//usingES6 modules
import { createFetch, base, accept, parse } from 'http-client'const fetch=createFetch(
base('http://dataserver/data.json'),
accept('application/json'),
parse('json')
)fetch('http://dataserver/data.json').then(response=> {
console.log(response.jsonData)
})
發送:
//usingES6 modules
import { createFetch, method, params } from 'http-client'const fetch=createFetch(
params({ name: 'Murdock' }),
base('http://dataserver/update')
)
優點:
· 在Node.js和瀏覽器中均可使用
· 由服務器端工作人員使用
· 基于Promise
· 提供頭部保護裝置,以提高CORS的安全性
缺點:
· 必須從外部源加載
· 非原生
Fetch是原生瀏覽器API,用于發出替代XMLHttpRequest的請求。與XMLHttpRequest相比,Fetch使網絡請求更容易。Fetch API使用Promises避免XMLHttpRequest回調地獄。
得到:
//WithES6 fetch
fetch('http://dataserver/data.json')
.then(data=> {
// ...do some stuff whith data
}).catch(error=> {
// Handle error
});
發送:
fetch('http://dataserver/update',{
method: 'post',
headers: {
'Accept': 'application/json,text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify({name: 'Murdock'})
}).then(res=>res.json())
.then(res=> console.log(res));//ORwith ES2017 for example(async ()=> {
const response=awaitfetch('http://dataserver/update', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body:JSON.stringify({name='Murdock'})
});const result=awaitresponse.json();console.log(result);
})();
優點:
· 是原生瀏覽器API
· Fetch基本上是經過完善的XMLHttpRequest
· 友好且易于學習
· 與大多數最近使用的瀏覽器兼容
· 是原生XMLHttpRequest對象的自然替代
· 學習曲線低
· 不需要從外部源加載它
· 使用promises避免回調地獄
· 不需要更多依賴項
缺點:
· 處理JSON數據的過程分為兩步。第一個是發出請求,然后第二個是在響應時調用.json()方法。對于Axios,默認情況下會收到JSON響應。
· 從Fetch()返回的Promise僅在網絡故障或任何阻止請求完成的情況發生時拒絕。即使響應為HTTP 404或500,也不會拒絕HTTP錯誤狀態。
· 缺乏其他庫的一些有用功能,例如:取消請求。
· 默認情況下,Fetch不會從服務器發送或接收Cookie,如果站點依賴于維持用戶會話,則會導致未經身份驗證的請求。但是可以通過添加以下內容來啟用:
{credentials: “same-origin.”}
圖源:unsplash
Fetch是一個新標準,新版本的Chrome和Firefox無需使用任何其他庫就可支持它。
此外,Axios,SuperAgent或其他庫都有適合的文檔,易于使用,并且學習曲線不太高。在某些情況下,它們可以提供Fetch不具有的功能。
Fetch在JavaScript里是原生的,足以滿足項目需求。如果沒有特殊需求,我認為Fetch就是最合適的選擇。
留言點贊關注
我們一起分享AI學習與發展的干貨
如轉載,請后臺留言,遵守轉載規范
*請認真填寫需求信息,我們會在24小時內與您取得聯系。