offer收割機(jī)-Web前端面試寶典【精編版-2】

image

在線訪問手冊(cè):
https://hanxueqing.github.io/Web-Front-end-Interview-Q-A/
github地址:
https://github.com/Hanxueqing/Web-Front-end-Interview-Q-A

原型鏈

JavaScript原型,原型鏈 ? 有什么特點(diǎn)?

image

* 原型對(duì)象也是普通的對(duì)象,是對(duì)象一個(gè)自帶隱式的 proto 屬性,原型也有可能有自己的原型,如果一個(gè)原型對(duì)象的原型不為null的話,我們就稱之為原型鏈。

* 原型鏈?zhǔn)怯梢恍┯脕砝^承和共享屬性的對(duì)象組成的(有限的)對(duì)象鏈。

* JavaScript的數(shù)據(jù)對(duì)象有那些屬性值?

writable:這個(gè)屬性的值是否可以改。

configurable:這個(gè)屬性的配置是否可以刪除,修改。

enumerable:這個(gè)屬性是否能在for…in循環(huán)中遍歷出來或在Object.keys中列舉出來。

value:屬性值。

* 當(dāng)我們需要一個(gè)屬性的時(shí),Javascript引擎會(huì)先看當(dāng)前對(duì)象中是否有這個(gè)屬性, 如果沒有的話,就會(huì)查找他的Prototype對(duì)象是否有這個(gè)屬性。

 function clone(proto) {

  function Dummy() { }

  Dummy.prototype = proto;

  Dummy.prototype.constructor = Dummy;

  return new Dummy(); //等價(jià)于Object.create(Person);

 } 

        function object(old) {

         function F() {};

         F.prototype = old;

         return new F();

        }

    var newObj = object(oldObject);

Javascript如何實(shí)現(xiàn)繼承?

原型鏈繼承,借用構(gòu)造函數(shù)繼承,組合繼承,寄生式繼承,寄生組合繼承

數(shù)組

for-of和for-in的區(qū)別

遍歷數(shù)組的時(shí)候:

for-of通過key直接拿數(shù)組里面的值

for-in通過key拿數(shù)組的索引

遍歷對(duì)象的時(shí)候:

for-in通過key拿屬性值

for-of不可以遍歷對(duì)象

遍歷對(duì)象的方法,for of為什么不能遍歷對(duì)象?

for-of可以遍歷的:arr/map/string,因?yàn)樗麄冎袑?shí)現(xiàn)了Symbol.iterator屬性

for of如何遍歷對(duì)象

注意:for-of目前js實(shí)現(xiàn)的對(duì)象有array,string,argument以及后面更高級(jí)的set,Map

當(dāng)我們遍歷對(duì)象的時(shí)候可以使用for-in,不過這種遍歷方式會(huì)把原型上的屬性和方法也給遍歷出來,當(dāng)然我們可以通過hasOwnProperty來過濾掉除了實(shí)例對(duì)象的數(shù)據(jù),但是for-of在object對(duì)象上暫時(shí)沒有實(shí)現(xiàn),但是我們可以通過Symbol.iterator給對(duì)象添加這個(gè)屬性,我們就可以使用for-of了,代碼如下:

var p = {
            name:'kevin',
            age:2,
            sex:'male'
        }
        Object.defineProperty(p,Symbol.iterator,{
            enumberable:false,
            configurable:false,
            writable:false,
            value:function(){
                var _this = this;
                var nowIndex = -1;
                var key = Object.keys(_this);
                return {
                    next:function(){
                        nowIndex++;
                        return {
                            value:_this[key[nowIndex]],
                            done:(nowIndex+1>key.length)
                        }
                    }
                }
            }
        })

        //這樣的話就可以直接通過for-of來遍歷對(duì)象了
        for(var i of p){
            console.log(i) //kevin,2,male
        }

for-in遍歷數(shù)組存在的問題(for-in更適合遍歷對(duì)象)

var myArray = [1,2,4,5,6,7]
        myArray.name = "殺馬特"
        Array.prototype.method = function(){
            console.log("length",this.length)
        }
        for(var index in myArray){
            console.log("myArray",myArray[index])
        }

使用for in 也可以遍歷數(shù)組,但是會(huì)存在以下問題:

index索引為字符串型數(shù)字,不能直接進(jìn)行幾何運(yùn)算
遍歷順序有可能不是按照實(shí)際數(shù)組的內(nèi)部順序
使用for in會(huì)遍歷數(shù)組所有的可枚舉屬性,包括原型。例如上栗的原型方法method和name屬性 所以for in更適合遍歷對(duì)象,不要使用for in遍歷數(shù)組。
image

使用for-of遍歷數(shù)組:

//for-of遍歷數(shù)組
        var myArray = [1, 2, 4, 5, 6, 7]
            myArray.name = "殺馬特"
            Array.prototype.method = function () {
                console.log("length", this.length)
            }
            for (var index of myArray) {//這里的index輸出的是value而不是索引
                console.log("index", index)
            }
image

for循環(huán)和forEach循環(huán) 哪個(gè)可以停止

for循環(huán)可以通過break停止,forEach一般是沒有辦法終止跳出。

如何實(shí)現(xiàn)forEach的終止跳出?

思路1 break 不能用,不可行,執(zhí)行后會(huì)報(bào)錯(cuò)!

var arr = ['a','b','c']

arr.forEach((item,index) => {

if(item === 'b') break

console.log(item)

})

思路2 return false 會(huì)跳出當(dāng)前的遍歷執(zhí)行==》a,c

var arr = ['a','b','c']

arr.forEach((item,index) => {

if(item === 'b') return false

console.log(item)

})

思路3 try...catch 語句跳出異常 //a exit done

try {

  arr.forEach((item,index) => {

    if(item === 'b') throw new Error('exist')

    console.log(item)

  })

} catch (e) {

  if(e.message=='exist'){

console.log(e.message)

throw e

} 

} finally {

  console.log('done')

}

程序最后可以終止退出循環(huán),所以使用try...catch通過拋出異常的方式來終止程序繼續(xù)執(zhí)行是可行。

arr.map arr.filter arr.reduce的作用分別是?

【arr.map】

遍歷數(shù)組通常使用for循環(huán),ES5的話也可以使用forEach,ES5具有遍歷數(shù)組功能的還有map、filter、some、every、reduce、reduceRight等,只不過他們的返回結(jié)果不一樣。但是使用foreach遍歷數(shù)組的話,使用break不能中斷循環(huán),使用return也不能返回到外層函數(shù)

arr.map循環(huán)遍歷,并且將符合條件的元素放入一個(gè)新數(shù)組返回

var arr = [1,2,3]
let b = [];
//map循環(huán)遍歷,并且返回一個(gè)新數(shù)組
let a = arr.map(item=>{
    if(item>2){
        b.push(item)
        return b
    }
})
console.log(b) //返回符合條件的新數(shù)據(jù)[3]

因?yàn)閞eact中沒有v-for指令,所以循環(huán)渲染的時(shí)候需要用到arr.map方法來渲染視圖

【arr.filter】

arr.filter 過濾器 可以過濾掉不符合要求的元素,內(nèi)部返回false就直接過濾掉了,將符合條件的數(shù)據(jù)返回,也是不影響原數(shù)組。

//過濾器
arr = arr.filter(item=>{
    return item>2
})
console.log(arr) //過濾出來符合條件的數(shù)據(jù)[3]

【arr.reduce】

reduce為數(shù)組中每一個(gè)元素依次執(zhí)行回調(diào)函數(shù),不包括數(shù)組中被刪除或從未被賦值的元素,接收四個(gè)參數(shù):初始值(或者上一次回調(diào)函數(shù)的返回值),當(dāng)前元素值,當(dāng)前索引,調(diào)用reduce的數(shù)組。reduce方法可以搞定的東西for循環(huán)或者forEach方法有時(shí)候也可以搞定。

var newArr = [4,5,6,7]
newArr.reduce((res,currentValue,index,arr)=>{//第一個(gè)參數(shù)為一個(gè)回調(diào)函數(shù)
    console.log(res,currentValue,index) //4,5,1
})
//res:默認(rèn)為第一個(gè)值(4),currentValue:當(dāng)前值(5),index:當(dāng)前值的索引(1)
let result = newArr.reduce((res,currentValue,index,arr)=>{
    console.log(res,currentValue) //第一次:4,5;第二次:9,6;第三次:15,7
    return res+currentValue//第一次:9;第二次:15;第三次:22;最后結(jié)果為22
},10)//第二個(gè)參數(shù)為一個(gè)初始值,這里給它賦值為10
console.log(result)//現(xiàn)在res就變成了10,currentValue變成了4,依次累加,10+22 初始值+累加值

Filter、forEach、map、reduce之間的區(qū)別聯(lián)系?

作用

every():對(duì)數(shù)組中的每一項(xiàng)運(yùn)行給定函數(shù),如果該函數(shù)對(duì)每一項(xiàng)都返回 true ,則返回 true。
some():對(duì)數(shù)組中的每一項(xiàng)運(yùn)行給定函數(shù),如果該函數(shù)對(duì)任一項(xiàng)返回 true ,則返回 true
filter():對(duì)數(shù)組中的每一項(xiàng)運(yùn)行給定函數(shù),返回該函數(shù)會(huì)返回 true 的項(xiàng)組成的數(shù)組。
forEach():對(duì)數(shù)組中的每一項(xiàng)運(yùn)行給定函數(shù)。這個(gè)方法沒有返回值。

map():對(duì)數(shù)組中的每一項(xiàng)運(yùn)行給定函數(shù),返回每次函數(shù)調(diào)用的結(jié)果組成的數(shù)組。

相同點(diǎn)

他們的參數(shù)都一樣:

  • 在每一項(xiàng)上運(yùn)行的函數(shù)(該函數(shù)有三個(gè)參數(shù))
    • 函數(shù)第一個(gè)參數(shù):數(shù)組項(xiàng)的值
    • 函數(shù)第二個(gè)參數(shù):數(shù)組項(xiàng)的索引
    • 函數(shù)第三個(gè)參數(shù):數(shù)組對(duì)象本身
  • 運(yùn)行該函數(shù)的作用域?qū)ο蟆绊憈his的值(可選)

