前端基礎進階(七):函數與函數式編程

函數:菜鳥收割者

縱觀JavaScript中所有必須需要掌握的重點知識中,函數是我們在初學的時候最容易忽視的一個知識點。在學習的過程中,可能會有很多人、很多文章告訴你面向對象很重要,原型很重要,可是卻很少有人告訴你,面向對象中所有的重點難點,幾乎都與函數息息相關。

包括我之前幾篇文章介紹的執行上下文,變量對象,閉包,this等,都是圍繞函數的細節來展開。

我知道很多人在學習中,很急切的希望自己快一點開始學習面向對象,學習模塊,學習流行框架,然后迅速成為高手。但是我可以很負責的告訴你,關于函數的這些基礎東西沒理解到一定程度,那么你的學習進展一定是舉步維艱的。

所以,大家一定要重視函數!

當然,關于函數的重點,難點在前面幾篇文章都已經說得差不多了,這篇文章主要總結一下函數的基礎知識,并初步學習函數式編程的思維。

一、函數聲明、函數表達式、匿名函數與自執行函數

關于函數在實際開發中的應用,大體可以總結為函數聲明、函數表達式、匿名函數、自執行函數。

函數聲明

我們知道,JavaScript中,有兩種聲明方式,一個是使用var的變量聲明,另一個是使用function的函數聲明。

在前端基礎進階(三):變量對象詳解中我有提到過,變量對象的創建過程中,函數聲明比變量聲明具有更為優先的執行順序,即我們常常提到的函數聲明提前。因此我們在執行上下文中,無論在什么位置聲明了函數,我們都可以在同一個執行上下文中直接使用該函數。

fn();  // functionfunction fn() {console.log('function');
}

函數表達式

與函數聲明不同,函數表達式使用了var進行聲明,那么我們在確認他是否可以正確使用的時候就必須依照var的規則進行判斷,即變量聲明。我們知道使用var進行變量聲明,其實是進行了兩步操作。

// 變量聲明
var a = 20;// 實際執行順序
var a = undefined;  // 變量聲明,初始值undefined,變量提升,提升順序次于function聲明
a = 20;  // 變量賦值,該操作不會提升

同樣的道理,當我們使用變量聲明的方式來聲明函數時,就是我們常常說的函數表達式。函數表達的提升方式與變量聲明一致。

fn(); // 報錯
var fn = function() {console.log('function');
}

上例子的執行順序為:

var fn = undefined;   // 變量聲明提升
fn();    // 執行報錯
fn = function() {   // 賦值操作,此時將后邊函數的引用賦值給fnconsole.log('function');
}
因此,由于聲明方式的不同,導致了函數聲明與函數表達式在使用上的一些差異需要我們注意,除此之外,這兩種形式的函數在使用上并無不同。

關于上面例子中,函數表達式中的賦值操作,在其他一些地方也會被經常使用,我們清楚其中的關系即可。

在構造函數中添加方法
function Person(name) {this.name = name;this.age = age;// 在構造函數內部中添加方法this.getAge = function() {return this.age;}this.
}
// 給原型添加方法
Person.prototype.getName = function() {return this.name;
}// 在對象中添加方法
var a = {m: 20,getM: function() {return this.m;}
}

匿名函數

在上面我們大概講述了函數表達式中的賦值操作。而匿名函數,顧名思義,就是指的沒有被顯示進行賦值操作的函數。它的使用場景,多作為一個參數傳入另一個函數中。

var a = 10;
var fn = function(bar, num) {return bar() + num;
}fn(function() {return a;
}, 20)

在上面的例子中,fn的第一個參數傳入了一個匿名函數。雖然該匿名函數沒有顯示的進行賦值操作,我們沒有辦法在外部執行上下文中引用到它,但是在fn函數內部,我們將該匿名函數賦值給了變量bar,保存在了fn變量對象的arguments對象中。

