国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

實(shí)現(xiàn)一個(gè)符合標(biāo)準(zhǔn)的Promise

yuanzhanghu / 654人閱讀

摘要:不同的的實(shí)現(xiàn)需要可以相互調(diào)用,搞清楚了標(biāo)準(zhǔn)之后,開(kāi)始動(dòng)手吧構(gòu)造函數(shù)產(chǎn)生一個(gè)對(duì)象有很多種方法,構(gòu)造函數(shù)是看起來(lái)最面向?qū)ο蟮囊环N,而且原生實(shí)現(xiàn)也是使用的構(gòu)造函數(shù),因此我也決定使用構(gòu)造函數(shù)的方法。

-- What i can"t create, i don"t understant

前言

實(shí)現(xiàn)Promise的目的是為了深入的理解Promies,以在項(xiàng)目中游刃有余的使用它。完整的代碼見(jiàn)gitHub

Promise標(biāo)準(zhǔn)

Promise的標(biāo)準(zhǔn)有很多個(gè)版本,本文采用ES6原生Promise使用的Promise/A+標(biāo)準(zhǔn)。完整的Promise/A+標(biāo)準(zhǔn)見(jiàn)這里,總結(jié)如下:

promise具有狀態(tài)state(status),狀態(tài)分為pending, fulfilled(我比較喜歡叫做resolved), rejected。初始為pending,一旦狀態(tài)改變,不能再更改為其它狀態(tài)。當(dāng)promise為fulfilled時(shí),具有value;當(dāng)promise為rejected時(shí),具有reason;value和reason都是一旦確定,不能改變的。

promise具有then方法,注意了,只有then方法是必須的,其余常用的catch,race,all,resolve等等方法都不是必須的,其實(shí)這些方法都可以用then方便的實(shí)現(xiàn)。

不同的promise的實(shí)現(xiàn)需要可以相互調(diào)用

OK,搞清楚了promise標(biāo)準(zhǔn)之后,開(kāi)始動(dòng)手吧

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

產(chǎn)生一個(gè)對(duì)象有很多種方法,構(gòu)造函數(shù)是看起來(lái)最面向?qū)ο蟮囊环N,而且原生Promise實(shí)現(xiàn)也是使用的構(gòu)造函數(shù),因此我也決定使用構(gòu)造函數(shù)的方法。

首先,先寫(xiě)一個(gè)大概的框架出來(lái):

// 總所周知,Promise傳入一個(gè)executor,有兩個(gè)參數(shù)resolve, reject,用來(lái)改變promise的狀態(tài)
function Promise(executor) {
    this.status = "pending"
    this.value = void 0 // 為了方便把value和reason合并

    const resolve = function() {}
    const reject = function() {} 
    executor(resolve, reject)
}

很明顯,這個(gè)構(gòu)造函數(shù)還有很多問(wèn)題們一個(gè)一個(gè)來(lái)看

resolve和reject并沒(méi)有什么卵用。

首先,用過(guò)promise的都知道,resolve和reject是用來(lái)改變promise的狀態(tài)的:

   function Promise(executor) {
       this.status = "pending"
       this.value = void 0 // 為了方便把value和reason合并

       const resolve = value => {
           this.value = value
           this.status = "resolved"
       }
       const reject = reason => {
           this.value = reason
           this.status = "rejected"
       } 
       executor(resolve, reject)
   }
   

然后,當(dāng)resolve或者reject調(diào)用的時(shí)候,需要執(zhí)行在then方法里傳入的相應(yīng)的函數(shù)(通知)。有沒(méi)有覺(jué)得這個(gè)有點(diǎn)類似于事件(發(fā)布-訂閱模式)呢?

   function Promise(executor) {
       this.status = "pending"
       this.value = void 0 // 為了方便把value和reason合并

       this.resolveListeners = []
       this.rejectListeners = []

       // 通知狀態(tài)改變
       const notify(target, val) => {
           target === "resolved"
               ? this.resolveListeners.forEach(cb => cb(val))
               : this.rejectListeners.forEach(cb => cb(val))
       }

       const resolve = value => {
           this.value = value
           this.status = "resolved"
           notify("resolved", value)
       }
       const reject = reason => {
           this.value = reason
           this.status = "rejected"
           notify("rejected", reason)
       } 
       executor(resolve, reject)
   }

