3

我有這樣的代碼,正在建設一個URL端點採取不同的參數:如何在javascript中使用組合函數鏈接?

const query = (obj) => { 
 
    let starter = 'query=' 
 
    let queryToString = JSON.stringify(obj) 
 
    return `${starter}${queryToString}` 
 
} 
 

 
const params = (str) => `${str}` 
 

 
const endpoint = (protocol, base, params, query) => { 
 
    if (!params && !query) return `${base}` 
 
    if (!params) return `${base}${query}` 
 
    return `${protocol}${base}?${params}&${query}` 
 
} 
 

 
const baseUrl = 'api.content.io' 
 

 
const protocol = (secure = true) => secure ? 'https://' : 'http://' 
 

 
let result = endpoint(protocol(), baseUrl, params('limit=5&order=desc'), 
 
    query({ 
 
    field: 'title', 
 
    include: 'brands' 
 
    })); 
 

 
console.log(result)

這將構建一個字符串,如:

https: //api.content.io?limit=5&order=desc&query={"field":"title","include":"brands"} 

是否有可能重構這個代碼這樣endpoint函數中的條件可以被刪除,正確的連接字符串被應用和整個事情鏈接到一個功能調用如

Endpoint.chain(protocol(p)).chain(base(b)).chain(params(p)).chain(query(q)).build() 

我該如何開始這樣做?

更新:下面的解決方案是相當不錯的,但我想了解功能程序員如何使用Monad ADT(代數數據類型)來解決此問題。這個想法是運行一個chain的功能,然後fold找回我想要的值

+1

你確定你_want_做這樣的事? 'base'實際上不是'params'的參數。這些都不屬於任何其他。他們在製作端點方面都是平等的參與者。如果您希望在調用中顯示組件的名稱,則JS成語就像使用對象速記符號調用的「endpoint({protocol,base,params,query})」。 –

+0

嗯..你是對的。你是說我只有在參數匹配時才能達到功能組合?這可能是一個錯誤的應用程序? –

+0

@RayToal我想要做的實際上是鏈接函數調用我猜 - 以便一個函數的結束值被傳遞到另一個,並檢查空值的必要性被刪除 –

回答

2

你在尋找類似的東西嗎?

鏈接基本上發生在每個函數調用中返回完整對象時。在這裏,每個函數都會設置給定塊的值,並返回該對象用於所連接的任何上下文。每個函數都可以處理它接收到的值,值函數將根據設置的參數構建url。

var Endpoint = { 
    protocol: protocol, 
    base: base, 
    params: params, 
    query: query, 
    value: value 
} 
function protocol(b) { 
    protocol.value = b && 'https://' || 'http://'; 
    return this; 
} 
function base(s) { 
    base.value = s || ''; 
    return this; 
} 
function params(s) { 
    params.value = s || ''; 
    return this; 
} 
function query(s) { 
    query.value = s || ''; 
    return this; 
} 
function value(s) { 
    return '$protocol$base$params$params$query' 
     .replace('$protocol',protocol.value) 
     .replace('$base',base.value) 
     .replace('$params',params.value) 
     .replace('$query',query.value) 
} 

Endpoint 
    .protocol(true) 
    .base('www.foo.com') 
    .params('one/two/three') 
    .query('?foo=bar') 
    .value() 
// "https://www.foo.comone/two/three$params?foo=bar" 
+0

這是非常接近,但我想了解功能程序員如何使用Monad ADT(代數數據類型)來解決這個問題問題 –

+0

我對這段代碼如何工作有點困惑。你能告訴我如何'base.value = s || '''實際上有效?我的意思是左側。 'base.value'中的'base'來自哪裏? –

+0

這是用方法鏈實現的裝飾模式。你要麼很出色,要麼你的教學大綱寫得很出色。令人難以置信的是,偶然的情況下,在這個例子中Monad被精美地圖解。至於你問到的細節,我會給你一個提示,功能也是對象! – Shanimal

2

你可以使用一個類,它擁有讓鏈接的方法(它們返回this):

class EndPoint { 
 
    constructor() { 
 
     // defaults 
 
     this.prot = 'https://'; 
 
     this.bas = 'api.content.io'; 
 
     this.qry = ''; 
 
     this.par = ''; 
 
    } 
 
    secure(on = true) { 
 
     this.prot = on ? 'https://' : 'http://'; 
 
     return this; 
 
    } 
 
    base(str) { 
 
     this.bas = str; 
 
     return this; 
 
    } 
 
    query(obj) { 
 
     this.qry = `query=${JSON.stringify(obj)}` 
 
     return this; 
 
    } 
 
    params(str) { 
 
     this.par = str 
 
     return this; 
 
    } 
 
    build() { 
 
     let sep1 = this.qry.length || this.par.length ? '?' : ''; 
 
     let sep2 = this.qry.length && this.par.length ? '&' : ''; 
 
     return `${this.prot}${this.bas}${sep1}${this.par}${sep2}${this.qry}`; 
 
    } 
 
}; 
 

 
let result = new EndPoint().secure(true).base('www.example.com') 
 
    .params('limit=5&order=desc').query({ field: 'title', include: 'brands' }).build(); 
 

 
console.log(result);

1

雖然上面的答案會的工作,但如果你希望語法以Endpoint().開頭,然後使用EndpointBuilder類和下面的工廠函數。

class EndpointBuilder { 

    constructor() { 
     this.params = []; 
     this.protocol = 'http://'; 
     this.baseUrl = 'api.endpoint.io'; 
    } 

    base(url) { 
     if (url && url.trim().length > 0) 
      this.baseUrl = url; 
     return this; 
    } 

    secure() { 
     this.protocol = 'https://'; 
     return this; 
    } 

    setParam(param, val) { 
     if (param && val) 
      this.params.push({ param, val }); 
     return this 
    } 

    toString() { 

     const url = `${this.protocol}${this.baseUrl}`; 
     if (this.params.length <= 0) 
      return url; 

     let qString = ''; 
     this.params.forEach(p => { 
      qString = `${qString}${qString.length > 0 ? '&' : ''}${p.param}=${JSON.stringify(p.val)}`; 
     }); 

     return `${url}?${qString}`; 
    } 
}; 

// Endpoint Factory 
const Endpoint = function() { 
    return new EndpointBuilder(); 
}; 

用法示例:

const url1 = Endpoint().setParam('limit', 5).setParam('query', { field: 'title', include: 'brands' }).toString(); 

const url2 = Endpoint().base('another.endpoint.io').setParam('limit', 5).setParam('order', 'desc').setParam('query', { field: 'title', include: 'brands' }).toString(); 

const url3 = Endpoint().base('another.endpoint.io').secure().setParam('limit', 5).setParam('order', 'desc').setParam('query', { field: 'title', include: 'brands' }).toString(); 

console.log(url1); 
// http://api.endpoint.io?limit=5&query={"field":"title","include":"brands"} 

console.log(url2); 
// http://another.endpoint.io?limit=5&order="desc"&query={"field":"title","include":"brands"} 

console.log(url3); 
// https://another.endpoint.io?limit=5&order="desc"&query={"field":"title","include":"brands"} 
相關問題