// 變量對象在fn上下文執行過程中的創建階段
VO(fn) = {arguments: {bar: undefined,num: undefined,length: 2}
}// 變量對象在fn上下文執行過程中的執行階段
// 變量對象變為活動對象,并完成賦值操作與執行可執行代碼
VO -> AOAO(fn) = {arguments: {bar: function() { return a },num: 20,length: 2}
}

由于匿名函數傳入另一個函數之后,最終會在另一個函數中執行,因此我們也常常稱這個匿名函數為回調函數。關于匿名函數更多的內容,我會在下一篇深入探討柯里化的文章中進行更加詳細講解。

匿名函數的這個應用場景幾乎承擔了函數的所有難以理解的知識點,因此我們一定要對它的這些細節了解的足夠清楚,如果對于變量對象的演變過程你還看不太明白,一定要回過頭去看這篇文章:前端基礎進階(三):變量對象詳解

函數自執行與塊級作用域

在ES5中,沒有塊級作用域,因此我們常常使用函數自執行的方式來模仿塊級作用域,這樣就提供了一個獨立的執行上下文,結合閉包,就為模塊化提供了基礎。而函數自執行,其實是匿名函數的一種應用。

(function() {// ...
})();

一個模塊往往可以包括:私有變量、私有方法、公有變量、公有方法。

根據作用域鏈的單向訪問,外面可能很容易知道在這個獨立的模塊中,外部執行環境是無法訪問內部的任何變量與方法的,因此我們可以很容易的創建屬于這個模塊的私有變量與私有方法。

(function() {// 私有變量var age = 20;var name = 'Tom';// 私有方法function getName() {return `your name is ` + name;}
})();

但是共有方法和變量應該怎么辦?大家還記得我們前面講到過的閉包的特性嗎?沒錯,利用閉包,我們可以訪問到執行上下文內部的變量和方法,因此,我們只需要根據閉包的定義,創建一個閉包,將你認為需要公開的變量和方法開放出來即可。

如果你對閉包了解不夠,前端基礎進階(四):詳細圖解作用域鏈與閉包應該可以幫到你。
(function() {// 私有變量var age = 20;var name = 'Tom';// 私有方法function getName() {return `your name is ` + name;}// 共有方法function getAge() {return age;}// 將引用保存在外部執行環境的變量中,形成閉包,防止該執行環境被垃圾回收window.getAge = getAge;
})();

當然,閉包在模塊中的重要作用,我們也在講解閉包的時候已經強調過,但是這個知識點真的太重要,需要我們反復理解并且徹底掌握,因此為了幫助大家進一步理解閉包,我們來看看jQuery中,是如何利用我們模塊與閉包的。