區(qū)別

filter()、forEach()、map()、some()、every()都是對(duì)數(shù)組的每一項(xiàng)調(diào)用函數(shù)進(jìn)行處理。

區(qū)別:
– some()、every()的返回值 :true / false
– filter()、map()的返回值 :一個(gè)新數(shù)組
– forEach()無返回值。

使用filter()、forEach()、map()、some()、every()都不改變?cè)瓟?shù)組。

參考:js小記:filter()、forEach()、map()、reduce()、reduceRight()的區(qū)別

https://blog.csdn.net/b954960630/article/details/81432881

splice()

splice(index,len,[item]) 注釋:該方法會(huì)改變?cè)紨?shù)組。

//刪除起始下標(biāo)為1,長度為1的一個(gè)值(len設(shè)置1,如果為0,則數(shù)組不變)
var arr = ['a','b','c','d'];
arr.splice(1,1);
console.log(arr); //['a','c','d']; 

//替換起始下標(biāo)為1,長度為1的一個(gè)值為‘ttt’,len設(shè)置的1
var arr = ['a','b','c','d'];
arr.splice(1,1,'ttt');
console.log(arr); //['a','ttt','c','d'] 

var arr = ['a','b','c','d'];
arr.splice(1,0,'ttt');
console.log(arr); //['a','ttt','b','c','d'] 表示在下標(biāo)為1處添加一項(xiàng)'ttt'

slice()

slice()方法可以基于當(dāng)前數(shù)組獲取指定區(qū)域元素 [start, end)

格式:數(shù)組.slice(start, end);

參數(shù):start和end都是下標(biāo),[start, end),獲取指定范圍內(nèi)的元素,生成新數(shù)組。(原數(shù)組是不會(huì)改變的。

返回值:提取出來元素組成的新數(shù)組。

split()和join()的區(qū)別

join函數(shù)獲取一批字符串,然后用分隔符字符串將它們連接起來,從而返回一個(gè)字符串。
split()函數(shù)獲取一個(gè)字符串,然后在分隔符處將其斷開,從而返回一批字符串。
但是,這兩個(gè)函數(shù)之間的區(qū)別在于join可以使用任何分割字符串將多個(gè)字符串連接起來,而split()只能使用一個(gè)字符分隔符將字符串?dāng)嚅_。
簡單地說,如果你用split(),是把一串字符串(根據(jù)某個(gè)分隔符)分成若干個(gè)元素存放在一個(gè)數(shù)組里。而join是把數(shù)組中的字符串連接成一個(gè)長串,可以大體上認(rèn)為是split的逆操作。

push、pop、shift、unshift

  • push()方法可以在數(shù)組的末屬添加一個(gè)或多個(gè)元素

  • shift()方法把數(shù)組中的第一個(gè)元素刪除

  • unshift()方法可以在數(shù)組的前端添加一個(gè)或多個(gè)元素

  • pop()方法把數(shù)組中的最后一個(gè)元素刪除

參考:數(shù)組的push()、pop()、shift()和unshift()方法

https://blog.csdn.net/qwe502763576/article/details/79055682

數(shù)組的方法

解析鏈接www.qq.com?name=jack&age=18&id=100,獲取其中的查詢參數(shù),并格式為js對(duì)象的代碼:如: {name:”jack”,age:18,id:100}

