web進階筆記

數據類型都有哪些

原始值數據類型【值類型、基本數據類型】

  • number 數字
  • string 字符串
  • boolean 布爾
  • null 空對象指針
  • undefined 未定義
  • bigint 大數

對象類型【引用數據類型】

  • 標準普通對象 object
  • 標準特殊對象 Array、RegExp、Data、Math、Error...
  • 非標準特殊對象 Number、String、Boolean...
  • 可調用/執行對象 function

數據檢測有哪些方法

typeof

  • typeof返回值永遠是字符串。
    • typeof typeof typeof 'nihao'返回結果是'string'
  • typeof bull 返回值是'object'
  • typeof function 返回值'function'
  • typeof n檢測一個未被聲明的變量,返回值是'undefined'
  • 按照計算機底層的存儲的二進制進行檢測【效率高】
    • 000開頭表明對象
    • 1 開始的表明數字
    • 010 開頭表明浮點數(有小數點)
    • 100 開始的表明字符串
    • 110 開始表明布爾
    • 0000000 開頭表明null,這就是null檢測是object的緣由。
    • -2^30 表明undefined

typeof底層處理機制

instanceof

constructor

object.prototype.toString.call

JS底層存儲機制:堆(Heap)、棧(Stack)內存

  • 當瀏覽器去加載渲染頁面【開一個頁卡】,首先會從計算機內存條中分配出兩塊內存。(堆棧內存)

棧內存(ECStack執行環境棧)

棧內存做用

  • 供代碼執行
    • 最開始,要執行的全局下的代碼,先造成一個全局執行上下文(EC(G)),而後進棧執行
  • 存放聲明的變量
  • 存放原始值類型
  • 存放全局執行上下文,函數私有上下文,塊級私有上下文
    • 全局上下文建立時間:打開頁面,執行全局代碼就會造成,頁面關閉的時候纔會釋放,或者是按F5刷新,至關於刪掉以前的全局上下文,從新生成新的全局上下文。
    • 私有上下文是在代碼執行到函數或者塊級做用域時生成,這個函數或者塊級做用域代碼執行完後,就會當即釋放。因此函數每執行一次就會生成一個新的私有上下文(也叫活動對象)

堆內存

堆內存做用

  • 存放對象數據類型值
  • 放置瀏覽器(window)的內置API(全局對象global object)簡稱GO內存空間,例如setTimeout、alert。

建立變量時發生的事情

  • var 變量 = 值
    • 先建立值
      • 原始值直接存儲到棧內存中
      • 對象值須要在堆內存中出,開闢出一塊空間來,(16進制地址),在空間中存儲對象的鍵值對,最後把地址放到棧內存中,供變量引入。
    • 聲明變量
      • 把聲明的變量存儲到當前上下文的變量對象中
    • 賦值(定義)操做
      • 讓變量和對應的值關聯在一塊兒(指針指向過程)
  • 注意
    • 基於var/function聲明的變量值不是存放到VO(全局變量對象,這個是在棧內存),而是放在了GO(全局對象,這個是堆內存),就至關於給window設置了對應的屬性,好比var a = 13;他會在GO中建立a:13鍵值和對應的地址,而後將這個地址賦值到VO中的變量a。我們能夠經過window.a拿到a的值。
    • 基於let/const/class聲明的變量,是純正血統的全局變量,存放到VO中,和GO是沒有關係的。
    • 沒有任何聲明的變量,也至關因而給全局變量對象(GO)設置了一個屬性。
      var a = 13;
      console.log(a,window.a)// 13 13
      let b = 15;
      console.log(b,window.b)// 15 undefined
      d = 15  //等於window.d
      //注:在全局上下文中,使用一個變量,首先看是不是VO中,若是不是則看GO,若是尚未就未定義錯誤。
      複製代碼

閉包做用域和瀏覽器垃圾回收機制(GC)

常見的瀏覽器垃圾回收機制有兩種方法

第一種標記清除法(chrome)

  • 開闢內存時(不管是棧內存或者堆內存),會有一個標記,標記本身有沒有被引用,瀏覽器會在本身空閒的時候,會把咱們開闢的內存依次去迭代和遍歷,若是沒有引用瀏覽器就會自動把它回收。

第二種引用計數法(IE6~8)

  • 引用計數相似與標記清除,它也是進行一個標記,不過是這個地址被引用幾回就標記爲幾,當它的引用計數爲0時,瀏覽器在空閒時就會將它回收。ios

  • 例如git