// 使用函數自執行的方式創建模塊
(function(window, undefined) {// 聲明jQuery構造函數var jQuery = function(name) {// 主動在構造函數中,返回一個jQuery實例return new jQuery.fn.init(name);}// 添加原型方法jQuery.prototype = jQuery.fn = {constructor: jQuery,init:function() { ... },css: function() { ... }}jQuery.fn.init.prototype = jQuery.fn;// 將jQuery改名為$,并將引用保存在window上,形成閉包,對外開發jQuery構造函數,這樣我們就可以訪問所有掛載在jQuery原型上的方法了window.jQuery = window.$ = jQuery;})(window);// 在使用時,我們直接執行了構造函數,因為在jQuery的構造函數中通過一些手段,返回的是jQuery的實例,所以我們就不用再每次用的時候在自己new了
$('#div1');

在這里,我們只需要看懂閉包與模塊的部分就行了,至于內部的原型鏈是如何繞的,為什么會這樣寫,我在講面向對象的時候會為大家慢慢分析。舉這個例子的目的所在,就是希望大家能夠重視函數,因為在實際開發中,它無處不在。

接下來我要分享一個高級的,非常有用的模塊的應用。當我們的項目越來越大,那么需要保存的數據與狀態就越來越多,因此,我們需要一個專門的模塊來維護這些數據,這個時候,有一個叫做狀態管理器的東西就應運而生。對于狀態管理器,最出名的,我想非redux莫屬了。雖然對于還在學習中的大家來說,redux是一個有點高深莫測的東西,但是在我們學習之前,可以先通過簡單的方式,讓大家大致了解狀態管理器的實現原理,為我們未來的學習奠定堅實的基礎。

先來直接看代碼。

// 自執行創建模塊
(function() {// states 結構預覽// states = {//     a: 1,//     b: 2,//     m: 30,  //     o: {}// }var states = {};  // 私有變量,用來存儲狀態與數據// 判斷數據類型function type(elem) {if(elem == null) {return elem + '';}return toString.call(elem).replace(/[\[\]]/g, '').split(' ')[1].toLowerCase();}/*** @Param name 屬性名* @Description 通過屬性名獲取保存在states中的值*/function get(name) {return states[name] ? states[name] : '';}function getStates() {return states;}/** @param options {object} 鍵值對* @param target {object} 屬性值為對象的屬性,只在函數實現時遞歸中傳入* @desc 通過傳入鍵值對的方式修改state樹,使用方式與小程序的data或者react中的setStates類似*/function set(options, target) {var keys = Object.keys(options);var o = target ? target : states;keys.map(function(item) {if(typeof o[item] == 'undefined') {o[item] = options[item];}else {type(o[item]) == 'object' ? set(options[item], o[item]) : o[item] = options[item];}return item;})}// 對外提供接口window.get = get;window.set = set;window.getStates = getStates;
})()// 具體使用如下set({ a: 20 });     // 保存 屬性a
set({ b: 100 });    // 保存屬性b
set({ c: 10 });     // 保存屬性c// 保存屬性o, 它的值為一個對象
set({o: {m: 10,n: 20}
})// 修改對象o 的m值
set({o: {m: 1000}
})// 給對象o中增加一個c屬性
set({o: {c: 100}
})
console.log(getStates())

demo實例在線地址

我之所以說這是一個高級應用,是因為在單頁應用中,我們很可能會用到這樣的思路。根據我們提到過的知識,理解這個例子其實很簡單,其中的難點估計就在于set方法的處理上,因為為了具有更多的適用性,因此做了很多適配,用到了遞歸等知識。如果你暫時看不懂,沒有關系,知道如何使用就行了,上面的代碼可以直接運用于實際開發。記住,當你需要保存的狀態太多的時候,你就想到這一段代碼就行了。

函數自執行的方式另外還有其他幾種寫法,諸如!function(){}()+function(){}()
二、函數參數傳遞方式:按值傳遞

還記得基本數據類型與引用數據類型在復制上的差異嗎?基本數據類型復制,是直接值發生了復制,因此改變后,各自相互不影響。但是引用數據類型的復制,是保存在變量對象中的引用發生了復制,因此復制之后的這兩個引用實際訪問的實際是同一個堆內存中的值。當改變其中一個時,另外一個自然也被改變。如下例。

var a = 20;
var b = a;
b = 10;
console.log(a);  // 20var m = { a: 1, b: 2 }
var n = m;
n.a = 5;
console.log(m.a) // 5

當值作為函數的參數傳遞進入函數內部時,也有同樣的差異。我們知道,函數的參數在進入函數后,實際是被保存在了函數的變量對象中,因此,這個時候相當于發生了一次復制。如下例。

var a = 20;function fn(a) {a = a + 10;return a;
}
fn(a);
console.log(a); // 20
var a = { m: 10, n: 20 }
function fn(a) {a.m = 20;return a;
}fn(a);
console.log(a);   // { m: 20, n: 20 }

正是由于這樣的不同,導致了許多人在理解函數參數的傳遞方式時,就有許多困惑。到底是按值傳遞還是按引用傳遞?實際上結論仍然是按值傳遞,只不過當我們期望傳遞一個引用類型時,真正傳遞的,只是這個引用類型保存在變量對象中的引用而已。為了說明這個問題,我們看看下面這個例子。

var person = {name: 'Nicholas',age: 20
}function setName(obj) {  // 傳入一個引用obj = {};   // 將傳入的引用指向另外的值obj.name = 'Greg';  // 修改引用的name屬性
}setName(person);
console.log(person.name);  // Nicholas 未被改變

在上面的例子中,如果person是按引用傳遞,那么person就會自動被修改為指向其name屬性值為Gerg的新對象。但是我們從結果中看到,person對象并未發生任何改變,因此只是在函數內部引用被修改而已。

四、函數式編程

雖然JavaScript并不是一門純函數式編程的語言,但是它使用了許多函數式編程的特性。因此了解這些特性可以讓我們更加了解自己寫的代碼。

當我們想要使用一個函數時,通常情況下其實就是想要將一些功能,邏輯等封裝起來。相信大家對于封裝這個概念并不陌生。

我們通常通過函數封裝來完成一件事情。例如,我想要計算任意三個數的和,我們就可以將這三個數作為參數,封裝一個簡單的函數。

function add(a, b, c) {return a + b + c;
}

當我們想要計算三個數的和時,直接調用該方法即可。

add(1, 2, 3); // 6

當然,當我們想要做的事情比較簡單的時候,可能還看不出來封裝成為函數之后帶來的便利。如果我們想要做的事情稍微復雜一點呢。例如我想要計算一個數組中的所有子項目的和。

function mergeArr(arr) {var result = 0;for(var i = 0; i < arr.length; i++) { result  += arr[i] }return result;
}

如果我們不通過函數封裝的方式,那么再每次想要實現這個功能時,就不得不重新使用一次for循環,這樣的后果就是我們的代碼中充斥著越來越多的重復代碼。而封裝之后,當我們想要再次做這件事情的時候,只需要一句話就可以了。

mergeArr([1, 2, 3, 4, 5]);

當然,我相信大家對于函數封裝的意義都應該有非常明確的認知,但是我們要面臨的問題是,當我們想要去封裝一個函數時,如何做才是最佳實踐呢?

函數式編程能給我們答案。

我們在初學時,往往會不由自主的使用命令式編程的風格來完成我們想要干的事情。因為命令式編程更加的簡單,直白。例如我們現在有一個數組,array = [1, 3, 'h', 5, 'm', '4'],現在想要找出這個數組中的所有類型為number的子項。當我們使用命令式編程思維時,可能就會直接這樣做。

var array = [1, 3, 'h', 5, 'm', '4'];
var res = [];
for(var i = 0; i < array.length; i ++) {if (typeof array[i] === 'number') {res.push(array[i]);}
}

在這種實現方式中,我們平鋪直敘的實現了我們的目的。這樣做的問題在于,當我們在另外的時刻,想要找出另外一個數組中所有的子項時,我們不得不把同樣的邏輯再寫一次。當出現次數變多時,我們的代碼也變得更加糟糕且難以維護。

而函數式編程的思維則建議我們將這種會多次出現的功能封裝起來以備調用。

function getNumbers(array) {var res = [];array.forEach(function(item) {if (typeof item === 'number') {res.push(item);}})return res;
}// 以上是我們的封裝,以下是功能實現
var array = [1, 3, 'h', 5, 'm', '4'];
var res = getNumbers(array);

因此當我們將功能封裝之后,我們實現同樣的功能時,只需要寫一行代碼。而如果未來需求變動,或者稍作修改,我們只需要對getNumbers方法進行調整就可以了。而且我們在使用時,只需要關心這個方法能做什么,而不用關心他具體是怎么實現的。這也是函數式編程思維與命令式不同的地方之一。

函數式編程思維還具有以下幾個特征。

函數是第一等公民

所謂"第一等公民"(first class),指的是函數與其他數據類型一樣,處于平等地位,可以賦值給其他變量,也可以作為參數,傳入另一個函數,或者作為別的函數的返回值。這些場景,我們應該見過很多。

var a = function foo() {}  // 賦值
function fn(function() {}, num) {}   // 函數作為參數// 函數作為返回值
function var() {return function() {... ...}
}

當然,這都是JavaScript的基本概念。但是我想很多人,甚至包括正在閱讀的你自己都可能會無視這些概念。可以用一個簡單的例子來驗證一下。

我們先自定義這樣一個函數。

function delay() {console.log('5000ms之后執行該方法.');
}

現在要做的是,如果要求你結合setTimeout方法,讓delay方法延遲5000ms執行,應該怎么做?

其實很簡單,對不對,直接這樣就可以了。

var timer = setTimeout(function() {delay();
}, 5000);

那么現在問題來了,如果你對函數是一等公民有一個深刻的認知,我想你會發現上面這種寫法其實是有一些問題的。所以思考一下,問題出在哪里?

函數既然能夠作為一個參數傳入另外一個函數,那么我們是不是可以直接將delay作為setTimeout的第一個參數,而不用額外的多加一層匿名函數呢?

因此,其實最正確的解法應該這樣寫。

var timer = setTimeout(delay, 5000);

當然,如果你已經提前想到這樣做了,那么恭喜你,說明你在JavaScript上比普通人更有天賦。其實第一種糟糕的方式很多人都在用,包括有多年工作經驗的人也沒有完全避免。而他們甚至還不知道自己問題出在什么地方。

在未來的實踐中,你還會遇到更多類似的場景。為了驗證讀者朋友們的理解,我們不妨來思考一下如何優化下面的代碼。

function getUser(path, callback) {return $.get(path, function(info) {return callback(info);})
}getUser('/api/user', function(resp) {// resp為成功請求之后返回的數據console.log(resp);
})

優化的原理和setTimeout的例子一模一樣,我這里賣個關子,不打算告訴大家結論,僅提示一句,getUser優化之后,僅有一句代碼。考驗大家學習成果的時候到了 ^ ^。

只用"表達式",不用"語句"

"表達式"(expression)是一個單純的運算過程,總是有返回值;"語句"(statement)是執行某種操作,沒有返回值。函數式編程要求,只使用表達式,不使用語句。也就是說,每一步都是單純的運算,而且都有返回值。

假如我們的項目中,多處需要改變某個元素的背景色。因此我們可以這樣封裝一下。

var ele = document.querySelector('.test');
function setBackgroundColor(color) {ele.style.backgroundColor = color;
}// 多處使用
setBackgroundColor('red');
setBackgroundColor('#ccc');

我們可以很明顯的感受到,setBackgroundColor封裝的僅僅只是一條語句。這并不是理想的效果。函數式編程期望一個函數有輸入,也有輸出。因此良好的習慣應該如下做。

function setBackgroundColor(ele, color) {ele.style.backgroundColor = color;return color;
}// 多處使用
var ele = document.querySelector('.test');
setBackgroundColor(ele, 'red');
setBackgroundColor(ele, '#ccc');

了解這一點,可以讓我們自己在封裝函數的時候養成良好的習慣。

純函數

相同的輸入總會得到相同的輸出,并且不會產生副作用的函數,就是純函數。

所謂"副作用"(side effect),指的是函數內部與外部互動(最典型的情況,就是修改全局變量的值),產生運算以外的其他結果。

函數式編程強調沒有"副作用",意味著函數要保持獨立,所有功能就是返回一個新的值,沒有其他行為,尤其是不得修改外部變量的值。

即所謂的只要是同樣的參數傳入,返回的結果一定是相等的。

例如我們期望封裝一個函數,能夠得到傳入數組的最后一項。那么可以通過下面兩種方式來實現。

function getLast(arr) {return arr[arr.length];
}function getLast_(arr) {return arr.pop();
}var source = [1, 2, 3, 4];var last = getLast(source); // 返回結果4 原數組不變
var last_ = getLast_(source); // 返回結果4 原數據最后一項被刪除

getLast與getLast_雖然同樣能夠獲得數組的最后一項值,但是getLast_改變了原數組。而當原始數組被改變,那么當我們再次調用該方法時,得到的結果就會變得不一樣。這樣不可預測的封裝方式,在我們看來是非常糟糕的。它會把我們的數據搞得非常混亂。在JavaScript原生支持的數據方法中,也有許多不純的方法,我們在使用時需要非常警惕,我們要清晰的知道原始數據的改變是否會留下隱患。

var source = [1, 2, 3, 4, 5];source.slice(1, 3); // 純函數 返回[2, 3] source不變
source.splice(1, 3); // 不純的 返回[2, 3, 4] source被改變source.pop(); // 不純的
source.push(6); // 不純的
source.shift(); // 不純的
source.unshift(1); // 不純的
source.reverse(); // 不純的// 我也不能短時間知道現在source被改變成了什么樣子,干脆重新約定一下
source = [1, 2, 3, 4, 5];source.concat([6, 7]); // 純函數 返回[1, 2, 3, 4, 5, 6, 7] source不變
source.join('-'); // 純函數 返回1-2-3-4-5 source不變

閉包

閉包是函數式編程語言的重要特性,我也在前面幾篇文章中說了很多關于閉包的內容。這里不再贅述。

柯里化

下一章。

前端基礎進階系列目錄

clipboard.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/391603.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/391603.shtml
英文地址,請注明出處:http://en.pswp.cn/news/391603.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

期權數據 獲取_我如何免費獲得期權數據

期權數據 獲取by Harry Sauers哈里紹爾斯(Harry Sauers) 我如何免費獲得期權數據 (How I get options data for free) 網頁抓取金融簡介 (An introduction to web scraping for finance) Ever wished you could access historical options data, but got blocked by a paywall…

顯示與刪除使用工具

右擊工具菜單欄中的空白處選擇自定義 在彈出的自定義菜單中選擇命令選項在選擇想要往里面添加工具的菜單&#xff0c;之后在選擇要添加的工具 若想要刪除工具欄中的某個工具&#xff0c;在打開自定義菜單后&#xff0c;按住鼠標左鍵拖動要刪除工具到空白處 例如 轉載于:https:/…

js值的拷貝和值的引用_到達P值的底部:直觀的解釋

js值的拷貝和值的引用介紹 (Introduction) Welcome to this lesson on calculating p-values.歡迎參加有關計算p值的課程。 Before we jump into how to calculate a p-value, it’s important to think about what the p-value is really for.在我們開始計算p值之前&#xff…

leetcode 115. 不同的子序列(dp)

給定一個字符串 s 和一個字符串 t &#xff0c;計算在 s 的子序列中 t 出現的個數。 字符串的一個 子序列 是指&#xff0c;通過刪除一些&#xff08;也可以不刪除&#xff09;字符且不干擾剩余字符相對位置所組成的新字符串。&#xff08;例如&#xff0c;“ACE” 是 “ABCDE…

監督學習-KNN最鄰近分類算法

分類&#xff08;Classification&#xff09;指的是從數據中選出已經分好類的訓練集&#xff0c;在該訓練集上運用數據挖掘分類的技術建立分類模型&#xff0c;從而對沒有分類的數據進行分類的分析方法。 分類問題的應用場景&#xff1a;用于將事物打上一個標簽&#xff0c;通常…

istio 和 kong_如何啟動和運行Istio

istio 和 kongby Chris Cooney克里斯庫尼(Chris Cooney) 如何啟動和運行Istio (How to get Istio up and running) 而一旦完成&#xff0c;您就可以做的瘋狂的事情。 (And the crazy stuff you can do once it is.) The moment you get Istio working on your cluster, it fee…

js練習--貪吃蛇(轉)

最近一直在看javascript&#xff0c;但是發現不了動力。就開始想找動力&#xff0c;于是在網上找到了一個用js寫的貪吃蛇游戲。奈何還不會用git&#xff0c;就只能先這樣保存著。哈哈哈&#xff0c;這也算第一篇博客了&#xff0c;以后會堅持用自己的代碼寫博客的&#xff0c;下…

bzoj千題計劃169:bzoj2463: [中山市選2009]誰能贏呢?

http://www.lydsy.com/JudgeOnline/problem.php?id2463 n為偶數時&#xff0c;一定可以被若干個1*2 矩形覆蓋 先手每次從矩形的一端走向另一端&#xff0c;后手每次走向一個新的矩形 所以先手必勝 n為奇數時&#xff0c;先手走完一步后&#xff0c;剩下同n為偶數 所以先手必敗…

無監督學習-主成分分析和聚類分析

聚類分析&#xff08;cluster analysis&#xff09;是將一組研究對象分為相對同質的群組&#xff08;clusters&#xff09;的統計分析技術&#xff0c;即將觀測對象的群體按照相似性和相異性進行不同群組的劃分&#xff0c;劃分后每個群組內部各對象相似度很高&#xff0c;而不…

struts實現分頁_在TensorFlow中實現點Struts

struts實現分頁If you want to get started on 3D Object Detection and more specifically on Point Pillars, I have a series of posts written on it just for that purpose. Here’s the link. Also, going through the Point Pillars paper directly will be really help…

封裝jQuery下載文件組件

使用jQuery導出文檔文件 jQuery添加download組件 jQuery.download function(url, data, method){if( url && data ){data typeof data string ? data : paramEdit(data);     function paramEdit(obj){        var temStr "",tempStr"…

7.13. parallel - build and execute shell command lines from standard input in parallel

并行執行shell命令 $ sudo apt-get install parallel 例 7.5. parallel - build and execute shell command lines from standard input in parallel $ cat *.csv | parallel --pipe grep 13113 設置塊大小 $ cat *.csv | parallel --block 10M --pipe grep 131136688 原…

MySQL-InnoDB索引實現

聯合索引提高查詢效率的原理 MySQL會為InnoDB的每個表建立聚簇索引&#xff0c;如果表有索引會建立二級索引。聚簇索引以主鍵建立索引&#xff0c;如果沒有主鍵以表中的唯一鍵建立&#xff0c;唯一鍵也沒會以隱式的創建一個自增的列來建立。聚簇索引和二級索引都是一個b樹&…

Go語言-基本的http請求操作

Go發起GET請求 基本的GET請求 //基本的GET請求 package mainimport ("fmt""io/ioutil""net/http" )func main() {resp, err : http.Get("http://www.hao123.com")if err ! nil {fmt.Println(err)return}defer resp.Body.Close()body, …

釘釘設置jira機器人_這是當您機器學習JIRA票證時發生的事情

釘釘設置jira機器人For software developers, one of the most-debated and maybe even most-hated questions is “…and how long will it take?”. I’ve experienced those discussions myself, which oftentimes lacked precise information on the requirements. What I…

python的賦值與參數傳遞(python和linux切換)

1&#xff0c;python模式切回成linux模式------exit&#xff08;&#xff09; linux模式切換成python模式------python 2,在linux里運行python的復合語句&#xff08;得在linux創建.py文件&#xff09; touch le.py vim le.py----在le文件里輸入python語句 #!/usr/bin/python …

vscode 標準庫位置_如何在VSCode中使用標準

vscode 標準庫位置I use Visual Studio Code as my text editor. When I write JavaScript, I follow JavaScript Standard Style.Theres an easy way to integrate Standard in VS Code—with the vscode-standardjs plugin. I made a video for this some time ago if youre …

leetcode 1603. 設計停車系統

請你給一個停車場設計一個停車系統。停車場總共有三種不同大小的車位&#xff1a;大&#xff0c;中和小&#xff0c;每種尺寸分別有固定數目的車位。 請你實現 ParkingSystem 類&#xff1a; ParkingSystem(int big, int medium, int small) 初始化 ParkingSystem 類&#xf…

IBM量子計算新突破:成功構建50個量子比特原型機

本文來自AI新媒體量子位&#xff08;QbitAI&#xff09;IBM去年開始以云計算服務的形式提供量子計算能力。當時&#xff0c;IBM發布了包含5個量子比特的計算機。在短短18個月之后&#xff0c;IBM周五宣布&#xff0c;將發布包含20個量子比特的計算機。 IBM還宣布&#xff0c;該…

ChromeDriver與chrome對應關系

http://chromedriver.storage.googleapis.com/index.html 轉載于:https://www.cnblogs.com/gcgc/p/11387605.html