var str = "www.qq.com?name=jack&age=18";
var str2 = str.substring(str.lastIndexOf(“?")+1); //索引從后往前找
var arr = str2.split(“&”);//通過&符號(hào)去切割 切割成如下形式[‘name = jack’,’age=18’,'id=100']
var json = {};
for(var i=0;i<arr.length;i++){ //循環(huán)遍歷數(shù)組的長度
    var newArr = arr[i].split(“=“); //拿到每一個(gè)字符串 拿到之后通過split進(jìn)行切割 [‘name’,’jack’]
    json[newArr[0]] = newArr[1];  // key名=value
} 
考查知識(shí)點(diǎn):數(shù)組截取方法/數(shù)組中字符串操作/對(duì)象的中括號(hào)會(huì)不會(huì)用
對(duì)象的、數(shù)組的、字符串的相關(guān)的使用的比較多的方法

下列代碼的運(yùn)行結(jié)果是:

var array1 = [1,2]; 
var array2 = array1; // 數(shù)組指向的是同一個(gè)地址
array1[0] = array2[1]; // 把a(bǔ)rray[1]拿出來放在array1[0]的位置變成2,2
array2.push(3);
console.log(array1);// [2,2,3]
console.log(array2);// [2,2,3]
        var arr = [1,2]
        arr2 = arr;//arr2和arr1指向的是同一塊內(nèi)存空間
        arr2.push(3)
        console.log(arr) //[1,2,3]
        var arr = [1,2]
        arr2 = arr
        arr = [1,2,3] //arr 指向了新的內(nèi)存空間
        arr2.push(4)
        console.log(arr)//[1,2,3]
        console.log(arr2)//[1,2,4]
        var a = {n:1}
        var b = a;
        a.x = a = {n:2}
        console.log(a); //a賦值了一個(gè)新的地址 輸出{n:2}
        console.log(b); //b指向的是a原來的地址 輸出{n:1,x:{n:2}}

JS數(shù)組去重

  1. 利用splice方法
var arr = [10, 20, 30, 40, 50, 40, 30, 20, 20, 20, 20, 10];
    function norepeat(arr){
        for(var i = 0; i < arr.length - 1; i++){
            for(var j = i + 1; j < arr.length; j++){
                if(arr[i] === arr[j]){
                    arr.splice(j,1);
                    j--
                }
            }
        }
    }
    alert(arr);//10,20,30,40,50,40,30,20,20,20,20,10
    norepeat(arr);
    alert(arr);//10,20,30,40,50
  1. 倒序刪除
//倒序刪除
    function norepeat(arr){
        for(var i = arr.length -1; i > 0; i--){
            for(var j = i - 1;j >= 0; j--){
                if(arr[i] === arr[j]){
                    arr.splice(j,1);
                }
            }
        }
    }
    alert(arr);//10,20,30,40,50,40,30,20,20,20,20,10
    norepeat(arr);
    arr.reverse();
    alert(arr);//10,20,30,40,50
  1. 利用對(duì)象的屬性不會(huì)重復(fù)這一特性,校驗(yàn)數(shù)組元素是否重復(fù)
function unique(arr){
        var obj = {};
        var result = [];
        for(var i=0;i<arr.length;i++){
            if(!obj[arr[i]]){
                result.push(arr[i]);
                obj[arr[i]] = true; //將每個(gè)數(shù)作為key,屬性值值為true,當(dāng)key名相同時(shí),判斷屬性值是否為false,不為false則不push進(jìn)數(shù)組
            }
        }
        return result;
}
  1. ES6中新增了數(shù)據(jù)類型set,set的一個(gè)最大的特點(diǎn)就是數(shù)據(jù)不重復(fù)。Set函數(shù)可以接受一個(gè)數(shù)組(或類數(shù)組對(duì)象)作為參數(shù)來初始化,利用該特性也能做到給數(shù)組去重。

    Set集合是默認(rèn)去重復(fù)的,但前提是兩個(gè)添加的元素嚴(yán)格相等,所以5和"5"不相等,兩個(gè)new出來的字符串不相等。

下面展示了一種極為精巧的數(shù)組去重的方法

var newarr = [...new Set(array)];

//拓展 固定寫法
    alert(arr);//10,20,30,40,50,40,30,20,20,20,20,10
    //下述寫法的值,就是去重以后的數(shù)組。
    arr = [...new Set(arr)];
    alert(arr);//10,20,30,40,50

跨域

什么是跨域

由于 Javascript 同源策略的存在使得一個(gè)源中加載來自其它源中資源的行為受到了限制。即會(huì)出現(xiàn)跨域請(qǐng)求禁止。

通俗一點(diǎn)說就是如果存在協(xié)議、域名、端口或者子域名不同服務(wù)端,或一者為IP地址,一者為域名地址(在跨域問題上,域僅僅是通過“ url的首部 ”來識(shí)別而不會(huì)去嘗試判斷相同的IP地址對(duì)應(yīng)著兩個(gè)域或者兩個(gè)域是否同屬同一個(gè)IP),之中任意服務(wù)端旗下的客戶端發(fā)起請(qǐng)求其它服務(wù)端資源的訪問行動(dòng)都是跨域的,而瀏覽器為了安全問題一般都限制了跨域訪問,也就是不允許跨域請(qǐng)求資源。

同源策略

  1. 同協(xié)議

  2. 同域名

  3. 同端口號(hào)

解決跨域問題的主流方案是什么

  1. Jsonp 利用script標(biāo)簽發(fā)起get請(qǐng)求不會(huì)出現(xiàn)跨域禁止的特點(diǎn)實(shí)現(xiàn)

  2. window.name+iframe 借助中介屬性window.name實(shí)現(xiàn)

  3. html5的 postMessage 主要側(cè)重于前端通訊,不同域下頁面之間的數(shù)據(jù)傳遞

  4. Cors需要服務(wù)器設(shè)置header:Access-Control-Allow-Origin

  5. Nginx反向代理 可以不需要目標(biāo)服務(wù)器配合,不過需要Nginx中轉(zhuǎn)服務(wù)器,用于轉(zhuǎn)發(fā)請(qǐng)求(服務(wù)端之間的資源請(qǐng)求不會(huì)有跨域限制)

參考:Nginx反向代理、CORS、JSONP等跨域請(qǐng)求解決方法總結(jié)

https://blog.csdn.net/diudiu5201/article/details/54808142

cors實(shí)現(xiàn)請(qǐng)求跨域

https://blog.csdn.net/badmoonc/article/details/82706246

JQuery跨域方式

  1. 修改ajax的請(qǐng)求頭(盡量不要用)

改成"Access-control-Allow-Origin"

  1. 通過PHP文件作為中轉(zhuǎn)站,進(jìn)行間接跨源(爬蟲)

  2. JSONP跨域

JSONP原理

動(dòng)態(tài)創(chuàng)建script標(biāo)簽,src屬性連接接口地址,callback參數(shù)就是服務(wù)器返回給我們的數(shù)據(jù)。

缺點(diǎn):jsonp只支持get請(qǐng)求方式,post方式不支持。

JSONP跨域的流程

  1. 在資源加載進(jìn)來之前定義好一個(gè)函數(shù),這個(gè)函數(shù)接收一個(gè)參數(shù)(數(shù)據(jù)),函數(shù)里面利用這個(gè)參數(shù)做一些事情。

  2. 然后需要的時(shí)候通過script標(biāo)簽加載對(duì)應(yīng)的遠(yuǎn)程文件資源。

  3. 當(dāng)遠(yuǎn)程文件加載進(jìn)來的時(shí)候,就會(huì)去執(zhí)行我們前面定義好的函數(shù),并且把數(shù)據(jù)當(dāng)做這個(gè)函數(shù)中的參數(shù)傳進(jìn)去。

JSONP跨域的缺點(diǎn)

  1. 它只支持GET請(qǐng)求而不支持POST等其它類型的HTTP請(qǐng)求;

  2. 它只支持跨域HTTP請(qǐng)求這種情況,不能解決不同域的兩個(gè)頁面之間如何進(jìn)行JavaScript調(diào)用的問題

  3. json文件不能用jsonp方法。

AJAX

什么是AJAX

AJAX是一種用于快速創(chuàng)建動(dòng)態(tài)網(wǎng)頁的技術(shù),通過在后臺(tái)與服務(wù)器進(jìn)行少量數(shù)據(jù)交換,AJAX可以實(shí)現(xiàn)網(wǎng)頁實(shí)現(xiàn)異步更新,這意味著可以在不加載整個(gè)網(wǎng)頁的情況下,對(duì)網(wǎng)頁的某部分進(jìn)行更新。

傳統(tǒng)的網(wǎng)頁(不使用AJAX)如果需要更新內(nèi)容,必須重載整個(gè)網(wǎng)頁。

AJAX的原理

思路:先解釋異步,再解釋ajax如何使用

Ajax的原理簡單來說通過XmlHttpRequest對(duì)象來向服務(wù)器發(fā)異步請(qǐng)求,從服務(wù)器獲得數(shù)據(jù),然后用javascript來操作DOM而更新頁面。這其中最關(guān)鍵的一步就是從服務(wù)器獲得請(qǐng)求數(shù)據(jù)。要清楚這個(gè)過程和原理,我們必須對(duì) XMLHttpRequest有所了解。

XMLHttpRequest是ajax的核心機(jī)制,它是在IE5中首先引入的,是一種支持異步請(qǐng)求的技術(shù)。簡單的說,也就是javascript可以及時(shí)向服務(wù)器提出請(qǐng)求和處理響應(yīng),而不阻塞用戶。達(dá)到無刷新的效果。

AJAX的優(yōu)點(diǎn)

AJAX不是新的編程語言,而是一種使用現(xiàn)有標(biāo)準(zhǔn)的新方法。

AJAX最大的優(yōu)點(diǎn)是在不重新加載整個(gè)頁面的情況下,可以與服務(wù)器交換數(shù)據(jù)并更新部分網(wǎng)頁內(nèi)容。

AJAX不需要任何瀏覽器插件,但需要用戶允許JavaScript在瀏覽器上運(yùn)行。

AJAX的缺點(diǎn)

  1. AJAX干掉了Back和History功能,即對(duì)瀏覽器機(jī)制的破壞。 在動(dòng)態(tài)更新頁面的情況下,用戶無法回到前一個(gè)頁面狀態(tài),因?yàn)闉g覽器僅能記憶歷史記錄中的靜態(tài)頁面。一個(gè)被完整讀入的頁面與一個(gè)已經(jīng)被動(dòng)態(tài)修改過的頁面之間的差別非常微妙;用戶通常會(huì)希望單擊后退按鈕能夠取消他們的前一次操作,但是在Ajax應(yīng)用程序中,這將無法實(shí)現(xiàn)。

  2. 安全問題技術(shù)同時(shí)也對(duì)IT企業(yè)帶來了新的安全威脅,ajax技術(shù)就如同對(duì)企業(yè)數(shù)據(jù)建立了一個(gè)直接通道。這使得開發(fā)者在不經(jīng)意間會(huì)暴露比以前更多的數(shù)據(jù)和服務(wù)器邏輯。ajax的邏輯可以對(duì)客戶端的安全掃描技術(shù)隱藏起來,允許黑客從遠(yuǎn)端服務(wù)器上建立新的攻擊。還有ajax也難以避免一些已知的安全弱點(diǎn),諸如跨站點(diǎn)腳步攻擊、SQL注入攻擊和基于credentials的安全漏洞等。

  3. 對(duì)搜索引擎的支持比較弱。如果使用不當(dāng),AJAX會(huì)增大網(wǎng)絡(luò)數(shù)據(jù)的流量,從而降低整個(gè)系統(tǒng)的性能。

AJAX狀態(tài)碼說明

1**:請(qǐng)求收到,繼續(xù)處理

2**:操作成功收到,分析、接受

3**:完成此請(qǐng)求必須進(jìn)一步處理

4**:請(qǐng)求包含一個(gè)錯(cuò)誤語法或不能完成

5**:服務(wù)器執(zhí)行一個(gè)完全有效請(qǐng)求失敗

AJAX的流程

  1. 聲明Ajax對(duì)象xhr,創(chuàng)建 XMLHttpRequest 實(shí)例

IE8以后才有如下聲明的方式

var xhr = new XMLHttpRequest();

XMLHttpRequest()是AJAX的原生對(duì)象

  1. 一旦新建實(shí)例,就可以使用open()方法發(fā)出 HTTP 請(qǐng)求。

填寫請(qǐng)求信息,發(fā)出 HTTP 請(qǐng)求

第一個(gè)參數(shù):請(qǐng)求方式:get/post

第二個(gè)參數(shù):url(統(tǒng)一資源定位符)

第三個(gè)參數(shù):true/false true異步,false同步

xhr.open('GET', 'http://www.example.com/page.php', true);
  1. 向服務(wù)器發(fā)送請(qǐng)求

xhr.send(),正在發(fā)送請(qǐng)求

  1. 等待數(shù)據(jù)響應(yīng),接收服務(wù)器傳回的數(shù)據(jù)

xhr.onreadystatechange = function(){}

在回調(diào)函數(shù)中進(jìn)行請(qǐng)求狀態(tài)readyState的監(jiān)控

當(dāng) readyState 等于 4 且狀態(tài)為 200 時(shí),表示響應(yīng)內(nèi)容解析完成,可以在客戶端調(diào)用了。

返回的內(nèi)容:

responseText:返回以文本形式存放的內(nèi)容

responseXML:返回XML形式的內(nèi)容

  1. 更新網(wǎng)頁數(shù)據(jù)

AJAX中的GET和POST請(qǐng)求

get一般用來進(jìn)行查詢操作,url地址有長度限制,請(qǐng)求的參數(shù)都暴露在url地址當(dāng)中,如果傳遞中文參數(shù),需要自己進(jìn)行編碼操作,安全性較低。

post請(qǐng)求方式主要用來提交數(shù)據(jù),沒有數(shù)據(jù)長度的限制,提交的數(shù)據(jù)內(nèi)容存在于http請(qǐng)求體中,數(shù)據(jù)不會(huì)暴漏在url地址中。

GET 還是 POST?

與 POST 相比,GET 更簡單也更快,并且在大部分情況下都能用。

然而,在以下情況中,請(qǐng)使用 POST 請(qǐng)求:

  • 無法使用緩存文件(更新服務(wù)器上的文件或數(shù)據(jù)庫)
  • 向服務(wù)器發(fā)送大量數(shù)據(jù)(POST 沒有數(shù)據(jù)量限制)
  • 發(fā)送包含未知字符的用戶輸入時(shí),POST 比 GET 更穩(wěn)定也更可靠

AJAX如何實(shí)現(xiàn)跨域

理解跨域的概念:協(xié)議、域名、端口都相同才同域,否則都是跨域。

出于安全考慮,服務(wù)器不允許ajax跨域獲取數(shù)據(jù),但是可以跨域獲取文件內(nèi)容,所以基于這一點(diǎn),可以動(dòng)態(tài)創(chuàng)建script標(biāo)簽,使用標(biāo)簽的src屬性訪問js文件的形式獲取js腳本,并且這個(gè)js腳本中的內(nèi)容是函數(shù)調(diào)用,該函數(shù)調(diào)用的參數(shù)是服務(wù)器返回的數(shù)據(jù),為了獲取這里的參數(shù)數(shù)據(jù),需要事先在頁面中定義回調(diào)函數(shù),在回調(diào)函數(shù)中處理服務(wù)器返回的數(shù)據(jù),這就是解決跨域問題的主流解決方案。

一個(gè)頁面從輸入U(xiǎn)RL到頁面加載顯示完成,這個(gè)過程中都發(fā)生了什么?

分為4個(gè)步驟:

  1. 當(dāng)發(fā)送一個(gè) URL 請(qǐng)求時(shí),不管這個(gè) URL 是 Web 頁面的 URL 還是 Web 頁面上每個(gè)資源的 URL,瀏覽器都會(huì)開啟一個(gè)線程來處理這個(gè)請(qǐng)求,同時(shí)在遠(yuǎn)程 DNS 服務(wù)器上啟動(dòng)一個(gè) DNS 查詢。這能使瀏覽器獲得請(qǐng)求對(duì)應(yīng)的 IP 地址。

  2. 瀏覽器與遠(yuǎn)程 Web 服務(wù)器通過 TCP 三次握手協(xié)商來建立一個(gè) TCP/IP 連接。該握手包括一個(gè)同步報(bào)文,一個(gè)同步-應(yīng)答報(bào)文和一個(gè)應(yīng)答報(bào)文,這三個(gè)報(bào)文在 瀏覽器和服務(wù)器之間傳遞。該握手首先由客戶端嘗試建立起通信,而后服務(wù)器應(yīng)答并接受客戶端的請(qǐng)求,最后由客戶端發(fā)出該請(qǐng)求已經(jīng)被接受的報(bào)文。

  3. 一旦 TCP/IP 連接建立,瀏覽器會(huì)通過該連接向遠(yuǎn)程服務(wù)器發(fā)送 HTTP 的 GET 請(qǐng)求。遠(yuǎn)程服務(wù)器找到資源并使用 HTTP 響應(yīng)返回該資源,值為 200 的 HTTP 響應(yīng)狀態(tài)表示一個(gè)正確的響應(yīng)。

  4. 此時(shí),Web 服務(wù)器提供資源服務(wù),客戶端開始下載資源。

從用戶輸入U(xiǎn)RL,到瀏覽器呈現(xiàn)給用戶頁面,經(jīng)過了什么過程?

用戶輸入U(xiǎn)RL,瀏覽器獲取到URL

瀏覽器(應(yīng)用層)進(jìn)行DNS解析(如果輸入的是IP地址,此步驟省略)

根據(jù)解析出的IP地址+端口,瀏覽器(應(yīng)用層)發(fā)起HTTP請(qǐng)求,請(qǐng)求中攜帶(請(qǐng)求頭header(也可細(xì)分為請(qǐng)求行和請(qǐng)求頭)、請(qǐng)求體body),

header包含:

請(qǐng)求的方法(get、post、put..)

協(xié)議(http、https、ftp、sftp...)

目標(biāo)url(具體的請(qǐng)求路徑已經(jīng)文件名)

一些必要信息(緩存、cookie之類)

body包含:

請(qǐng)求的內(nèi)容

請(qǐng)求到達(dá)傳輸層,tcp協(xié)議為傳輸報(bào)文提供可靠的字節(jié)流傳輸服務(wù),它通過三次握手等手段來保證傳輸過程中的安全可靠。通過對(duì)大塊數(shù)據(jù)的分割成一個(gè)個(gè)報(bào)文段的方式提供給大量數(shù)據(jù)的便攜傳輸。

到網(wǎng)絡(luò)層, 網(wǎng)絡(luò)層通過ARP尋址得到接收方的Mac地址,IP協(xié)議把在傳輸層被分割成一個(gè)個(gè)數(shù)據(jù)包傳送接收方。

數(shù)據(jù)到達(dá)數(shù)據(jù)鏈路層,請(qǐng)求階段完成

接收方在數(shù)據(jù)鏈路層收到數(shù)據(jù)包之后,層層傳遞到應(yīng)用層,接收方應(yīng)用程序就獲得到請(qǐng)求報(bào)文。

接收方收到發(fā)送方的HTTP請(qǐng)求之后,進(jìn)行請(qǐng)求文件資源(如HTML頁面)的尋找并響應(yīng)報(bào)文。

發(fā)送方收到響應(yīng)報(bào)文后,如果報(bào)文中的狀態(tài)碼表示請(qǐng)求成功,則接受返回的資源(如HTML文件),進(jìn)行頁面渲染。

fetch

什么是fetch?

fetch號(hào)稱是AJAX的替代品,是在ES6出現(xiàn)的,使用了ES6中的promise對(duì)象。Fetch是基于promise設(shè)計(jì)的。Fetch的代碼結(jié)構(gòu)比起ajax簡單多了,參數(shù)有點(diǎn)像jQuery ajax。但是,一定記住fetch不是ajax的進(jìn)一步封裝,而是原生js,沒有使用XMLHttpRequest對(duì)象

try {
  let response = await fetch(url);
  let data = response.json();
  console.log(data);
} catch(e) {
  console.log("Oops, error", e);
}

fetch的優(yōu)點(diǎn)

  1. 符合關(guān)注分離,沒有將輸入、輸出和用事件來跟蹤的狀態(tài)混雜在一個(gè)對(duì)象里。
  2. 更好更方便的寫法

fetch的優(yōu)勢(shì)

  1. 語法簡潔,更加語義化
  2. 基于標(biāo)準(zhǔn) Promise 實(shí)現(xiàn),支持 async/await
  3. 同構(gòu)方便,使用 isomorphic-fetch
  4. 更加底層,提供的API豐富(request, response)
  5. 脫離了XHR,是ES規(guī)范里新的實(shí)現(xiàn)方式

fetch的劣勢(shì)

  1. fetch只對(duì)網(wǎng)絡(luò)請(qǐng)求報(bào)錯(cuò),對(duì)400,500都當(dāng)做成功的請(qǐng)求,服務(wù)器返回 400,500 錯(cuò)誤碼時(shí)并不會(huì) reject,只有網(wǎng)絡(luò)錯(cuò)誤這些導(dǎo)致請(qǐng)求不能完成時(shí),fetch 才會(huì)被 reject。
  2. fetch默認(rèn)不會(huì)帶cookie,需要添加配置項(xiàng): fetch(url, {credentials: 'include'})
  3. fetch不支持abort,不支持超時(shí)控制,使用setTimeout及Promise.reject的實(shí)現(xiàn)的超時(shí)控制并不能阻止請(qǐng)求過程繼續(xù)在后臺(tái)運(yùn)行,造成了流量的浪費(fèi)
  4. fetch沒有辦法原生監(jiān)測(cè)請(qǐng)求的進(jìn)度,而XHR可以

axios

axios是什么

Axios 是一個(gè)基于 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中,主要是用于向后臺(tái)發(fā)起請(qǐng)求的。

axios的用途

(1)向后臺(tái)發(fā)送ajax請(qǐng)求數(shù)據(jù)。

(2) axios可以支持高并發(fā)請(qǐng)求,可以同時(shí)請(qǐng)求多個(gè)接口。

(3) axios可以防止CSRF/XSRF(跨站請(qǐng)求偽造)釣魚網(wǎng)站。

(4)axios提供了攔截器、catch捕獲。

封裝axios

Get

import axios from 'axios'

export default ({url,data})=>{
    return axios.get(url,{
        params:data
    })
}

Post

import axios from 'axios'
import qs from 'querystring'

export default ({url,data})=>{
    return axios.post(url,qs.stringify(data))
}

利用axios實(shí)現(xiàn)數(shù)據(jù)請(qǐng)求

引入axios之后就可以在實(shí)例/組件上掛載一個(gè)$http屬性,用這個(gè)就可以進(jìn)行數(shù)據(jù)交互了。

提供了一個(gè)get方法,執(zhí)行this.$http.get().then()可以異步執(zhí)行,拿到promise對(duì)象的值

axios如何防止CSRF(跨站攻擊)

在a頁面登錄注冊(cè)成功后時(shí)候跳轉(zhuǎn)到b頁面,b頁面可以獲取你的cookie信息,把你的用戶信息攔截到,然后惡意向別的網(wǎng)站散發(fā)一些郵件或者其他的東西,當(dāng)你使用axios之后,就可以防止這種攻擊,a頁面存儲(chǔ)的時(shí)候往cookie添加一個(gè)唯一個(gè)key,b頁面如果是別的域名是獲取不到這個(gè)key的,釣魚網(wǎng)站就是把b頁面這個(gè)域名篡改到別的位置去了,所以它無法獲取到key值,也就拿不到用戶信息,這樣可以防止釣魚網(wǎng)站的威脅。

如何在項(xiàng)目中通過路由守衛(wèi)來實(shí)現(xiàn)登錄攔截?講一個(gè)在項(xiàng)目中使用路由守衛(wèi)的案例?

攔截器的工作流程:

image

第一步:路由攔截

首先在定義路由的時(shí)候就需要多添加一個(gè)自定義字段requireAuth,用于判斷該路由的訪問是否需要登錄。如果用戶已經(jīng)登錄,則順利進(jìn)入路由, 否則就進(jìn)入登錄頁面。

const routes = [
    {
        path: '/',
        name: '/',
        component: Index
    },
    {
        path: '/repository',
        name: 'repository',
        meta: {
            requireAuth: true,  // 添加該字段,表示進(jìn)入這個(gè)路由是需要登錄的
        },
        component: Repository
    },
    {
        path: '/login',
        name: 'login',
        component: Login
    }
];

定義完路由后,我們主要是利用vue-router提供的鉤子函數(shù)beforeEach()對(duì)路由進(jìn)行判斷。

router.beforeEach((to, from, next) => {
    if (to.meta.requireAuth) {  // 判斷該路由是否需要登錄權(quán)限
        if (store.state.token) {  // 通過vuex state獲取當(dāng)前的token是否存在
            next();
        }
        else {
            next({
                path: '/login',
                query: {redirect: to.fullPath}  // 將跳轉(zhuǎn)的路由path作為參數(shù),登錄成功后跳轉(zhuǎn)到該路由
            })
        }
    }
    else {
        next();
    }
})

其中,to.meta中是我們自定義的數(shù)據(jù),其中就包括我們剛剛定義的requireAuth字段。通過這個(gè)字段來判斷該路由是否需要登錄權(quán)限。需要的話,同時(shí)當(dāng)前應(yīng)用不存在token,則跳轉(zhuǎn)到登錄頁面,進(jìn)行登錄。登錄成功后跳轉(zhuǎn)到目標(biāo)路由。

登錄攔截到這里就結(jié)束了嗎?并沒有。這種方式只是簡單的前端路由控制,并不能真正阻止用戶訪問需要登錄權(quán)限的路由。還有一種情況便是:當(dāng)前token失效了,但是token依然保存在本地。這時(shí)候你去訪問需要登錄權(quán)限的路由時(shí),實(shí)際上應(yīng)該讓用戶重新登錄。
這時(shí)候就需要結(jié)合 http 攔截器 + 后端接口返回的http 狀態(tài)碼來判斷。(具體方法見下一題目)

axios+vue如何在前端實(shí)現(xiàn)登錄攔截?(路由攔截、http攔截)

登錄流程控制中,根據(jù)本地是否存在token判斷用戶的登錄情況,但是即使token存在,也有可能token是過期的,所以在每次的請(qǐng)求頭中攜帶token,后臺(tái)根據(jù)攜帶的token判斷用戶的登錄情況,并返回給我們對(duì)應(yīng)的狀態(tài)碼,而后我們可以在響應(yīng)攔截器中,根據(jù)狀態(tài)碼進(jìn)行一些統(tǒng)一的操作。

// 先導(dǎo)入vuex,因?yàn)槲覀円褂玫嚼锩娴臓顟B(tài)對(duì)象
// vuex的路徑根據(jù)自己的路徑去寫
import store from '@/store/index';

// 請(qǐng)求攔截器axios.interceptors.request.use(  //axios的一個(gè)方法,用于請(qǐng)求之前攔截  
    config => {        
        // 每次發(fā)送請(qǐng)求之前判斷vuex中是否存在token        
        // 如果存在,則統(tǒng)一在http請(qǐng)求的header都加上token,這樣后臺(tái)根據(jù)token判斷你的登錄情況
        // 即使本地存在token,也有可能token是過期的,所以在響應(yīng)攔截器中要對(duì)返回狀態(tài)進(jìn)行判斷 
        const token = store.state.token;        
        token && (config.headers.Authorization = token); (Authorization是后端自定義的名字) // 判斷vuex中是否存在token,如果存在的話,則在每個(gè)http請(qǐng)求時(shí)header都加上token       
        return config;  //再把這個(gè)請(qǐng)求發(fā)送給我們的后臺(tái)  
    },    
    error => {        
        return Promise.error(error); //如果有錯(cuò)誤直接返回報(bào)錯(cuò)的相關(guān)內(nèi)容   
})