let obj = { name: 1, age: 12}; //此時會建立一個堆內存來存儲鍵值對
obj = null;  //將變量obj從新賦值,剛剛建立的堆內存在瀏覽器空閒後就會進行釋放回收
複製代碼

閉包

  • 私有上下文:通常函數(代碼塊)中的代碼執行完,瀏覽器會自動把私有上下文出棧釋放,可是若是,當前上下文中,某個和它關聯的內容(通常是一個堆內存)被當前上下文之外的事物佔用了,那麼這個私有上下文不能出棧釋放,這樣私有上下文中的私有變量和值也被保存起來了。web

  • 他是一種機制,函數執行會產生一個私有上下文(做用域),能夠保護裏面的私有變量不受外界干擾,防止全局變量污染,我i們把函數執行的這種機制叫作閉包。ajax

閉包的實際應用

  • 閉包解決循環點擊按鈕綁定點擊事件,點擊按鈕輸出當前的索引

文件上傳

小文件基於文件流

  1. 基於文件流
    • 直接用element-ui upload的插件
    beforeUpload(file){
        let {type, size} = file
        if(/(png|git|jpeg|jpg)/i.test(type)){
            this.$message('文件格式不正確')
            retrun false
        }
        if(size>200*1024*1024){
            this.$message('文件格式不正確')
            return false
        }
    }
    
    handleSuccess(result){
        //請求成功後返回數據result
    }
    複製代碼
  2. 基於base64編碼格式
    • 把上傳的文件先進行解析(fileReader)
    • 把其轉換爲base64編碼格式
    • 本身基於axios把信息傳遞給服務器
    function fileParse(file,type==='base64'){
        return new Promise(resolve=>{
            let fileRead = new FileReader();
            if(type=='base64'){
                fileRead.readAsDataURL(file); 
                }else{
                    fileRead.readAsArrayBuffer(file)
                    }
            fileRead.onload = ev=>{
                 resolve(ev.target.result)
            }
        })
    }
    複製代碼

大文件切片上傳及*斷點續傳

import SparkMD5 from 'spark-md5'
async changeFile(file){
    if(!file) return
    file = file.raw
    //利用上面的方法解析文件轉爲buffer數據
    //咱們會把文件切片處理;把一個文件分割成爲好幾個部分(固定數量/固定大小)
    
    //固定數量
    //每個切片有本身的部分數據和本身名字,例如HASH-1.mp四、HASH-2.mp四、HASH-3.mp4...
    let buffer = await fileParse(file,'buffer'),
    spark = new SparkMD5.ArrayBuffer(),
    hash,
    suffix;//後綴名
    spark.append(buffer)
    hash = spark.end()
    suffix = /\.([0-9a-zA-Z]+)$/i.exec(file.name)[1]
    
    //建立100個切片
    let partList = [],
    partsize = file.size / 100,
    cur = 0
    for(let i = 0; i<100; i++){
        let item = {
            chunk: file.slice(cur,cur + partsize),
            filename: `${hash}_${i}.${suffix}`
        }
        cur += partsize
        partList.push(item)
    }
    this.partList = partList
    this.hash = hash
    this.fileUpload()
}
//上傳切片
async function fileUpload(){
//根據100個切片創造100個請求集合
    let requestList = [];
    this.partList.forEach((item,index)=>{
        let fn = ()=>{
        let formData = new FormData();
            formData.append('chunk',item.chunk)
            formData.append('filename',item.filename)
            return axios.post('url',formData,{headers:{"Content-Type":"multipart/form-data"}}).then(res=>{
                result = res.data
                if(result.code==0){
                    this.total += 1; //這個是上傳的個數
                    //傳完的切片移除掉
                    this.partList.splice(index,1)
                }
            })
        }
        requestList.push(fn)  //100個請求集合
    }) 
    //傳遞:併發(並行)經過ajax.abort()阻止繼續上傳/串行基於標識(自定義變量控制不繼續發送)
    let i = 0;
    let complete = async ()=>{
        let result = await axios.post('url',{params:{hash:this.hash}})
        result = result.data
        if(result.code ===0){
            this.$message('上傳成功')
        }else{
            this.$message('')
        }
    }
    let send =async ()=>{
        if(this.abort) return
        if(i>=requestList.length){
            //都傳完了
            complete()
            return
        }
        await requestList[i]()
        i++
        send()
    }
    send()
}
//暫停繼續,斷點上傳
function handleBtn(){
    if(this.btn){
    //斷點續傳
    this.btn = false//經過true false顯示繼續 暫停
    this.abort = false
    this.fileUpload()
    }
    //暫停上傳
    this.btn = true
    this.abort = true
}
複製代碼

