自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

JavaScript 代碼越來越難讀了 ...

開發(fā) 前端
今天來我給大家介紹 JavaScript 代碼的一個(gè)新運(yùn)算符:管道運(yùn)算符 |>。

今天來給大家介紹 JavaScript 代碼的一個(gè)新運(yùn)算符:管道運(yùn)算符 |>。

對(duì)一個(gè)值執(zhí)行連續(xù)操作

當(dāng)我們?cè)?JavaScript 中對(duì)一個(gè)值執(zhí)行連續(xù)操作(例如函數(shù)調(diào)用)時(shí),目前有兩種基本方式:

  • 將值作為參數(shù)傳遞給具體操作(如果有多個(gè)操作,則嵌套操作),例如:three(two(one(value)));
  • 將函數(shù)作為值上的方法調(diào)用(如果有多個(gè)方法,則為鏈?zhǔn)秸{(diào)用),例如:value.one().two().three()。

在 2020 年 JS 狀態(tài)調(diào)查中,“你認(rèn)為 JavaScript 目前缺少什么?“ 問題中,希望擁有管道操作符 答案排行第四名。

看來大家當(dāng)前對(duì) JS 中連續(xù)操作的寫法還是不太滿意啊。

首先,如果是嵌套寫法的話,簡(jiǎn)單的嵌套還好,但是當(dāng)嵌套變得很深的時(shí)候就有點(diǎn)難以閱讀了。嵌套的執(zhí)行流程是從右到左移動(dòng)的,而不是我們正常閱讀代碼從左到右的方向。另外,我們?cè)诤芏嗬ㄌ?hào)之間找到一個(gè)位置添加一些參數(shù)也比較困難。比如下面的代碼:

console.log(
chalk.dim(
`$ ${Object.keys(envars)
.map(envar =>
`${envar}=${envars[envar]}`)
.join(' ')
}`,
'node',
args.join(' ')));

對(duì)于鏈?zhǔn)秸{(diào)用,只有我們把方法指定為值的實(shí)例方法時(shí)才能用,這讓它具有很大的局限性。當(dāng)然,如果你的庫(kù)設(shè)計(jì)的很好(比如 jQuery) 還是挺好用的。

管道式編程

Unix 操作系統(tǒng)有一個(gè)管道機(jī)制,可以把前一個(gè)操作的值傳給后一個(gè)操作。這個(gè)機(jī)制非常有用,使得簡(jiǎn)單的操作可以組合成為復(fù)雜的操作。許多語(yǔ)言都有管道的實(shí)現(xiàn),舉個(gè)簡(jiǎn)單的例子:

function capitalize (str) {
return str[0].toUpperCase() + str.substring(1);
}
function hello (str) {
return str + ' Hello!';
}

上面是兩個(gè)簡(jiǎn)單的函數(shù),想要嵌套執(zhí)行,傳統(tǒng)寫法和管道寫法分別如下:

// 傳統(tǒng)的寫法
exclaim(hello('conardli'))
// "Conardli Hello!"

// 管道的寫法
'conardli'
|> capitalize
|> hello
// "Conardli Hello!"

兩個(gè)互相競(jìng)爭(zhēng)的提案

關(guān)于管道運(yùn)算符,目前在 ES 中有兩個(gè)相互競(jìng)爭(zhēng)的提案:

  • Microsoft 提出的 F# :是一種函數(shù)式編程語(yǔ)言,其核心基于 OCaml,這個(gè)運(yùn)算符可以很方便的寫出柯里化風(fēng)格的代碼。
  • Meta 提出的 Hack:大致是 PHP 的靜態(tài)類型版本。這個(gè)管道運(yùn)算符專注于柯里化函數(shù)以外的語(yǔ)言特性。

目前來看,Meta 提出的 Hack 應(yīng)該更收社區(qū)的歡迎,Microsoft 提出的 F# 已經(jīng)多次被 TC39 打回去了。不過不用擔(dān)心,F(xiàn)# 的優(yōu)勢(shì)后續(xù)也可能會(huì)引入 Hack 中。

下面我們分別來看看兩個(gè)提案的用法吧。

Hack 管道運(yùn)算符

下面是一個(gè) Hack 管道運(yùn)算符 |> 的簡(jiǎn)單示例:

'ConardLi' |> console.log(%)  // ConardLi

管道運(yùn)算符 |> 的左側(cè)是一個(gè)表達(dá)式,它被計(jì)算并成為特殊變量 % 的值。我們可以在右側(cè)使用該變量。返回右側(cè)的執(zhí)行結(jié)果。前面的例子等價(jià)于:

console.log('ConardLi') // ConardLi

下面還有一些和其他寫法配合的例子:

value |> someFunction(1, %, 3) // function calls
value |> %.someMethod() // method call
value |> % + 1 // operator
value |> [%, 'b', 'c'] // Array literal
value |> {someProp: %} // object literal
value |> await % // awaiting a Promise
value |> (yield %) // yielding a generator value

下面我們?cè)賮砜磦€(gè)更復(fù)雜點(diǎn)的例子,一個(gè)嵌套函數(shù)調(diào)用:

const y = h(g(f(x)));

Hack pipe 操作符可以讓我們更好地表達(dá)這段代碼的意思:

const y = x |> f(%) |> g(%) |> h(%);

這段代碼更符合我們常規(guī)的編碼思想,代碼從左到右依次執(zhí)行:f、g、h。

F# 管道運(yùn)算符

F# 管道運(yùn)算符與 Hack 管道運(yùn)算符大致相似。但是,它沒有特殊變量 %。相反,運(yùn)算符右側(cè)的函數(shù)并會(huì)直接應(yīng)用于其左側(cè)。因此,以下兩個(gè)表達(dá)式是等價(jià)的:

'ConardLi' |> console.log

console.log('ConardLi')

因此 F# 管道運(yùn)算符更適合單參數(shù)的函數(shù),下面三個(gè)函數(shù)是等價(jià)的:

const y = h(g(f(x))); // no pipe
const y = x |> f(%) |> g(%) |> h(%); // Hack pipe
const y = x |> f |> g |> h; // F# pipe

在這種情況下,Hack pipe 比 F# pipe 更冗長(zhǎng)。

但是,如果是多參數(shù)的情況下,F(xiàn)# pipe 的寫法就要復(fù)雜一點(diǎn)了:

5 |> add2(1, %) // Hack pipe
5 |> $ => add2(1, $) // F# pipe

可以看到,F(xiàn)# pipe 還要多寫一個(gè)匿名函數(shù),這顯然相對(duì)與 Hack pipe 來講缺失了一些靈活性。這可能也是大家更傾向于 Hack pipe 的原因。

管道運(yùn)算符的一些實(shí)際用例

(1) 嵌套函數(shù)調(diào)用的扁平寫法

JavaScript 標(biāo)準(zhǔn)庫(kù)創(chuàng)建的所有迭代器都有一個(gè)共同的原型。這個(gè)原型是不能直接訪問的,但我們可以像這樣檢索它:

const IteratorPrototype =
Object.getPrototypeOf(
Object.getPrototypeOf(
[][Symbol.iterator]()
)
)
;

使用管道運(yùn)算符,代碼會(huì)更容易理解一些:

const IteratorPrototype =
[][Symbol.iterator]()
|> Object.getPrototypeOf(%)
|> Object.getPrototypeOf(%)
;

(2) 后期處理

看看下面的代碼:

function myFunc() {
// ···
return conardLi.someMethod();
}

如果現(xiàn)在我們想在函數(shù)返回前對(duì)返回值做一些其他的操作,我們應(yīng)該怎么辦呢?

在以前我們肯定要定義一個(gè)臨時(shí)變量或者在函數(shù)外側(cè)再包一個(gè)函數(shù),使用管道運(yùn)算符,我們可以這樣做:

function myFunc() {
// ···
return theResult |> (console.log(%), %); // (A)
}

在下面的代碼中,我們后處理的值是一個(gè)函數(shù) — 我們可以向它添加一個(gè)屬性:

const testPlus = () => {
assert.equal(3+4, 7);
} |> Object.assign(%, {
name: 'Test the plus operator',
});

前面的代碼等價(jià)于:

const testPlus = () => {
assert.equal(3+4, 7);
}
Object.assign(testPlus, {
name: 'Testing +',
});

我們也可以像這樣使用管道運(yùn)算符:

const testPlus = () => {
assert.equal(3+4, 7);
}
|> (%.name = 'Test the plus operator', %)
;

鏈?zhǔn)胶瘮?shù)調(diào)用

我們可以用 Array 的一些方法例如 .filter()和 .map() 實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用,但是這僅僅是內(nèi)置在數(shù)組里的一些方法,我們沒辦法通過庫(kù)引入更多的 Array 方法。

使用管道運(yùn)算符,我們可以像數(shù)組本身的方法一樣實(shí)現(xiàn)一些其他方法的鏈?zhǔn)秸{(diào)用:

import {Iterable} from '@rauschma/iterable/sync';
const {filter, map} = Iterable;

const resultSet = inputSet
|> filter(%, x => x >= 0)
|> map(%, x => x * 2)
|> new Set(%)
;

最后再回來看看標(biāo)題的代碼:

const regexOperators =
['*', '+', '[', ']']
.map(ch => escapeForRegExp(ch))
.join('')
|> '[' + % + ']'
|> new RegExp(%)
;

實(shí)際上就等價(jià)于:

let _ref;

const regexOperators =
(
(_ref = ['*', '+', '[', ']']
.map(ch => escapeForRegExp(ch))
.join('')),
new RegExp(`[${_ref}]`)
);

和引入中間變量相比,管道運(yùn)算符是不是更易于閱讀且簡(jiǎn)潔呢。

責(zé)任編輯:趙寧寧 來源: code秘密花園
相關(guān)推薦

2022-05-27 11:44:53

JS代碼

2021-04-15 13:48:08

視頻監(jiān)控視頻分析智能安防

2018-01-12 15:36:09

JavaScript參數(shù)功能

2017-12-26 15:34:55

2024-02-21 09:44:33

Rust前端

2021-08-03 11:09:41

智能手機(jī)功能技術(shù)

2017-10-27 12:28:14

云端遷移云計(jì)算

2018-08-23 07:24:40

MEC多接入邊緣計(jì)算網(wǎng)絡(luò)邊緣

2010-07-08 09:03:20

openSUSE 11Fedora

2019-10-28 15:10:31

懶人剪輯運(yùn)動(dòng)相機(jī)移動(dòng)應(yīng)用

2021-05-18 15:12:06

開源軟件云服務(wù)

2019-12-26 09:42:54

互聯(lián)網(wǎng)免費(fèi)收費(fèi)

2021-04-02 13:00:51

大數(shù)據(jù)數(shù)據(jù)采集

2023-02-21 09:29:57

ChatGPT人工智能

2011-12-01 09:33:17

Google微軟

2020-09-02 09:25:23

遷移公共云數(shù)據(jù)

2009-11-25 11:27:47

2013-05-14 09:12:01

Intel摩爾定律工藝制程

2022-06-16 20:56:53

邊緣計(jì)算

2018-10-09 15:12:38

內(nèi)存SSD價(jià)格
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)