如果后臺(tái)傳遞過來的狀態(tài)碼是失效狀態(tài),就需要在response響應(yīng)攔截器中清除本地token和清空vuex中token對(duì)象,通過commit觸發(fā)mutations方法來同步更改vuex中的狀態(tài),清空token之后跳轉(zhuǎn)到登錄頁面,讓用戶重新登錄。

// 清除token
                    localStorage.removeItem('token');
                    store.commit('loginSuccess', null);
                    // 跳轉(zhuǎn)登錄頁面,并將要瀏覽的頁面fullPath傳過去,登錄成功后跳轉(zhuǎn)需要訪問的頁面 
                    setTimeout(() => {                        
                        router.replace({                            
                            path: '/login',                            
                            query: { 
                                redirect: router.currentRoute.fullPath 
                            }                        
                        });                    
                    }, 1000);

完整方法見:vue中Axios的封裝和API接口的管理

https://juejin.im/post/5b55c118f265da0f6f1aa354

vue+axios 前端實(shí)現(xiàn)登錄攔截(路由攔截、http攔截)

https://www.cnblogs.com/guoxianglei/p/7084506.html

一個(gè)axios的簡單教程

http://m.itdecent.cn/p/13cf01cdb81f

axios與fetch、ajax區(qū)別?

(1)fetch和axios差不多,都是基于promise的,fetch沒有封裝xhr(ajax的原生對(duì)象),是新的語法,默認(rèn)不傳cookie,也監(jiān)聽不到請(qǐng)求的進(jìn)度,axios可以監(jiān)聽到請(qǐng)求的進(jìn)度。