文件下載

  1. 基於blob
    //若是須要下載json格式的文件
    function(res.e){
        let blob
        if(e==='json'){
            blob = new Blob ([JSON.stringfy(res.data)])
        }else{
            blob = new Blob([res.data])
        }
        let fileName = decodeURI(escape(res.headers['filename']))
        if('dowload' in document.createElement('a')){
            let a = document.createElement('a')
                a.download = fileName
                a.display.style = none
                a.href = URL.createObjectURL(blob)
                document.body.appendChild(a)
                a.click()
                URL.removeObjectURL(a.href)
                document.removeChild(a)
        }else{
                navigator.msSaveBlob(blob)
        }
    }
    複製代碼

Promise

Promise使用

  • new Promise(可執行函數)
    • 它等價於new 一個類執行,是同步的,代碼運行和new 一個函數同樣。
    • new Promise的時候,在Promise內部會將可執行函數當即執行,通常這個函數是放一個異步的編程代碼,不是異步的代碼也能夠。
    • 同時會給這個可執行函數傳遞兩個參數,resolve和reject函數。
  • let p = new Promise(()=>{})
    • p是Promise的一個實例
    • 內置私有屬性
      • PromiseState 實例狀態 pending準備狀態 fulfilled/resolved成功狀態 rejected失敗狀態
      • PromiseValue
    • 公有屬性方法 Promise.prototype
      • then
      • catch
      • Symbol(Symbol.toStringTag):'Promise' 這也是object.tostring.prototype.call('p')的原理[object Promise]
  • 在可執行函數中執行resolve或者reject都是爲了改變實例的狀態
  • 一旦狀態改變爲fulfilled、resolved或者rejected則不能再改成其餘狀態
let p1 = new Promise((resolve,reject)=>{
    resolve('ok') // 這是PromiseState就會改成resolved ,PromiseValue的值就成爲ok,若是是reject同理
})
複製代碼
  • 實例的狀態改變能夠控制then中兩個方法中的一個方法,若是是resolved,觸發執行的是第一個回調函數,若是是reject觸發的是第二個函數回調。而且會將PromiseValue的值傳遞給方法chrome

    let p = new Promise((resolve,reject)=>{
           resolve('ok')
        }).then((res)=>{
               console.log(res)// 'ok'
           },()=>{})
    複製代碼
  • 當promise的狀態由pending改變爲resolved或者reject時編程

    • 首先會將傳遞進行的onFulfilledCallback和onrejectCallback存儲起來【存到一個容器中】
    • 其次再去驗證當前的實例狀態
    • 驗證後通知對應的回調函數執行【注意:可是不是當即執行,.then是異步,得等同步函數執行結束再執行】
  • let p2 = p1.then(res=>{ console.log(111) },rej=>{})element-ui

    • p2 不等於p1,p2是p1.then()運行的實例。他仍是屬於pending狀態,若是要改變它的狀態須要在.then()的兩個回調函數中,使用resolve或者reject
  • 若是咱們的onfulfilledCallback和onrejectCallback不傳遞,則狀態會順延/穿透到下一個同等狀態應該執行的函調函數上,內部是實際上是本身補充了一些實現效果的默認函數。json

    new Promise ((resolve,reject)=>{
        resolve('ok')
    }).then(null,null).then((res)=>{
        console.log('成功',res),
        (reject)=>{
            console.log('失敗',reject)
        }
    })
    複製代碼
  • catch捕獲失敗的,原理以下axios

    Promise.prototype.catch = function(onrejectedCallback) {
        return this.then(null,onrejectedCallback)
    }
    複製代碼
  • 結合順延和catch,真實項目中寫法數組

    new Promise((resolve,reject)=>{
        reject('no')
    }).then(res=>{
        console.log('成功',res)
    }).catch(rej=>{
        console.log('失敗',rej)
    })
    複製代碼
  • all

    • let aa = Promise.all([promise實例])
      • 要求數組裏的每一項都是promise的實例
      • all返回的是一個promise實例,它的成功或者失敗取決於數組中每一項的實例是成功仍是失敗,只要有一個失敗,返回值就是失敗的。只有都成功aa纔是成功的。
      let a = new Promise((resolve)=>{
          resolve('ok')
      })
      let b = new Promise((resolve,reject)=>{
          reject('no')
      })
      Promise.all([a,b]).then(res=>{
          console.log(res,'ok')
      }).catch(rej=>{
          console.log(rej,'rej')
      })
      複製代碼
    • 不管誰先知道狀態,最後結果的順序和出阿迪的數組循序保持一致
  • race誰先知道狀態就返回AA的成功和失敗