status和value并沒(méi)有做到一旦確定,無(wú)法更改。這里有兩個(gè)問(wèn)題,一是返回的對(duì)象暴露了status和value屬性,并且可以隨意賦值;二是如果在executor里多次調(diào)用resolve或者reject,會(huì)使value更改多次。

第一個(gè)問(wèn)題,如何實(shí)現(xiàn)只讀屬性:

   function Promise(executor) {
       if (typeof executor !== "function") {
           throw new Error("Promise executor must be fucntion")
       }

       let status = "pending" // 閉包形成私有屬性
       let value = void 0

       ......

       // 使用status代替this.value
       const resolve = val => {
           value = val
           status = "resolved"
           notify("resolved", val)
       }
       const reject = reason => {
           value = reason
           status = "rejected"
           notify("rejected", reason)
       }

       // 通過(guò)getter和setter設(shè)置只讀屬性
       Object.defineProperty(this, "status", {
           get() {
               return status
           },
           set() {
               console.warn("status is read-only")
           }
       })

       Object.defineProperty(this, "value", {
           get() {
               return value
           },
           set() {
               console.warn("value is read-only")
           }
       })

第二個(gè)問(wèn)題,避免多次調(diào)用resolve、reject時(shí)改變value,而且標(biāo)準(zhǔn)里(2.2.2.3 it must not be called more than once)也有規(guī)定,then注冊(cè)的回調(diào)只能執(zhí)行一次。

   const resolve = val => {
       if (status !== "pending") return // 避免多次運(yùn)行
       value = val
       status = "resolved"
       notify("resolved", val)
   }

then注冊(cè)的回調(diào)需要異步執(zhí)行。

說(shuō)到異步執(zhí)行,對(duì)原生Promise有了解的同學(xué)都知道,then注冊(cè)的回調(diào)在Micro-task中,并且調(diào)度策略是,Macro-task中執(zhí)行一個(gè)任務(wù),清空所有Micro-task的任務(wù)。簡(jiǎn)而言之,promise異步的優(yōu)先級(jí)更高。

其實(shí),標(biāo)準(zhǔn)只規(guī)定了promise回調(diào)需要異步執(zhí)行,在一個(gè)“干凈的”執(zhí)行棧執(zhí)行,并沒(méi)有規(guī)定一定說(shuō)要用micro-task,并且在低版本瀏覽器中,并沒(méi)有micro-task隊(duì)列。不過(guò)在各種promise的討論中,由于原生Promise的實(shí)現(xiàn),micro-task已經(jīng)成成為了事實(shí)標(biāo)準(zhǔn),而且promise回調(diào)在micro-task中也使得程序的行為更好預(yù)測(cè)。

在瀏覽器端,可以用MutationObserver實(shí)現(xiàn)Micro-task。本文利用setTimeout來(lái)簡(jiǎn)單實(shí)現(xiàn)異步。

   const resolve = val => {
       if (val instanceof Promise) {
           return val.then(resolve, reject)
       }

       // 異步執(zhí)行
       setTimeout(() => {
           if (status !== "pending") return
           
           status = "resolved"
           value = val
           notify("resolved", val)
       }, 0)
   }

最后,加上錯(cuò)誤處理,就得到了一個(gè)完整的Promise構(gòu)造函數(shù):

function Promise(executor) {
    if (typeof executor !== "function") {
        throw new Error("Promise executor must be fucntion")
    }

    let status = "pending"
    let value = void 0

    const notify = (target, val) => {
        target === "resolved"
            ? this.resolveListeners.forEach(cb => cb(val))
            : this.rejectListeners.forEach(cb => cb(val))
    }

    const resolve = val => {
        if (val instanceof Promise) {
            return val.then(resolve, reject)
        }

        setTimeout(() => {
            if (status !== "pending") return
            
            status = "resolved"
            value = val
            notify("resolved", val)
        }, 0)
    }

    const reject = reason => {
        setTimeout(() => {
            if (status !== "pending") return

            status = "rejected"
            value = reason
            notify("rejected", reason)
        }, 0)
    }

    this.resolveListeners = []
    this.rejectListeners = []

    Object.defineProperty(this, "status", {
        get() {
            return status
        },
        set() {
            console.warn("status is read-only")
        }
    })

    Object.defineProperty(this, "value", {
        get() {
            return value
        },
        set() {
            console.warn("value is read-only")
        }
    })

    try {
        executor(resolve, reject)
    } catch (e) {
        reject(e)
    }
}

總的來(lái)說(shuō),Promise構(gòu)造函數(shù)其實(shí)只干了一件事:執(zhí)行傳入的executor,并構(gòu)造了executor的兩個(gè)參數(shù)。

實(shí)現(xiàn)then方法

首先需要確定的是,then方法是寫(xiě)在構(gòu)造函數(shù)里還是寫(xiě)在原型里。
寫(xiě)在構(gòu)造函數(shù)了里有一個(gè)比較大的好處:可以像處理status和value一樣,通過(guò)閉包讓resolveListeners和rejectListeners成為私有屬性,避免通過(guò)this.rejectListeners來(lái)改變它。
寫(xiě)在構(gòu)造函數(shù)里的缺點(diǎn)是,每一個(gè)promise對(duì)象都會(huì)有一個(gè)不同的then方法,這既浪費(fèi)內(nèi)存,又不合理。我的選擇是寫(xiě)在原型里,為了保持和原生Promise有一樣的結(jié)構(gòu)和接口。

ok,還是先寫(xiě)一個(gè)大概的框架:

Promise.prototype.then = function (resCb, rejCb) {
    this.resolveListeners.push(resCb)
    this.rejectListeners.push(rejCb)

    return new Promise()
}

隨后,一步一步的完善它:

then方法返回的promise需要根據(jù)resCb或rejCb的運(yùn)行結(jié)果來(lái)確定狀態(tài)。

Promise.prototype.then = function (resCb, rejCb) {
    return new Promise((res, rej) => {
        this.resolveListeners.push((val) => {
            try {
                const x = resCb(val)
                res(x) // 以resCb的返回值為value來(lái)resolve
            } catch (e) {
                rej(e) // 如果出錯(cuò),返回的promise以異常為reason來(lái)reject
            }
        })

        this.rejectListeners.push((val) => {
            try {
                const x = rejCb(val)
                res(x) // 注意這里也是res而不是rej哦
            } catch (e) {
                rej(e) // 如果出錯(cuò),返回的promise以異常為reason來(lái)reject
            }
        })
    })
}

ps:眾所周知,promise可以鏈?zhǔn)秸{(diào)用,說(shuō)起鏈?zhǔn)秸{(diào)用,我的第一個(gè)想法就是返回this就可以了,但是then方法不可以簡(jiǎn)單的返回this,而要返回一個(gè)新的promise對(duì)象。因?yàn)閜romise的狀態(tài)一旦確定就不能更改,而then方法返回的promise的狀態(tài)需要根據(jù)then回調(diào)的運(yùn)行結(jié)果來(lái)決定。