(2)axios返回一個(gè)promise對(duì)象,拿到對(duì)象之后再去.then可以拿到resolve之后的內(nèi)容。

axios.get(url,{params:{}}).then(res=>{}).catch(err=>{}); 
axios.post(url,{}).then(res=>).catch(err=>{});

(3)ajax主要是利用callback回調(diào)函數(shù)的形式。

JQuery中的ajax:$.ajax({url,data,success(){}}) 在回調(diào)函數(shù)獲取數(shù)據(jù)

axios 和 ajax 的使用方法基本一樣,只有個(gè)別參數(shù)不同;

axios({
            url: 'http://jsonplaceholder.typicode.com/users',
            method: 'get',
            responseType: 'json', // 默認(rèn)的
            data: {
                //'a': 1,
                //'b': 2,
            }
        }).then(function (response) {
            console.log(response);
            console.log(response.data);
        }).catch(function (error) {
            console.log(error);
        })
$.ajax({
            url: 'http://jsonplaceholder.typicode.com/users',
            type: 'get',
            dataType: 'json',
            data: {
                //'a': 1,
                //'b': 2,
            },
            success: function (response) {
                console.log(response);
            }
        })

參考:ajax和axios、fetch的區(qū)別

http://m.itdecent.cn/p/8bc48f8fde75

JSON

什么是 JSON ?

  • JSON 指的是 JavaScript 對(duì)象表示法(JavaScript Object Notation)
  • JSON 是輕量級(jí)的文本數(shù)據(jù)交換格式
  • JSON 獨(dú)立于語言:JSON 使用 Javascript語法來描述數(shù)據(jù)對(duì)象,但是 JSON 仍然獨(dú)立于語言和平臺(tái)。JSON 解析器和 JSON 庫支持許多不同的編程語言。 目前非常多的動(dòng)態(tài)(PHP,JSP,.NET)編程語言都支持JSON。
  • JSON 具有自我描述性,更易理解

與 XML 相同之處

  • JSON 是純文本
  • JSON 具有"自我描述性"(人類可讀)
  • JSON 具有層級(jí)結(jié)構(gòu)(值中存在值)
  • JSON 可通過 JavaScript 進(jìn)行解析
  • JSON 數(shù)據(jù)可使用 AJAX 進(jìn)行傳輸

與 XML 不同之處

  • 沒有結(jié)束標(biāo)簽
  • 更短
  • 讀寫的速度更快
  • 能夠使用內(nèi)建的 JavaScript eval() 方法進(jìn)行解析
  • 使用數(shù)組
  • 不使用保留字

為什么使用 JSON?

對(duì)于 AJAX 應(yīng)用程序來說,JSON 比 XML 更快更易使用:

使用 XML

  • 讀取 XML 文檔
  • 使用 XML DOM 來循環(huán)遍歷文檔
  • 讀取值并存儲(chǔ)在變量中

使用 JSON

  • 讀取 JSON 字符串
  • 用 eval() 處理 JSON 字符串

js中想要把json字符串轉(zhuǎn)化為js對(duì)象的方式

  1. JSON.parse()

  2. eval()

假設(shè)我們有一個(gè)json字符串

          var str = '{"friends":[{"name":"梅梅","age":29,"sex":"女"},' +
                '{"name":"李華","age":18,"sex":"男"}]' +
                '}';

使用 JSON.parse()方法來轉(zhuǎn)化

     var str = '{"friends":[{"name":"梅梅","age":29,"sex":"女"},' +
            '{"name":"李華","age":18,"sex":"男"}]' +
            '}';
    JSON.parse(str);

使用 eval()方法傳化:

    var str = '{"friends":[{"name":"梅梅","age":29,"sex":"女"},' +
            '{"name":"李華","age":18,"sex":"男"}]' +
            '}';
    eval('('+str+')');

注意點(diǎn): 通過 eval 來轉(zhuǎn)化,如果返回的字符串內(nèi)容是一個(gè)數(shù)組,可以直接轉(zhuǎn)化,如果返回的字符串內(nèi)容是一個(gè)對(duì)象,必須在字符串的前后加上()

當(dāng)字符串內(nèi)容是一個(gè)數(shù)組時(shí) ,eval()的轉(zhuǎn)化方式:

    var arr = '[{"name":"唐老鴨","sex":"男"},{"name":"紅太狼","sex":"女"}]';
    eval(arr);

JSON.parse() 和 eval() 的區(qū)別

  1. eval方法不會(huì)去檢查給的字符串是否符合json的格式,而JSON.parse解析不滿足json格式的字符串時(shí),會(huì)報(bào)錯(cuò)。

  2. 如果給的字符串中存在js代碼eval也會(huì)一并執(zhí)行,比如下面的代碼段:

        var str1 = '{"log":alert("我被會(huì)執(zhí)行的")}';
        eval("("+str1+")");

執(zhí)行該代碼片段,會(huì)將 alert 語句作為js代碼來執(zhí)行,如果我們?cè)陂_發(fā)中建議使用JSON.parse來轉(zhuǎn)化,這樣可以避免很多隱患,比如,我們?cè)L問第三方提供的接口,返回的串中包含 window.location.href這樣的內(nèi)容,那么執(zhí)行了就會(huì)跳轉(zhuǎn)到不明網(wǎng)站,好危險(xiǎn),所以最好還是使用JSON.parse()來解析。

JSON.parse()

JSON 通常用于與服務(wù)端交換數(shù)據(jù)。

在接收服務(wù)器數(shù)據(jù)時(shí)一般是字符串。

我們可以使用 JSON.parse() 方法將數(shù)據(jù)轉(zhuǎn)換為 JavaScript 對(duì)象。

JSON.parse(text[, reviver])

JSON.stringify()

JSON 通常用于與服務(wù)端交換數(shù)據(jù)。

在向服務(wù)器發(fā)送數(shù)據(jù)時(shí)一般是字符串。

我們可以使用 JSON.stringify() 方法將 JavaScript 對(duì)象轉(zhuǎn)換為字符串。

JSON.stringify(value[, replacer[, space]])

Promise

同步異步函數(shù)的區(qū)別

同步:阻塞,當(dāng)前程序必須等前面一個(gè)程序執(zhí)行完畢以后,才能夠執(zhí)行。

異步:非阻塞,前一個(gè)程序是否執(zhí)行完畢,不影響后面程序的執(zhí)行。

promise、async、await