promise輸出案例

new Promise((resolve)=>{
    console.log('promise1')
    resolve()
}).then(()=>{
    console.log('then11')
    new Promise((resolve)=>{
        console.log('promise2')
        resolve()
    }).then(()=>{
        console.log('then21')
    }).then(()=>{
        console.log('then22')
    })
}).then(()=>{
    console.log('then12')
})// promise1 then11 promise2 then21 then12 then22
複製代碼
  • 解析上面代碼
    • new promise是同步,因此先輸出promise1
    • resolve修改狀態爲成功,故它第一個then11爲微任務1,馬上放入EventQueue(微任務)
    • 下面第二個then12,它的狀態取決於then11,但then11尚未執行完,故放到webAPI中監聽等待。
    • 執行微任務1(then11),同步輸除then11,promise2
    • resolve狀態成功,當即生成微任務3,then21,
    • then22,它的狀態取決於then21,可是then21尚未執行,故放入webAPI
    • 執行代碼,輸入then21,webAPI中微任務二先存,故先執行,輸出then12 最後到then22

async await ES7

  • async是函數的修飾符,控制函數返回Promise實例
    async function fn(){
        return 10
    }
    console.log(fn())  //返回promise實例,成功狀態,值爲10
    複製代碼
    • 若是函數內部執行報錯,則返回的promise實例,狀態是失敗

async 中加try 和 catch

  • 若是函數內部作了異常捕獲,則仍是成功狀態
    let a = async function fn() {
        try {
          console.log(b);
        } catch (e) {
          console.log(e);  //捕獲錯誤
        }
        return 10;
    };
    console.log(a()); //返回狀態是成功的,值是10
    複製代碼
  • await是異步微任務,await後面的代碼愛咋地咋地,可是下面的代碼會暫停執行,把他們看成一個任務,設置在EventQueue微任務隊列中。
  • await後面通常都是跟Promise實例,若是await後面跟的不是promise實例,瀏覽器也會把其變爲Promise實例,若是await後面的實例是失敗狀態,則代碼將會結束執行。以下
    async function fn(){
        await 1 //等價於 await Promise.resolve(1)
        await Promise.reject(1)
        console.log(1111) // 不會輸出1111
    }
    複製代碼

關於this

事件綁定

  • DOM0; xxx.onxxx = function(){}
  • DOM2; xxx.addEventListener('onxxx',function(){})
    • 給當前元素的某個事件行爲綁定方法【此時是建立方法,方法沒有執行】,當事件行爲觸發,瀏覽器會把綁定的函數執行,此時函數中的this是當前元素對象自己。

函數執行

  • 正常的普通函數執行,看函數前是否有,有前面是誰this就是誰,沒有,this就是window,嚴格模式下undefined。'use strict'
  • 匿名函數
    • 函數表達式 var fn = function(){console.log(this)} //window
    • 自執行函數 (function(x){console.log(this)})(10) //window
    • 回調函數 function(callback){callback()} //通常是window,可是能夠經過call改變。
  • this指向試題
    var x = 3,
        obj = {
            x: 5,
        };
    obj.fn = (function () {
        this.x *= ++x; //window x = 12
        return function (y) {
            console.log(this)
            this.x *= ++x + y;  //obj.x = 95
            console.log(x);  //x 13
        };
    })();
    var fn = obj.fn;
    obj.fn(6);
    fn(4); //234
    console.log(obj.x, x); //95 234
    
    //首先代碼從上到下執行,建立x, obj, obj.fn,自執行函數執行,而後將return這個函數賦值給fn
    // obj.fn(6)執行,至關於this是obj,執行的函數是返回值
    // fn(4)執行,至關於它的this是window
    複製代碼
相關文章
相關標籤/搜索