如果resCb/rejCb返回一個(gè)promiseA,then返回的promise需要跟隨(adopt)promiseA,也就是說(shuō),需要保持和promiseA一樣的status和value。

this.resolveListeners.push((val) => {
    try {
        const x = resCb(val)

        if (x instanceof Promise) {
            x.then(res, rej) // adopt promise x
        } else {
            res(x)
        }
    } catch (e) {
        rej(e)
    }
})

this.rejectListeners.push((val) => {
    try {
        const x = resCb(val)

        if (x instanceof Promise) {
            x.then(res, rej) // adopt promise x
        } else {
            res(x)
        }
    } catch (e) {
        rej(e)
    }
})

如果then的參數(shù)不是函數(shù),需要忽略它,類似于這種情況:

new Promise(rs => rs(5))
    .then()
    .then(console.log)

其實(shí)就是把value和狀態(tài)往后傳遞

this.resolveListeners.push((val) => {
    if (typeof resCb !== "function") {
        res(val)
        return
    }

    try {
        const x = resCb(val)

        if (x instanceof Promise) {
            x.then(res, rej) // adopt promise x
        } else {
            res(x)
        }
    } catch (e) {
        rej(e)
    }
})

// rejectListeners也是相同的邏輯

如果調(diào)用then時(shí), promise的狀態(tài)已經(jīng)確定,相應(yīng)的回調(diào)直接運(yùn)行