async函數(shù)返回的是一個(gè) Promise 對(duì)象,可以使用 then 方法添加回調(diào)函數(shù),async 函數(shù)內(nèi)部 return 語句返回的值,會(huì)成為 then 方法回調(diào)函數(shù)的參數(shù)。當(dāng)函數(shù)執(zhí)行的時(shí)候,一旦遇到await就會(huì)先返回,等到異步操作完成,再接著執(zhí)行函數(shù)體內(nèi)后面的語句。

await只能用在異步函數(shù)中,使用await必須要先使用async,命令后面返回的是Promise對(duì)象,運(yùn)行結(jié)果可能是rejected,所以最好把a(bǔ)wait命令放在try...catch代碼塊中。

Promise的概念

我理解的Promise就是一套為處理異步情況的方法。先創(chuàng)建一個(gè)promise對(duì)象來注冊(cè)一個(gè)委托,其中包括委托成功及失敗后的處理函數(shù)。然后基于這種表述方式,來將promise應(yīng)用到各種異步處理的情況中。

promise寫法案例

var promise = getAsyncPromise('fileA.txt');
promise.then( function(result){
      // 成功時(shí)的處理辦法
}).catch( function(error){
      // 失敗時(shí)的處理辦法
})

// 返回一個(gè)promise對(duì)象

promise三個(gè)狀態(tài)

pending(進(jìn)行中)、fulfilled(已成功)和rejected(已失?。?/p>

Promise 實(shí)際就是一個(gè)對(duì)象, 從它可以獲得異步操作的消息,Promise 對(duì)象有三種狀態(tài),pending(進(jìn)行中)、fulfilled(已成功)和rejected(已失?。?。Promise 的狀態(tài)一旦改變之后,就不會(huì)在發(fā)生任何變化,將回調(diào)函數(shù)變成了鏈?zhǔn)秸{(diào)用。

Promise的設(shè)計(jì)思想是,所有異步任務(wù)都返回一個(gè)Promise實(shí)例。Promise實(shí)例有一個(gè)then方法,用來指定下一步的回調(diào)函數(shù)。

總的來說,傳統(tǒng)的回調(diào)函數(shù)寫法使得代碼混成一團(tuán),變得橫向發(fā)展而不是向下發(fā)展。Promise就是解決這個(gè)問題,使得異步流程可以寫成同步流程。

Promise構(gòu)造函數(shù)

JavaScript 提供原生的Promise構(gòu)造函數(shù),用來生成 Promise 實(shí)例。

var promise = new Promise(function (resolve, reject) {
  // ...

  if (/* 異步操作成功 */){
    resolve(value);
  } else { /* 異步操作失敗 */
    reject(new Error());
  }
});

上面代碼中,Promise構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是resolve和reject。它們是兩個(gè)函數(shù),由JavaScript引擎提供,不用自己實(shí)現(xiàn)。

resolve函數(shù)的作用是,將Promise實(shí)例的狀態(tài)從"未完成"變?yōu)?成功"(即從pending變?yōu)閒ulfilled),在異步操作成功時(shí)調(diào)用,并將異步操作的結(jié)果,作為參數(shù)傳遞出去。reject函數(shù)的作用是,將Promise實(shí)例的狀態(tài)從"未完成"變?yōu)?失敗"(即從pending變?yōu)閞ejected),在異步失敗時(shí)調(diào)用,并將異步操作報(bào)出的錯(cuò)誤,作為參數(shù)傳遞出去。

Promise的優(yōu)缺點(diǎn)

Promise 的優(yōu)點(diǎn)在于,讓回調(diào)函數(shù)變成了規(guī)范的鏈?zhǔn)綄懛?,程序流程可以看得很清楚。它有一整套接口,可以?shí)現(xiàn)許多強(qiáng)大的功能,比如同時(shí)執(zhí)行多個(gè)異步操作,等到它們的狀態(tài)都改變以后,再執(zhí)行一個(gè)回調(diào)函數(shù);再比如,為多個(gè)回調(diào)函數(shù)中拋出的錯(cuò)誤,統(tǒng)一指定處理方法等等。

而且,Promise 還有一個(gè)傳統(tǒng)寫法沒有的好處:它的狀態(tài)一旦改變,無論何時(shí)查詢,都能得到這個(gè)狀態(tài)。這意味著,無論何時(shí)為 Promise 實(shí)例添加回調(diào)函數(shù),該函數(shù)都能正確執(zhí)行。所以,你不用擔(dān)心是否錯(cuò)過了某個(gè)事件或信號(hào)。如果是傳統(tǒng)寫法,通過監(jiān)聽事件來執(zhí)行回調(diào)函數(shù),一旦錯(cuò)過了事件,再添加回調(diào)函數(shù)是不會(huì)執(zhí)行的。

Promise 的缺點(diǎn)是,編寫的難度比傳統(tǒng)寫法高,而且閱讀代碼也不是一眼可以看懂。你只會(huì)看到一堆then,必須自己在then的回調(diào)函數(shù)里面理清邏輯。

Promise的優(yōu)點(diǎn)

promise優(yōu)點(diǎn)主要解決回調(diào)地獄問題,使得原本的多層級(jí)的嵌套代碼,變成了鏈?zhǔn)秸{(diào)用,讓代碼更清晰,減少嵌套數(shù)。

Promise的缺點(diǎn)

首先,無法取消Promise,一旦新建它就會(huì)立即執(zhí)行,無法中途取消。其次,如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯(cuò)誤,不會(huì)反應(yīng)到外部。當(dāng)處于Pending狀態(tài)時(shí),無法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成)。

Promise的all方法

all方法是promise是類上自帶的方法,并發(fā)讀取,失敗一個(gè)都失敗了,時(shí)間只是一個(gè)讀取的時(shí)間

第一個(gè)參數(shù) 傳遞的是數(shù)組,數(shù)組裝的是一個(gè)個(gè)promise對(duì)象

調(diào)用后會(huì)再次返回一個(gè)promise實(shí)例

最好的寫法

Promise.all([read('./name.txt'),read('./age.txt')]).then(([name,age])=>{
//data就是promise執(zhí)行成功的結(jié)果類型是數(shù)組
    console.log({name,age});
}).catch((err)=>{
    console.log(err)
})

Promise的race方法

Promise.race ([promise1,promise2..])

當(dāng)參數(shù)里的任意一個(gè)promise成功或失敗后,該函數(shù)就會(huì)返回,并使用這個(gè)promise對(duì)象的值進(jìn)行resolve或reject

    let promise1 = ajax({method:'GET',url:'/x.json'});
    let promise2 = ajax({method:'GET',url:'/y.json'});
    Promise.all([promise1,promise2]).then(function(){
        console.log('兩個(gè)promise都執(zhí)行完成了')
    });
    Promise.race([promise1,promise2]).then(function(){
        console.log('有一個(gè)promise先執(zhí)行完成了')
    })

參考:簡單理解Promise

http://m.itdecent.cn/p/c8f9fba03df9

存儲(chǔ)

本地存儲(chǔ)(Local Storage )和cookies(儲(chǔ)存在用戶本地終端上的數(shù)據(jù))之間的區(qū)別是什么?

Cookies:服務(wù)器和客戶端都可以訪問;大小只有4KB左右;有有效期,過期后將會(huì)刪除;

本地存儲(chǔ):只有本地瀏覽器端可訪問數(shù)據(jù),服務(wù)器不能訪問本地存儲(chǔ),直到故意通過POST或者GET的通道發(fā)送到服務(wù)器;每個(gè)域5MB;沒有過期數(shù)據(jù),它將保留直到用戶從瀏覽器清除或者使用Javascript代碼移除。

cookie  4kb 隨http請(qǐng)求發(fā)送到服務(wù)端 后端可以幫助前端設(shè)置cookie 
session 放在服務(wù)端  一般存放用戶比較重要的信息
        (token 令牌  token ==> cookie /localstorage)  vuex

localStorage 本地存儲(chǔ)(h5的新特性 draggable canvas svg)
             5M     純粹在本地客戶端  多個(gè)標(biāo)簽頁共享數(shù)據(jù)
             sessionStorage  會(huì)話級(jí)別的存儲(chǔ)
             往本地頁面中存值的方法(localStorage.setItem(key,value))

講一下cookie、sessionstorage、localstorage

相同點(diǎn):都存儲(chǔ)在客戶端

不同點(diǎn):

1.存儲(chǔ)大小

  • cookie數(shù)據(jù)大小不能超過4k。
  • sessionStorage和localStorage 雖然也有存儲(chǔ)大小的限制,但比cookie大得多,可以達(dá)到5M或更大。

2.有效時(shí)間

  • localStorage 存儲(chǔ)持久數(shù)據(jù),瀏覽器關(guān)閉后數(shù)據(jù)不丟失除非主動(dòng)刪除數(shù)據(jù);
  • sessionStorage 數(shù)據(jù)在當(dāng)前瀏覽器窗口關(guān)閉后自動(dòng)刪除。
  • cookie 設(shè)置的cookie過期時(shí)間之前一直有效,即使窗口或?yàn)g覽器關(guān)閉

3.數(shù)據(jù)與服務(wù)器之間的交互方式

  • cookie的數(shù)據(jù)會(huì)自動(dòng)的傳遞到服務(wù)器,服務(wù)器端也可以寫cookie到客戶端
  • sessionStorage和localStorage不會(huì)自動(dòng)把數(shù)據(jù)發(fā)給服務(wù)器,僅在本地保存。

定義一個(gè)對(duì)象,里面包含用戶名、電話,然后將其存入localStorage的代碼

var json = {username:"張三",phone:17650246248}
for(var key in json){
    localStorage.setItem(key,json[key]);
}