// 注意這里需要異步
if (status === "resolved") setTimeout(() => resolveCb(value), 0)
if (status === "rejected") setTimeout(() => rejectCb(value), 0)

最后,就得到了一個(gè)完整的then方法,總結(jié)一下,then方法干了兩件事,一是注冊(cè)了回調(diào),二是返回一個(gè)新的promise對(duì)象。

// resolveCb和rejectCb是相同的邏輯,封裝成一個(gè)函數(shù)
const thenCallBack = (cb, res, rej, target, val) => {
    if (typeof cb !== "function") {
        target === "resolve"
            ? res(val)
            : rej(val)
        return
    }

    try {
        const x = cb(val)

        if (x instanceof Promise) {
            x.then(res, rej) // adopt promise x
        } else {
            res(x)
        }
    } catch (e) {
        rej(e)
    }
}

Promise.prototype.then = function (resCb, rejCb) {
    const status = this.status
    const value = this.value
    let thenPromise

    thenPromise = new Promise((res, rej) => {
        /**
         * 這里不能使用bind來(lái)實(shí)現(xiàn)柯里畫(huà),規(guī)范里規(guī)定了:
         * 2.2.5: onFulfilled and onRejected must be called as functions (i.e. with no this value))
         */
        const resolveCb = val => {
            thenCallBack(resCb, res, rej, "resolve", val)
        } 
        const rejectCb = val => {
            thenCallBack(rejCb, res, rej, "reject", val)
        }

        if (status === "pending") {
            this.resolveListeners.push(resolveCb)
            this.rejectListeners.push(rejectCb)
        }

        if (status === "resolved") setTimeout(() => resolveCb(value), 0)
        if (status === "rejected") setTimeout(() => rejectCb(value), 0)
    })

    return thenPromise
}
不同的Promise實(shí)現(xiàn)可以互相調(diào)用

首先要明白的是什么叫互相調(diào)用,什么情況下會(huì)互相調(diào)用。之前實(shí)現(xiàn)then方法的時(shí)候,有一條規(guī)則是:如果then方法的回調(diào)返回一個(gè)promiseA。then返回的promise需要adopt這個(gè)promiseA,也就是說(shuō),需要處理這種情況:

new MyPromise(rs => rs(5))
    .then(val => {
        return Promise.resolve(5) // 原生Promise
    })
    .then(val => {
        return new Bluebird(r => r(5)) // Bluebird的promise
    })

關(guān)于這個(gè),規(guī)范里定義了一個(gè)叫做The Promise Resolution Procedure的過(guò)程,我們需要做的就是把規(guī)范翻譯一遍,并替代代碼中判斷promise的地方

const resolveThenable = (promise, x, resolve, reject) => {
    if (x === promise) {
        return reject(new TypeError("chain call found"))
    }

    if (x instanceof Promise) {
        return x.then(v => {
            resolveThenable(promise, v, resolve, reject)
        }, reject)
    }

    if (x === null || (typeof x !== "object" && typeof x !== "function")) {
        return resolve(x)
    }

    let called = false
    try {
        // 這里有一個(gè)有意思的技巧。標(biāo)準(zhǔn)里解釋了,如果then是一個(gè)getter,那么通過(guò)賦值可以保證getter只被觸發(fā)一次,避免副作用
        const then = x.then

        if (typeof then !== "function") {
            return resolve(x)
        }

        then.call(x, v => {
            if (called) return
            called = true
            resolveThenable(promise, v, resolve, reject)
        }, r => {
            if (called) return
            called = true
            reject(r)
        })
    } catch (e) {
        if (called) return
        reject(e)
    }
}

到這里,一個(gè)符合標(biāo)準(zhǔn)的Promise就完成了,完整的代碼如下:

function Promise(executor) {
    if (typeof executor !== "function") {
        throw new Error("Promise executor must be fucntion")
    }

    let status = "pending"
    let value = void 0

    const notify = (target, val) => {
        target === "resolved"
            ? this.resolveListeners.forEach(cb => cb(val))
            : this.rejectListeners.forEach(cb => cb(val))
    }

    const resolve = val => {
        if (val instanceof Promise) {
            return val.then(resolve, reject)
        }

        setTimeout(() => {
            if (status !== "pending") return
            
            status = "resolved"
            value = val
            notify("resolved", val)
        }, 0)
    }

    const reject = reason => {
        setTimeout(() => {
            if (status !== "pending") return

            status = "rejected"
            value = reason
            notify("rejected", reason)
        }, 0)
    }

    this.resolveListeners = []
    this.rejectListeners = []

    Object.defineProperty(this, "status", {
        get() {
            return status
        },
        set() {
            console.warn("status is read-only")
        }
    })

    Object.defineProperty(this, "value", {
        get() {
            return value
        },
        set() {
            console.warn("value is read-only")
        }
    })

    try {
        executor(resolve, reject)
    } catch (e) {
        reject(e)
    }
}

const thenCallBack = (cb, res, rej, target, promise, val) => {
    if (typeof cb !== "function") {
        target === "resolve"
            ? res(val)
            : rej(val)
        return
    }

    try {
        const x = cb(val)
        resolveThenable(promise, x, res, rej)
    } catch (e) {
        rej(e)
    }
}

const resolveThenable = (promise, x, resolve, reject) => {
    if (x === promise) {
        return reject(new TypeError("chain call found"))
    }

    if (x instanceof Promise) {
        return x.then(v => {
            resolveThenable(promise, v, resolve, reject)
        }, reject)
    }

    if (x === null || (typeof x !== "object" && typeof x !== "function")) {
        return resolve(x)
    }

    let called = false
    try {
        // 這里有一個(gè)有意思的技巧。標(biāo)準(zhǔn)里解釋了,如果then是一個(gè)getter,那么通過(guò)賦值可以保證getter只被觸發(fā)一次,避免副作用
        const then = x.then

        if (typeof then !== "function") {
            return resolve(x)
        }

        then.call(x, v => {
            if (called) return
            called = true
            resolveThenable(promise, v, resolve, reject)
        }, r => {
            if (called) return
            called = true
            reject(r)
        })
    } catch (e) {
        if (called) return
        reject(e)
    }
}

Promise.prototype.then = function (resCb, rejCb) {
    const status = this.status
    const value = this.value
    let thenPromise

    thenPromise = new Promise((res, rej) => {
        const resolveCb = val => {
            thenCallBack(resCb, res, rej, "resolve", thenPromise, val)
        }
        const rejectCb = val => {
            thenCallBack(rejCb, res, rej, "reject", thenPromise, val)
        }

        if (status === "pending") {
            this.resolveListeners.push(resolveCb)
            this.rejectListeners.push(rejectCb)
        }

        if (status === "resolved") setTimeout(() => resolveCb(value), 0)
        if (status === "rejected") setTimeout(() => rejectCb(value), 0)
    })

    return thenPromise
}

測(cè)試腳本

關(guān)于promise的一些零散知識(shí)

Promise.resolve就是本文所實(shí)現(xiàn)的resolveThenable,并不是簡(jiǎn)單的用來(lái)返回一個(gè)resolved狀態(tài)的函數(shù),它返回的promise對(duì)象的狀態(tài)也并不一定是resolved。

promise.then(rs, rj)和promise.then(rs).catch(rj)是有區(qū)別的,區(qū)別在于當(dāng)rs出錯(cuò)時(shí),后一種方法可以進(jìn)行錯(cuò)誤處理。

感想與總結(jié)

實(shí)現(xiàn)Promise的過(guò)程其實(shí)并沒(méi)有我預(yù)想的那么難,所謂的Promise的原理我感覺(jué)就是類似于觀察者模式,so,不要有畏難情緒,我上我也行^_^。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/97944.html

相關(guān)文章

  • 一步一步實(shí)現(xiàn)一個(gè)符合PromiseA+規(guī)范Promise庫(kù)(1)

    摘要:今天我們來(lái)自己手寫(xiě)一個(gè)符合規(guī)范的庫(kù)。是異步編程的一種解決方案,比傳統(tǒng)的解決方案回調(diào)函數(shù)和事件更合理和更強(qiáng)大。我們可以看到,其實(shí)就是一個(gè)構(gòu)造函數(shù)。所以說(shuō)我們的數(shù)組里存的是一個(gè)一個(gè)的的回調(diào)函數(shù),也就是一個(gè)一個(gè)。 今天我們來(lái)自己手寫(xiě)一個(gè)符合PromiseA+規(guī)范的Promise庫(kù)。大家是不是很激動(dòng)呢?? showImg(https://segmentfault.com/img/bV6t4Z?...

    joyvw 評(píng)論0 收藏0
  • 【譯】前端知識(shí)儲(chǔ)備——Promise/A+規(guī)范

    摘要:在將來(lái)的其他規(guī)范中可能會(huì)涉及這些沒(méi)有提及的內(nèi)容。它禁止被觸發(fā)多次。如果到了狀態(tài),那么所有的回調(diào)函數(shù)都必須按照他們?cè)械捻樞蜻M(jìn)行調(diào)用執(zhí)行。 概述 自從準(zhǔn)備晉級(jí)之后,就拖更了很久了,既然晉級(jí)弄完了,那么也恢復(fù)更新了。 在面試別人的過(guò)程中,發(fā)現(xiàn)基本上沒(méi)有人對(duì)整個(gè)Promise完全了解,因此希望通過(guò)這篇文章來(lái)幫助大家了解下Promise的全貌。本文的主要內(nèi)容是Promise/A+規(guī)范的譯文,主...

    Gemini 評(píng)論0 收藏0
  • 前端開(kāi)發(fā)中Error以及異常捕獲

    摘要:前端開(kāi)發(fā)中的中的中,是一個(gè)構(gòu)造函數(shù),通過(guò)它創(chuàng)建一個(gè)錯(cuò)誤對(duì)象。是核心對(duì)象,表示調(diào)用一個(gè)時(shí)發(fā)生的異常。將回調(diào)函數(shù)包裹一層接下來(lái)可以將統(tǒng)一進(jìn)行處理。中的錯(cuò)誤捕獲在以前,可以使用來(lái)處理捕獲的錯(cuò)誤。研究結(jié)果在這里中的錯(cuò)誤捕獲的源碼中,在關(guān) 本文首發(fā)于公眾號(hào):符合預(yù)期的CoyPan 寫(xiě)在前面 在前端項(xiàng)目中,由于JavaScript本身是一個(gè)弱類型語(yǔ)言,加上瀏覽器環(huán)境的復(fù)雜性,網(wǎng)絡(luò)問(wèn)題等等,很容易...

    Mr_houzi 評(píng)論0 收藏0
  • 傳統(tǒng) Ajax 已死,F(xiàn)etch 永生

    摘要:結(jié)果證明,對(duì)于以上瀏覽器,在生產(chǎn)環(huán)境使用是可行的。后面可以跟對(duì)象,表示等待才會(huì)繼續(xù)向下執(zhí)行,如果被或拋出異常則會(huì)被外面的捕獲。,,都是現(xiàn)在和未來(lái)解決異步的標(biāo)準(zhǔn)做法,可以完美搭配使用。這也是使用標(biāo)準(zhǔn)一大好處。只允許外部傳入成功或失敗后的回調(diào)。 showImg(https://cloud.githubusercontent.com/assets/948896/10188666/bc9a53...

    fai1017 評(píng)論0 收藏0
  • ES6: Promise

    摘要:換句話說(shuō)該靜態(tài)函數(shù)返回個(gè)處于狀態(tài)的對(duì)象。等價(jià)于構(gòu)造函數(shù)的靜態(tài)函數(shù),創(chuàng)建一個(gè)對(duì)象并以值作為參數(shù)調(diào)用句柄函數(shù)。等價(jià)于介紹構(gòu)造函數(shù)的靜態(tài)函數(shù),參數(shù)是對(duì)象組成的可迭代數(shù)據(jù)集合。 一、概述 ES2015 Promise函數(shù)是對(duì)PromiseA+標(biāo)準(zhǔn)的實(shí)現(xiàn),并且嚴(yán)格遵守該標(biāo)準(zhǔn)。 二、APIs 2.1 創(chuàng)建Promise對(duì)象 Promise構(gòu)造函數(shù)的參數(shù)是個(gè)包含兩個(gè)參數(shù)的函數(shù),并且該函數(shù)的參數(shù)分別對(duì)...

    roadtogeek 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<