cookie和session的區(qū)別

  1. 保持狀態(tài):cookie保存在瀏覽器端,session保存在服務(wù)器端

  2. 使用方式:如果不在瀏覽器中設(shè)置過期時(shí)間,cookie被保存在內(nèi)存中,生命周期隨瀏覽器的關(guān)閉而結(jié)束,這種cookie簡稱會(huì)話cookie。如果在瀏覽器中設(shè)置了cookie的過期時(shí)間,cookie被保存在硬盤中,關(guān)閉瀏覽器后,cookie數(shù)據(jù)仍然存在,直到過期時(shí)間結(jié)束才消失。

  3. 存儲(chǔ)內(nèi)容:cookie只能保存字符串類型,以文本的方式;session通過類似與Hashtable的數(shù)據(jù)結(jié)構(gòu)來保存,能支持任何類型的對(duì)象(session中可含有多個(gè)對(duì)象)

  4. 存儲(chǔ)的大小:cookie:單個(gè)cookie保存的數(shù)據(jù)不能超過4kb;session大小沒有限制。

  5. 安全性:cookie:針對(duì)cookie所存在的攻擊:Cookie欺騙,Cookie截獲;session的安全性大于cookie。

  6. 應(yīng)用場(chǎng)景:

cookie:(1)判斷用戶是否登陸過網(wǎng)站,以便下次登錄時(shí)能夠?qū)崿F(xiàn)自動(dòng)登錄(或者記住密碼)。如果我們刪除cookie,則每次登錄必須從新填寫登錄的相關(guān)信息。

(2)保存上次登錄的時(shí)間等信息。

(3)保存上次查看的頁面

(4)瀏覽計(jì)數(shù)

session:Session用于保存每個(gè)用戶的專用信息,變量的值保存在服務(wù)器端,通過SessionID來區(qū)分不同的客戶。

(1)網(wǎng)上商城中的購物車

(2)保存用戶登錄信息

(3)將某些數(shù)據(jù)放入session中,供同一用戶的不同頁面使用

(4)防止用戶非法登錄

  1. 缺點(diǎn):

    cookie:

    (1)大小受限

    (2)用戶可以操作(禁用)cookie,使功能受限

    (3)安全性較低

    (4)有些狀態(tài)不可能保存在客戶端。

    (5)每次訪問都要傳送cookie給服務(wù)器,浪費(fèi)帶寬。

    (6)cookie數(shù)據(jù)有路徑(path)的概念,可以限制cookie只屬于某個(gè)路徑。

session:

(1)Session保存的東西越多,就越占用服務(wù)器內(nèi)存,對(duì)于用戶在線人數(shù)較多的網(wǎng)站,服務(wù)器的內(nèi)存壓力會(huì)比較大。

(2)依賴于cookie(sessionID保存在cookie),如果禁用cookie,則要使用URL重寫,不安全

(3)創(chuàng)建Session變量有很大的隨意性,可隨時(shí)調(diào)用,不需要開發(fā)者做精確地處理,所以,過度使用session變量將會(huì)導(dǎo)致代碼不可讀而且不好維護(hù)。

WebStorage

WebStorage的目的是克服由cookie所帶來的一些限制,當(dāng)數(shù)據(jù)需要被嚴(yán)格控制在客戶端時(shí),不需要持續(xù)的將數(shù)據(jù)發(fā)回服務(wù)器。

WebStorage兩個(gè)主要目標(biāo):

(1)提供一種在cookie之外存儲(chǔ)會(huì)話數(shù)據(jù)的路徑。

(2)提供一種存儲(chǔ)大量可以跨會(huì)話存在的數(shù)據(jù)的機(jī)制。

Localstroage與SessionStorage存儲(chǔ)的區(qū)別

HTML5的WebStorage提供了兩種API:localStorage(本地存儲(chǔ))和sessionStorage(會(huì)話存儲(chǔ))。

  1. 生命周期:localStorage:localStorage的生命周期是永久的,關(guān)閉頁面或?yàn)g覽器之后localStorage中的數(shù)據(jù)也不會(huì)消失。

localStorage除非主動(dòng)刪除數(shù)據(jù),否則數(shù)據(jù)永遠(yuǎn)不會(huì)消失。

sessionStorage的生命周期是在僅在當(dāng)前會(huì)話下有效。sessionStorage引入了一個(gè)“瀏覽器窗口”的概念,sessionStorage是在同源的窗口中始終存在的數(shù)據(jù)。只要這個(gè)瀏覽器窗口沒有關(guān)閉,即使刷新頁面或者進(jìn)入同源另一個(gè)頁面,數(shù)據(jù)依然存在。但是sessionStorage在關(guān)閉了瀏覽器窗口后就會(huì)被銷毀。同時(shí)獨(dú)立的打開同一個(gè)窗口同一個(gè)頁面,sessionStorage也是不一樣的。

  1. 存儲(chǔ)大?。簂ocalStorage和sessionStorage的存儲(chǔ)數(shù)據(jù)大小一般都是:5MB

  2. 存儲(chǔ)位置:localStorage和sessionStorage都保存在客戶端,不與服務(wù)器進(jìn)行交互通信。

  3. 存儲(chǔ)內(nèi)容類型:localStorage和sessionStorage只能存儲(chǔ)字符串類型,對(duì)于復(fù)雜的對(duì)象可以使用ECMAScript提供的JSON對(duì)象的stringify和parse來處理

  4. 獲取方式:localStorage:window.localStorage;;sessionStorage:window.sessionStorage;。

  5. 應(yīng)用場(chǎng)景:localStoragese:常用于長期登錄(+判斷用戶是否已登錄),適合長期保存在本地的數(shù)據(jù)。sessionStorage:敏感賬號(hào)一次性登錄;

WebStorage的優(yōu)點(diǎn)

  1. 存儲(chǔ)空間更大:cookie為4KB,而WebStorage是5MB;

  2. 節(jié)省網(wǎng)絡(luò)流量:WebStorage不會(huì)傳送到服務(wù)器,存儲(chǔ)在本地的數(shù)據(jù)可以直接獲取,也不會(huì)像cookie一樣美詞請(qǐng)求都會(huì)傳送到服務(wù)器,所以減少了客戶端和服務(wù)器端的交互,節(jié)省了網(wǎng)絡(luò)流量;

  3. 對(duì)于那種只需要在用戶瀏覽一組頁面期間保存而關(guān)閉瀏覽器后就可以丟棄的數(shù)據(jù),sessionStorage會(huì)非常方便;

  4. 快速顯示:有的數(shù)據(jù)存儲(chǔ)在WebStorage上,再加上瀏覽器本身的緩存。獲取數(shù)據(jù)時(shí)可以從本地獲取會(huì)比從服務(wù)器端獲取快得多,所以速度更快;

  5. 安全性:WebStorage不會(huì)隨著HTTP header發(fā)送到服務(wù)器端,所以安全性相對(duì)于cookie來說比較高一些,不會(huì)擔(dān)心截獲,但是仍然存在偽造問題;

  6. WebStorage提供了一些方法,數(shù)據(jù)操作比cookie方便;

WebStorage的方法

setItem (key, value) —— 保存數(shù)據(jù),以鍵值對(duì)的方式儲(chǔ)存信息。

getItem (key) —— 獲取數(shù)據(jù),將鍵值傳入,即可獲取到對(duì)應(yīng)的value值。

removeItem (key) —— 刪除單個(gè)數(shù)據(jù),根據(jù)鍵值移除對(duì)應(yīng)的信息。

clear () —— 刪除所有的數(shù)據(jù)

key (index) —— 獲取某個(gè)索引的key

Token

token是"令牌"的意思,服務(wù)端生成一串字符串,作為客戶端請(qǐng)求的一段標(biāo)識(shí)。用戶登錄的時(shí)候生成一個(gè)token,并將token返回客戶端,客戶端將收到的token放在cookie里,下次用戶向服務(wù)端發(fā)送請(qǐng)求的時(shí)候,服務(wù)端只需要對(duì)比token。

作用:進(jìn)行身份驗(yàn)證,避免表單重復(fù)提交。

在ajax請(qǐng)求后臺(tái)時(shí)token添加到哪里

在ajax請(qǐng)求的標(biāo)頭中加Token

 1 function GetDateForServiceCustomer(userId) {
 2     $.ajax({
 3         url: 'http://*******/api/orders',
 4         data: {
 5             currUserId: userId,
 6             type: 1
 7         },
 8         beforeSend: function(request) {
 9             request.setRequestHeader("Authorization", token);
10         },
11         dataType: 'JSON',
12         async: false,//請(qǐng)求是否異步,默認(rèn)為異步
13         type: 'GET',
14         success: function (list) {
15         },
16         error: function () {
17         }
18     });
19 }
image

參考:在ajax請(qǐng)求后臺(tái)時(shí)在請(qǐng)求標(biāo)頭RequestHeader加token

https://www.cnblogs.com/zfdcp-028/p/6374632.html

協(xié)議

HTTPS與HTTP的一些區(qū)別

  • HTTPS協(xié)議需要到CA申請(qǐng)證書,一般免費(fèi)證書很少,需要交費(fèi)。
  • HTTP協(xié)議運(yùn)行在TCP之上,所有傳輸?shù)膬?nèi)容都是明文,HTTPS運(yùn)行在SSL/TLS之上,SSL/TLS運(yùn)行在TCP之上,所有傳輸?shù)膬?nèi)容都經(jīng)過加密的。
  • HTTP和HTTPS使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443。
  • HTTPS可以有效的防止運(yùn)營商劫持,解決了防劫持的一個(gè)大問題。

HTTP1.0和HTTP2.0有什么區(qū)別

新的二進(jìn)制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本協(xié)議的格式解析存在天然缺陷,文本的表現(xiàn)形式有多樣性,要做到健壯性考慮的場(chǎng)景必然很多,二進(jìn)制則不同,只認(rèn)0和1的組合?;谶@種考慮HTTP2.0的協(xié)議解析決定采用二進(jìn)制格式,實(shí)現(xiàn)方便且健壯。

多路復(fù)用(MultiPlexing),即連接共享,即每一個(gè)request都是是用作連接共享機(jī)制的。一個(gè)request對(duì)應(yīng)一個(gè)id,這樣一個(gè)連接上可以有多個(gè)request,每個(gè)連接的request可以隨機(jī)的混雜在一起,接收方可以根據(jù)request的 id將request再歸屬到各自不同的服務(wù)端請(qǐng)求里面。

header壓縮,如上文中所言,對(duì)前面提到過HTTP1.x的header帶有大量信息,而且每次都要重復(fù)發(fā)送,HTTP2.0使用encoder來減少需要傳輸?shù)膆eader大小,通訊雙方各自cache一份header fields表,既避免了重復(fù)header的傳輸,又減小了需要傳輸?shù)拇笮 ?/p>

服務(wù)端推送(server push),同SPDY一樣,HTTP2.0也具有server push功能。

參考:HTTP1.0、HTTP1.1 和 HTTP2.0 的區(qū)別

https://www.cnblogs.com/heluan/p/8620312.html

Websocket

WebSocket 是 HTML5 開始提供的一種在單個(gè) TCP 連接上進(jìn)行全雙工通訊的協(xié)議。

WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動(dòng)向客戶端推送數(shù)據(jù)。在 WebSocket API 中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸。

在 WebSocket API 中,瀏覽器和服務(wù)器只需要做一個(gè)握手的動(dòng)作,然后,瀏覽器和服務(wù)器之間就形成了一條快速通道。兩者之間就直接可以數(shù)據(jù)互相傳送。

現(xiàn)在,很多網(wǎng)站為了實(shí)現(xiàn)推送技術(shù),所用的技術(shù)都是 Ajax 輪詢。輪詢是在特定的的時(shí)間間隔(如每1秒),由瀏覽器對(duì)服務(wù)器發(fā)出HTTP請(qǐng)求,然后由服務(wù)器返回最新的數(shù)據(jù)給客戶端的瀏覽器。這種傳統(tǒng)的模式帶來很明顯的缺點(diǎn),即瀏覽器需要不斷的向服務(wù)器發(fā)出請(qǐng)求,然而HTTP請(qǐng)求可能包含較長的頭部,其中真正有效的數(shù)據(jù)可能只是很小的一部分,顯然這樣會(huì)浪費(fèi)很多的帶寬等資源。

HTML5 定義的 WebSocket 協(xié)議,能更好的節(jié)省服務(wù)器資源和帶寬,并且能夠更實(shí)時(shí)地進(jìn)行通訊。

WebSocket特點(diǎn)

(1)建立在 TCP 協(xié)議之上,服務(wù)器端的實(shí)現(xiàn)比較容易。
(2)與 HTTP 協(xié)議有著良好的兼容性。默認(rèn)端口也是80和443,并且握手階段采用 HTTP 協(xié)議,因此握手時(shí)不容易屏蔽,能通過各種 HTTP 代理服務(wù)器。
(3)數(shù)據(jù)格式比較輕量,性能開銷小,通信高效。
(4)可以發(fā)送文本,也可以發(fā)送二進(jìn)制數(shù)據(jù)。
(5)沒有同源限制,客戶端可以與任意服務(wù)器通信。
(6)協(xié)議標(biāo)識(shí)符是ws(如果加密,則為wss),服務(wù)器網(wǎng)址就是 URL。

scoket套接字編程

網(wǎng)絡(luò)上的兩個(gè)程序通過一個(gè)雙向的通信連接實(shí)現(xiàn)數(shù)據(jù)的交換,這個(gè)連接的一端稱為一個(gè)socket。
如果將http比作轎車的話,那么socket就相當(dāng)于發(fā)動(dòng)機(jī)。

websocket跟 socket 的區(qū)別

軟件通信有七層結(jié)構(gòu),下三層結(jié)構(gòu)偏向與數(shù)據(jù)通信,上三層更偏向于數(shù)據(jù)處理,中間的傳輸層則是連接上三層與下三層之間的橋梁,每一層都做不同的工作,上層協(xié)議依賴與下層協(xié)議。基于這個(gè)通信結(jié)構(gòu)的概念。

Socket 其實(shí)并不是一個(gè)協(xié)議,是應(yīng)用層與 TCP/IP 協(xié)議族通信的中間軟件抽象層,它是一組接口。當(dāng)兩臺(tái)主機(jī)通信時(shí),讓 Socket 去組織數(shù)據(jù),以符合指定的協(xié)議。TCP 連接則更依靠于底層的 IP 協(xié)議,IP 協(xié)議的連接則依賴于鏈路層等更低層次。

WebSocket 則是一個(gè)典型的應(yīng)用層協(xié)議。

總的來說:Socket 是傳輸控制層協(xié)議,WebSocket 是應(yīng)用層協(xié)議。

webScoket如何兼容低瀏覽器

  1. Adobe Flash Socket
  2. ActiveX HTMLFile (IE)
  3. 基于 multipart 編碼發(fā)送 XHR
  4. 基于長輪詢的 XHR

參考:WebSocket解釋及如何兼容低版本瀏覽器

https://www.cnblogs.com/pengc/p/8718380.html

模塊化開發(fā)

模塊、函數(shù)、組件分別是什么?

模塊:在webpack中,通過import引入的文件叫做模塊。(js/css/png)
函數(shù):是一些功能的合集。
組件:指的是頁面的某一部分。

類是什么?類被編譯成什么?

類:

class Banner extends React.Component{ //es6寫法
    

}

ES5:通過模塊定義類 ES6中定義的類也被編譯成這樣

function  Banner(){ //構(gòu)造函數(shù)
    
}

組件化與模塊化的區(qū)別,或者說怎么實(shí)現(xiàn)組件化開發(fā),模塊化開發(fā)

組件化:針對(duì)的是頁面中的整個(gè)完整的功能模塊,劃分成瀏覽器可以識(shí)別的每個(gè)模塊,例如頭部Header、底部Footer、Banner。優(yōu)點(diǎn):代碼復(fù)用、便于維護(hù)。

模塊化:就是系統(tǒng)功能分離或獨(dú)立的功能部分的方法,一般指的是單一的某個(gè)東西,例如:js、css

模塊化開發(fā)的規(guī)范

(1)commonJS:自上而下同步進(jìn)行 會(huì)阻塞 用在服務(wù)端

使用模塊:const 變量名 = require("包名字")

聲明模塊:module.exports = {

對(duì)外的名字:函數(shù)

}

(2)AMD:異步加載文件 不會(huì)阻塞 用在瀏覽器端

define方法用于定義模塊,RequireJS要求每個(gè)模塊放在一個(gè)單獨(dú)的文件里。

使用模塊:require("模塊名",function(模塊對(duì)象)){

return 模塊對(duì)象.函數(shù)();//回調(diào)函數(shù)

}

(3)CMD規(guī)范 中國人發(fā)明的,ECMA6來了就廢棄了。

amd和cmd的區(qū)別

amd是require.js上的一個(gè)規(guī)范,cmd是sea.js的一個(gè)規(guī)范。

其實(shí)CMD與AMD規(guī)范并沒什么本質(zhì)的區(qū)別,區(qū)別在于他們對(duì)依賴模塊的執(zhí)行時(shí)機(jī)處理不同。雖然兩者都是異步加載模塊,但是AMD依賴前置,js可以方便知道依賴模塊是誰,要依賴什么js那就先加載進(jìn)來,至于你要依賴這些js來干嗎得先等著,等我加載完了資源再商量;而CMD就近依賴,需要使用這個(gè)依賴模塊時(shí),我再加載進(jìn)來用。

這就好比什么呢?就好像我今晚要看5集三國演義。AMD是先打開五個(gè)窗口,分別是1~5集,都緩沖著先,反正等下每集我都要看的;CMD則是先打開第一集的窗口,等到我第一集看完了,想看第二集了,就再跳轉(zhuǎn)到第二集。

現(xiàn)在使用頻率最高的,也是大家公認(rèn)的好的模塊化規(guī)范,是CommonJS。 后端(node.js)

require.js

實(shí)現(xiàn)了AMD規(guī)范的JavaScript工具庫

RequireJS的基本思想是,通過define方法,將代碼定義為模塊;通過require方法,實(shí)現(xiàn)代碼的模塊加載。

require.js的誕生,就是為了解決這兩個(gè)問題:

(1)實(shí)現(xiàn)了js文件的異步加載,避免網(wǎng)頁失去響應(yīng)

(2)管理模塊之間的依賴性,便于代碼的編寫和維護(hù)

common.js

CommonJS就很簡單了,一個(gè)js文件要輸出去,只需使用module.export={xxx:你要輸出的內(nèi)容},而在另外一個(gè)js中,你要引用什么,就通過var xxxx=require("xxxx")引用進(jìn)來就行了,這玩意并不是異步加載模塊,而是同步一次性加載出來。

common.js與require.js與sea.js的區(qū)別:

image
image

配置模塊化開發(fā)

<1>在頭部引入

<script scr = "js/require.js" defer async = "true" data-main = "js/main"></script>

main.js管理當(dāng)前頁面的js文件,每一個(gè)頁面都有自己的不同名字的main.js文件.

路徑以dist文件為主

在外部修改文件,不允許修改dist中的文件,gulp會(huì)自動(dòng)同步修改.

<2>在main中通過require.config配置當(dāng)前頁面需要的模塊路徑

配置模塊的依賴路徑:

shim:{

//由于jquery-cookie是基于jquery庫封裝的,所以要先引入jquery再引入jquery-cookie

"jquery-cookie":['jquery'],

//聲明一下,不是AMD規(guī)范的模塊

"parabola":{

exports:"_"

}

}

<3>編寫CSS樣式/JS代碼

編寫JS代碼:

  1. 先封裝成函數(shù)

  2. 再通過對(duì)象的形式對(duì)外暴露

define(["jquery"],function($){

function slide(){ 

$(function(){

function show(){ 

console.log("hello world");

}

return{

slide:slide,

show:show

}

})

<4>在main.js中加載

//配置當(dāng)前整個(gè)項(xiàng)目所有模塊的路徑

require.config({

paths:{

"slide":"slide"

},



require(["slide"],function(slide){

slide.show();

slide.slide();

})
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容