全球最大!亞洲巨型殺人蜂入侵 美國發現史上第一個蜂巢

摘錄自2020年10月24日自由時報報導

美國華盛頓州官方23日證實,專家在當地發現美國有史以來第一個「亞洲巨型殺人蜂」的蜂巢,敲響象徵著生態浩劫的警鐘。

根據《CNN》報導,大虎頭蜂分布於亞洲地區,以其巨大體型及兇猛的天性贏得「巨型殺人蜂」(giant murder hornets)的渾號,是世上體型最大的蜂類。美國華盛頓州農業部(WSDA)的昆蟲學家昨日在該州布萊恩鎮(Blaine)發現一個大虎頭蜂巢,是美國境內有史以來首見。

這並非大虎頭蜂首度現身北美,當局去年12月就曾於華盛頓州發現大虎頭蜂身影,不過當時並未找到任何蜂巢的蹤影,如今這次發現象徵該物種已於美國落地生根,未來恐成為優勢外來物種,對當地生物構成嚴重威脅。

生物多樣性
國際新聞
美國
華盛頓
外來種昆蟲

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

美國淨水廠遭駭客入侵險釀大禍 原因竟是使用TeamViewer還共用密碼

美國近日有一家淨水廠遭到駭客入侵,駭客差點成功的影響淨水廠輸出的水質,最後還好被管理員及時發現。而根據調查,淨水廠被入侵的原因,跟他們到現在還在使用Windows 7、高風險的遠端桌面軟體TeamViewer、公司網路沒有防火牆以及他們平時會共用密碼等不安全的行為所導致。

↑美國一間淨水廠遭到駭客入侵,差點送出危害人體的原水出去。(示意圖/pixabay)

綜合外媒報導指出,位於美國佛羅里達州奧德瑪爾市的淨水場,於5日遭到駭客入侵,內部電腦遭駭客透過TeamViewer存取成功,當時駭客試圖透過淨水廠內的電腦調整淨水廠的水質,要將原本用來調整水質的氫氧化鈉濃度從原本的100ppm調高至11100ppm,還好當時淨水廠內的管理員及時發現,才沒有因此釀成大禍。

事發之後,美國麻薩諸塞州州政府在一份給與境內公共給水業者的公告中,說明了佛羅里達州淨水廠的駭客事件事發經過。在公告中可以看到,這家遭到駭客入侵的佛州淨水廠,平時用來管理系統狀況、問題排查的電腦,到現在還是使用早已停止更新的Windows 7,而且所有廠內的管理員都可以使用TeamViewer進行遠端連線,所使用的帳號密碼還都是相同的。而且這台電腦除了有與外部網路進行直接連接外,公司網路也沒有裝設任何防火牆,就資安角度來看,可以說是問題重重。

而美國聯邦調查局(FBI)也在事發之後,發布了民營產業安全通知(Private Industry Notice,PIN),內容中警告民營企業「微軟早已停止對Windows 7的更新」,呼籲大家及早更換作業系統。而對於TeamViewer,FBI並沒有多作批評,但是則是強調這類型的遠端軟體使用時必須要搭配組成複雜的「強密碼」,而且平時使用時要保持警覺性。否則密碼外洩時會造成嚴重的後果,比如讓攻擊者可以透過登入TeamViewer後,在電腦中安裝木馬程式或惡意軟體。

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

澳研究:吃下塑膠的魚類行為更大膽活躍 生存率降低

摘錄自2020年10月28日聯合新聞網報導

澳洲最新研究指出,塑膠微粒能夠改變魚類的行為,吃下塑膠微粒的魚類,牠們傾向於變得更大膽、活躍,比起其他魚類生存率更低。

每日郵報報導,澳洲詹姆斯庫克大學(James Cook University)研究團隊在澳洲大堡礁水域捕捉幼魚,並連續四天餵食牠們除了豐年蝦(brine shrimp)以外的塑膠微粒。科學家將牠們標記後放回海裡觀察其行為,研究塑膠微粒是否對魚類造成影響。

科學家表示,他們不認為這是因為塑膠對魚類產生有毒影響,而是魚類在吃進塑膠後會更飢餓,這種「營養需求壓力」促使牠們更傾向於冒險尋找食物,而該冒險行為使牠們更容易被掠食者吃掉。

該研究領導學者麥考密克(Mark McCormick)表示,魚類行為上的改變及其對生存的影響,是因魚類吃下塑膠微粒後變得飽足但事實上卻沒有獲得營養。

海洋
污染治理
國際新聞
澳洲
塑膠微粒

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計最專業,超強功能平台可客製化

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家公司費用怎麼算?

核食檢測眉角多 日政府無心 民間自發學習輻射測定

文:宋瑞文(媽媽監督核電廠聯盟特約撰述)

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※超省錢租車方案

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

※推薦台中搬家公司優質服務,可到府估價

颶風伊塔威力增強 預計登陸中美洲地區

摘錄自2020年11月3日中央社報導

颶風伊塔(Eta)在加勒比海(Caribbean Sea)增強威力後,今(3日)預計登陸中美洲地區,宏都拉斯和尼加拉瓜等國恐面臨災難性的強風及洪水威脅。

法新社報導,美國國家颶風中心(National Hurricane Center)在午夜預警指出,這個「極度危險」颶風的風速達到每小時240公里,正往尼加拉瓜海岸前進。中美洲部分地區預計將出現暴潮、強風、暴洪及土石流等災情。

尼加拉瓜近海的密斯基多群島(Miskito Cays)當地的婦女和孩童已從村莊撤離,只剩男性留下來看顧房子,倘若情況變得更加危險,男性也會撤離避難。

加勒比海與中美洲的其他地區也可能面臨颶風伊塔的侵襲,國家颶風中心指出,牙買加、墨西哥東南部、薩爾瓦多、海地南部及開曼群島都可能出現洪患。

氣候變遷
國際新聞
中美洲
颶風

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※回頭車貨運收費標準

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

確認以 GT 為名! realme GT 高通 S888 新旗艦將於 3/4 14:00 正式發表

昨(17)日我們才報導過 realme 副總裁徐起在微博暗示接下來 realme 的高通 Snapdragon 888 新旗艦將命名為 GT 系列的暗示,想不到在今(18)日稍早官方證實了此消息,同時預告 realme GT 的新機發表會時間就訂在 3 月 4 日。徐起也暗示 realme GT 不僅擁有 Snapdragon 888 的澎湃性能,還擁有持久續航和和高螢幕更新率。

▲圖片來源:徐起Chase(微博)

確認以 GT 為名! realme GT 高通 S888 新旗艦將於 3/4 14:00 正式發表

經過前幾天 realme 副總裁徐起在微博暗示 realme 這款內部代號「Race」的 Snapdragon 888 旗艦為 realme GT,稍早官方正式公開證實此消息,同時也預告 3 月 4 日下午 2 點舉行 realme GT 新機發表會。

▲圖片來源:徐起Chase(微博)

徐起在微博的貼文也提及 realme GT 將追求極致、挑戰「120% 的自己」,不過目前還無法肯定 120 的暗示是指 120Hz 螢幕更新率或 120W 快速充電。不過在 realme GT 首張官方宣傳海報左下角有三個圖示暗示 realme GT 的三大特色,從圖示推測由左至右依序為處理器、螢幕更新率和充電。根據過去的傳聞, realme GT 將搭載 Qualcomm Snapdragon 888 旗艦行動平台、 120Hz 螢幕更新率和 125W UltraDart 超級閃充。

▲圖片來源:徐起Chase(微博)

去年 7 月 16 亮相自家的 125W UltraDart 超級閃充技術 ,標榜只要充電 3 分鐘就能為 4000mAh 電池容量的手機充電達到 33% 電量。不過至今 125W UltraDart 超級閃充還未在 realme 旗下手機搭載,目前還是以 65W SuperDart 閃充為主流,不排除有機會在 realme GT 首次搭載。

▲圖片來源:realme真我手機(微博)

稍早數碼閒聊站在微博透露, realmeGT 將推出素皮和玻璃兩種版本,並提及在設計上有新東西:

▲圖片來源:數碼閒聊站(微博)

其實大約兩週前, realme GT 機身外觀就已經在中國工信部資料庫曝光,螢幕正面採用左上角採單挖孔的平面全螢幕設計,同時也採用光學螢幕下指紋辨識。在 realme GT 的機身背面下緣加入 GT 字樣。至於相機規格目前還無法得知,不過據過去傳聞將配備四鏡頭主相機設計。

▲圖片來源:TENAA

接下來在 3 月中旬前已經有多款新機即將陸續推出,目前可確認的依序為 2 月 22 日發表華為 Mate X2 、2 月 25 日發表紅米 Redmi K40 系列,以及 3 月 4 日將發表紅米 Redmi Note 10 系列和 realme GT 。另外,稍早 ROG 遊戲手機官方微博也確認新一代 ROG Phone 遊戲手機命名為 ROG Phone 5 ,在中國市場也是連續第三年和騰訊遊戲合作,預計也會在 3 月正式亮相。

消息來源:徐起Chase(微博)

延伸閱讀:
Redmi Note 10 系列確定將於 3/4 全球發表,相機與螢幕為此次升級重點

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

中型車都打七折賣了!有面子又有空間,還買什麼小車?

98萬東風日產 天籟售價:17。58-29。88萬總結:今天介紹的這幾款車型目前來說,市場的終端優惠確實不少,而中級車相對而言實用性更好。現代名圖作為一款准中級車,本來的起步價就比較低廉,它大氣的外觀造型與寬敞是它的優勢,唯一就是品牌的認可度了。

就目前的緊湊車市場而言,屬於各個合資廠商拚命競爭的領地,數量眾多的車型使得消費者的選擇難度大增,但相較而言中級車的實用性更強,相對價格更高,不過在看來最近中級車的優惠很大,這樣對比一下緊湊車就沒有那麼值得購買了,接下來就看看目前市場上優惠較大的幾款中級車吧!

北京現代 名圖

售價:12.98-17.68萬

上汽通用雪佛蘭 邁銳寶

售價:16.49-19.99萬

廣汽本田 雅閣

售價:16.98-27.98萬

東風日產 天籟

售價:17.58-29.88萬

總結:今天介紹的這幾款車型目前來說,市場的終端優惠確實不少,而中級車相對而言實用性更好。現代名圖作為一款准中級車,本來的起步價就比較低廉,它大氣的外觀造型與寬敞是它的優勢,唯一就是品牌的認可度了。邁銳寶作為一款中級車,它的外觀造型年輕時尚,相比最新的邁銳寶XL相差不大,加上如今較大的優惠,性價比更高,很適合年輕人的心水。

最後介紹的這兩款車型都是年輕化的代表,雅閣之前作為中級車的領頭羊,如今變得更加的時尚但它的內飾與實用性一直得到延續,配上它如今更低的起步價與優惠,很適合家用購買。天籟同樣在向年輕進發,全新家族式造型與傳統的大沙髮結合,時尚與家用變得不再矛盾。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

10萬 20萬的車,如何用最少的錢買到最合適的配置?

這樣一來,發動機的動力被分配給四個車輪,遇到路況不好才不易出現車輪打滑,汽車的通過能力得到相當大地改善。推薦指數:不少人對四驅車有誤解,認為四驅車能在任何地形奔跑,實際上是誇大了它的能耐,即使是HUMMER,也不能在野外隨便撒野。

“小心開車”、“慢點開”,這一句句耳熟能詳的叮囑,大家是否上心?一次次地板油、併線超車想起長輩們的話時又會否鬆開油門?開車上路,安全是重中之重,開快車痛快之餘亦要對他人負責任,應在不影響交通秩序、確保行人安全的情況下釋放個人駕駛慾望。

因此,不少深知叮囑無用的長輩在給年輕人選購汽車時,會十分重視汽車的安全配置,讓它們去為不羈放縱的年輕人保駕護航、最大程度地提高出行的安全係數。

下面就為大家介紹市面上哪些安全配置不可或缺,哪些又是無足輕重的雞肋配置,教會你更精明地選車、獲得更理想的消費比,並推薦幾款各個價位中安全配置厚道的車型供大家參考。

車身电子穩定系統(ESp:Electronic Stability program):提升車輛的操控表現的同時、有效地防止汽車達到其動態極限時失控的系統或程序,提升車輛的安全性和操控性。

推薦指數:

當縱向力達到極值時(如車輪抱死),側向力即為0,車輛的橫向運動將不受控制,發生側滑,此時車輛可能無法按司機的意願進行變道或者轉彎。當电子穩定程序檢測到車輛將要失控,向特定的車輪施加制動力從而幫助車輛按照駕駛者期望的方向前進,在冰雪、濕滑環境ESp尤為重要。

聽着高大上對吧?但如果你認為配備ESp就能隨便撒野那就大錯特錯了,ESp通常在60、70km/h時速的介入效果比較明顯,速度過高進行極限操作ESp也無能為力,別回頭釀成事故就把屎盆子往ESp頭上扣。

电子剎車輔助系統(Electronic Brake Assistant,EBA):是為在緊急事件中,駕駛者不能迅速踩下剎車踏板而設計的。利用傳感器感應駕駛者對制動踏板踩踏的力度與速度大小,通過計算機判斷駕駛者該次剎車意圖。如果屬於緊急制動,EBA會指示制動系統產生更高的油壓使ABS制動防抱死系統發揮作用,使制動力迅速產生,縮短制動距離。而對於正常情況剎車,EBA則會通過判斷不予啟動ABS。

EBA能有效預防都市常見的“追尾”事故發生。

推薦指數:

主動剎車功能:指車輛在非自適應巡航的情況下遇到突發危險情況時能自身主動產生制動效果讓車輛減速(不一定能將車完全剎停)從而提高行車安全性的一種技術。

通過車四周的傳感器就像個雷達一樣,當發現有不可避免的碰撞發生時,自動剎車系統會提前介入,在駕駛員沒有反應過來之前進行制動,減少碰撞能量。著名的要數沃爾沃2010年推出的城市安全系統主動防碰撞技術。

推薦指數:

胎壓監測系統(TpMS:Tire pressure Monitoring System):分為兩種,一種是間接式,通過輪胎的轉速差來判斷輪胎是否異常;另一種是直接式,通過在輪胎裏面加裝四個胎壓監測傳感器,對輪胎氣壓和溫度進行實時自動監測,並在發現異常時及時警告,避免引發的交通事故,及時排除安全隱患。

推薦指數:

电子安全氣囊:發生碰撞事故達到規定強度,傳感器產生動作向电子控制器,後者與原存儲信號比較,若達到氣囊展開條件,就驅動電路啟動氣體發生器,引燃氣體發生劑,產生大量氣體,經過濾並冷卻後進入氣囊,在極短時間內突破襯墊迅速展開,形成彈性氣墊,並及時泄漏、收縮,緩衝衝擊能量,使人體免於傷害或減輕受傷程度。

推薦指數:

ACC自適應巡航:行駛過程中,安裝在前部的車距傳感器持續掃描前方道路,同時輪速傳感器採集車速信號。當與前車之間的距離過小時,ACC通過與制動防抱死系統、發動機控制系統協調運作,使車輪適當制動、發動機的輸出功率下降,使車輛與前方車輛始終保持安全距離。相比定速巡航要實用,跑高速最大程度釋放你勞累的右腳。

推薦指數:

倒車影像、倒車雷達:又稱泊車輔助系統,通過安裝在車身上的攝像頭,超聲波傳感器,以及紅外傳感器,探測停車位置,繪製停車地圖,並實時動態規劃泊車路徑,將汽車指引或者直接操控方向盤駛入停車位置,當與障礙物距離小於規定距離時會發出警報或座椅震動提醒駕駛員。十分實用的一項配置,能觀察到小朋友、小動物位於車身後方的視角盲點。

推薦指數:

四驅系統:四輪驅動顧名思義就是汽車四個車輪都能得到驅動力。這樣一來,發動機的動力被分配給四個車輪,遇到路況不好才不易出現車輪打滑,汽車的通過能力得到相當大地改善。

推薦指數:

不少人對四驅車有誤解,認為四驅車能在任何地形奔跑,實際上是誇大了它的能耐,即使是HUMMER,也不能在野外隨便撒野。四驅車並非萬能,沒有四驅系統反而傳動效率更高跑起來姿態更矯健輕盈,所以同款車二驅版本的加速成績通常比四驅車版本要快。

牽引力控制系統(TCS:Traction Control System):即循跡控制系統,根據驅動輪的轉數及傳動輪的轉數來判定驅動輪是否發生打滑現象,當前者大於後者時,抑制驅動輪轉速的防滑控制系統。汽車在光滑路面制動時,車輪會打滑,甚至使方向失控。同樣,汽車在起步或急加速時,驅動輪也有可能打滑。

推薦指數:

电子制動力分配(EBD:Electronic Brake force Distribution):當發生緊急制動時,EBD在ABS作用之前,依據車身的重量和路麵條件,自動以前輪為基準去比較後輪的滑動率,如發覺此差異程度必須被調整時,剎車油壓系統將會調整傳至後輪的油壓,以得到更平衡且更接近理想化的剎車力分佈。

EBD是在ABS的控制電腦里增加的一個控制軟件,機械系統與ABS完全一致,ABS系統的輔助功能、有效補充,組合使用,提高ABS功效。

推薦指數:

剎車優先系統(BOS:Brake Over ride System):踩剎車時向行車電腦發出信號,行車電腦在通知ABS準備工作的同時,也向供油系統發出指令,將噴油量降低到怠速水平,這樣即使剎車失靈,也能把車速降下來,不會出現車越跑越快、失控的情況。

推薦指數:

上坡輔助:車輛在陡峭或光滑坡面上起步時,駕駛員從制動踏板切換至油門踏板車輛將向後下滑,從而導致起步困難。為防止此情況發生,上坡起步輔助控制暫時(最長約2秒)對四個車輪施加制動以阻止車輛下滑。

推薦指數:

安全配置厚道的車型

吉利-帝豪GS 2016款 優雅版 1.3T 自動領尚型 售價9.48萬

1.3T雙離合版本標配胎壓監測裝置、ABS防抱死、制動力分配、剎車輔助、牽引力控制、車身穩定控制、上坡輔助、后雷達和倒車影像。安全配置十分厚道的帝豪GS,那副討喜的外觀,不愧為同價位自主SUV的佼佼者。

本田-思域 2016款 220TURBO 自動豪華版 售價:13.99萬

全系標配胎壓監測裝置、ABS防抱死、制動力分配、剎車輔助、牽引力控制、車身穩定控制、上坡輔助、自動駐車、后雷達和倒車影像。豐富的入門配置、強勁的動力、優秀的油耗表現,有潛力成為緊湊型車的新霸主。

觀致5 2017款 1.6T 自動領先型 售價:15.99萬

全系標配ABS防抱死、制動力分配、剎車輔助、牽引力控制、車身穩定控制、上坡輔助、自動駐車,獲要知道兄弟車型觀致3可是在嚴格的E-NCAp測試當中為數不多獲得五星評價的車型,觀致在安全性方面的造詣可見一斑。

沃爾沃S60L 2017款 1.5T T3 智行版 售價:26.69萬

全系標配胎壓監測裝置、ABS防抱死、制動力分配、剎車輔助、牽引力控制、車身穩定控制、上坡輔助、自動駐車、后雷達和倒車影像。談及汽車安全性,不得不提及安全起家的沃爾沃,主副駕駛座安全氣囊、前排側氣囊、前後排頭部氣囊(氣簾)全部齊全,最大程度地提高艙內乘員的安全係數,以人為本。

總結:再齊全的安全配置也敵不過糟糕的駕駛習慣,像變道要打燈、遠光燈視情況而開、搶紅不搶綠這些就不一一贅述了。“常在河邊走,哪有不濕鞋”,沒有安全的駕駛意識,安全配置終究會被撞成一堆廢鐵。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

循序漸進VUE+Element 前端應用開發(7)— 介紹一些常規的JS處理函數

在我們使用VUE+Element 處理界面的時候,往往碰到需要利用JS集合處理的各種方法,如Filter、Map、reduce等方法,也可以涉及到一些對象屬性賦值等常規的處理或者遞歸的處理方法,以前對於這些不是很在意,但往往真正使用的時候,需要了解清楚,否則很容易腦袋出現短路的情況。本篇隨筆列出一些在VUE+Element 前端開發中經常碰到的JS處理場景,供參考學習。

1、常規集合的filter、map、reduce處理方法

filter函數的主要用途是對數組元素進行過濾,並返回一個符合條件的元素的數組

const nums = [10,20,30,111,222,333]
let newNums=nums.filter(function(n){
    return n<100
})

輸出:[10,20,30]

 

map函數是對數組每個元素的映射操作,並返回一個新數組,原數組不會改變將newNums中每個数字乘2

const nums = [10,20,30,111,222,333]
let newNums=nums.filter(function(n){
    return n*2
})

輸出:[20,40,60,222,666]

 

reduce函數主要用於對數組所有元素的匯總操作,如全部相加、相乘等

const nums = [10,20,30,111,222,333]
let newNums=nums.reduce(function(preValue,n){
    return PreValue+n
},0)

輸出:726

 

有時候可以結合幾種處理方式一起,如下綜合案例所示。

const nums = [10,20,30,111,222,333]
let newNums=nums.filter(function(n){
    return n<100
}).map(function(n){
    return n*2
}).reduce(function(preValue,n){
    return preValue+n
},0)

結果:120

 

另外還有一個數組集合的find方法,和filter方法類似。

find()方法主要用來返回數組中符合條件的第一個元素(沒有的話,返回undefined)

 var Array = [1,2,3,4,5,6,7];
 var result = Array.find(function(value){
     return value > 5;   //條件
 });
 console.log(result);//6
 console.log(Array);//[1,2,3,4,5,6,7]

 

同樣我們也可以在vue裏面,利用require.context的處理機制,遍歷文件進行處理,也需要用到了filter,如下代碼所示。

下面代碼是我對某個文件夾裏面的文件進行一個過濾處理操作

const req = require.context('vue-awesome/icons', true, /\.js$/)
const requireAll = requireContext => requireContext.keys()

const re = /\.\/(.*)\.js/

const vueAwesomeIcons = requireAll(req).filter((key) => { return key.indexOf('index.js') < 0 }).map(i => {
  return i.match(re)[1]
})

export default vueAwesomeIcons

 

2、遞歸處理

有時候,我們需要從一個JSON集合裏面,由於集合是嵌套的,如children裏面還有chilren集合,根據某個關鍵屬性進行查詢,這種處理方式就要用到遞歸了。

例如我定義的一個菜單集合裏面,就是這樣一個嵌套的結構,需要根據名稱來獲得對應的對象的時候,就涉及到了一個遞歸處理函數。

首先我們來看看菜單的JSON集合。

// 此菜單數據一般由服務器端返回
export const asyncMenus = [
  {
    id: '1',
    pid: '-1',
    text: '首頁',
    icon: 'dashboard',
    name: 'dashboard'
  },
  {
    id: '2',
    pid: '-1',
    text: '產品信息',
    icon: 'table',
    children: [
      {
        id: '2-1',
        pid: '2',
        text: '產品展示',
        name: 'product-show',
        icon: 'table'
      }]
  },
  {
    id: '3',
    pid: '-1',
    text: '雜項管理',
    icon: 'example',
    children: [
      {
        id: '3-1',
        pid: '3',
        text: '圖標管理',
        name: 'icon',
        icon: 'example'
      },
      {
        id: '3-3',
        pid: '3',
        text: '樹功能展示',
        name: 'tree',
        icon: 'tree'
      },
      {
        id: '3-2',
        pid: '3',
        text: '二級菜單2',
        icon: 'tree',
        children: [
          {
            id: '3-2-2',
            pid: '3-2',
            text: '三級菜單2',
            name: 'menu1-1',
            icon: 'form'
          }
        ]
      }
    ]
  }
]

如果我們需要根據ID來遍歷查詢,就是一個典型的遞歸查詢處理。

    // 根據菜單id來獲取對應菜單對象
    FindMenuById(menuList, menuid) {
      for (var i = 0; i < menuList.length; i++) {
        var item = menuList[i];
        if (item.id && item.id === menuid) {
          return item
        } else if (item.children) {
          var foundItem = this.FindMenuById(item.children, menuid)
          if (foundItem) { // 只有找到才返回
            return foundItem
          }
        }
      }
    }

這裏值得注意的是,不能在遞歸的時候,使用下面直接返回


return this.FindMenuById(item.children, menuid)

而需要判斷是否有結果在進行返回,否則嵌套遞歸就可能返回undefined類型

  var foundItem = this.FindMenuById(item.children, menuid)
  if (foundItem) { // 只有找到才返回
    return foundItem
  }

 

3、forEach遍歷集合處理

在很多場合,我們也需要對集合進行一個forEach的遍歷處理,如下根據它的鍵值進行處理,註冊全局過濾器的處理操作

// 導入全局過濾器
import * as filters from './filters'
// 註冊全局過濾器
Object.keys(filters).forEach(key => {
  Vue.filter(key, filters[key])
})

或者我們在通過API方式獲取數據后,對集合進行處理的操作

    // 獲取產品類型,用於綁定字典等用途
    GetProductType().then(data => {
      if (data) {
        this.treedata = [];// 樹列表清空
        data.forEach(item => {
          this.productTypes.set(item.id, item.name)
          this.typeList.push({ key: item.id, value: item.name })

          var node = { id: item.id, label: item.name }
          this.treedata.push(node)
        })

        // 獲取列表信息
        this.getlist()
      }
    });

又或者請求字典數據的時候,進行一個非空值的判斷處理。

      // 使用字典類型,從服務器請求數據
      GetDictData(this.typeName).then(data => {
        if (data) {
          data.forEach(item => {
            if (item && typeof (item.Value) !== 'undefined' && item.Value !== '') {
              that.dictItems.push(item)
            }
          });
        }
      })

forEach()方法也是用於對數組中的每一個元素執行一次回調函數,但它沒有返回值(或者說它的返回值為undefined,即便我們在回調函數中寫了return語句,返回值依然為undefined)

注意: 如果forEach里有兩個參數,則第一個參數為該集合里的元素,第二個參數為集合的索引;

 

4、Object.assign賦值方法

在有些場合,我們需要把全新的集合,複製到另一個對象上,替換原來對象的屬性值,那麼我們可以利用Object對象的assign方法。

如在編輯界面展示的時候,把請求到的對象屬性複製到表單對象上。

      var param = { id: id }
      GetProductDetail(param).then(data => {
        Object.assign(this.editForm, data);
      })

或者查詢的時候,獲得查詢條件,進行部分替換

      // 構造常規的分頁查詢條件
      var param = {
        type: this.producttype === 'all' ? '' : this.producttype,
        pageindex: this.pageinfo.pageindex,
        pagesize: this.pageinfo.pagesize
      };

      // 把SearchForm的條件加入到param裏面,進行提交查詢
      param.type = this.searchForm.ProductType // 轉換為對應屬性
      Object.assign(param, this.searchForm);

 

5、slice() 方法

slice() 方法可從已有的數組中返回選定的元素。

語法如下所示。

arrayObject.slice(start,end)

如下案例所示。

let red = parseInt(color.slice(0, 2), 16)
let green = parseInt(color.slice(2, 4), 16)
let blue = parseInt(color.slice(4, 6), 16)

或者我們結合filter函數對圖標集合進行獲取部分處理

vueAwesomeIconsFiltered: function() {
  const that = this
  var list = that.vueAwesomeIcons.filter(item => { return item.indexOf(that.searchForm.label) >= 0 })
  if (that.searchForm.pagesize > 0) {
    return list.slice(0, that.searchForm.pagesize)
  } else {
    return list;
  }
}

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

“造輪運動”之 ORM框架系列(三)~ 乾貨呈上

   這一趴裏面,我就來正式介紹一下CoffeeSQL的乾貨。

    首先要給CoffeeSQL來個定位:最開始就是由於本人想要了解ORM框架內部的原理,所以就四處搜尋有關的博客與學習資料,就是在那個夏天,在博客園上看到了一位7tiny老哥的博客(https://www.cnblogs.com/7tiny/p/9575230.html),裏面基本上包含了我所想要了解的全套內容。幸得7tiny老哥的博客和代碼都寫的非常清晰,所以沒花多久時間就看完了源碼並洞悉其中奧妙,於是自己就有個想法:在7tiny的開源代碼的基礎上歸納自己的ORM框架。於是出於學習與自我使用的目的就開始了擴展功能的道路,到現在為止,自己已經在公司的一個項目中用上了,效果還不錯。在這裏也感謝7tiny老哥對我提出的一些問題及時的回復和指導,真心感謝。

一、框架模塊介紹

  根據CoffeeSQL的功能模塊組成來劃分,可以分為:數據庫連接管理、SQL命令執行入口、SQL命令生成器、SQL查詢引擎、ORM緩存機制、實體數據驗證 這六個部分,CoffeeSQL的操作入口與其他的ORM框架一樣,都是以數據庫上下文(DBContext)的方式進行操作。整體結構圖如下:

 

下面就大致地介紹一下每一個模塊的具體功能與實現的思路:

1、數據庫連接管理(DBConnectionManagement)

   數據庫連接的管理實際上就是對數據庫連接字符串與其對應的數據庫連接對象的管理機制,它可以保證在進行一主多從的數據庫部署時ORM幫助我們自動地切換連接的數據庫,而且還支持 <最小使用>與 <輪詢>兩種數據庫連接切換策略。

 

2、SQL命令執行入口(QueryExecute)

   QueryExecute是CoffeeSQL生成的所有sql語句執行的入口,執行sql語句並返回結果,貫穿整個CoffeeSQL最核心的功能就是映射sql查詢結果到實體,這裏採用的是構建表達式樹的技術,性能大大優於反射獲取實體的方式,具體的兩者速度對比的實驗在7tiny的博客中有詳細介紹,大家可以移步觀看(https://www.cnblogs.com/7tiny/p/9861166.html),在我的博客(https://www.cnblogs.com/MaMaNongNong/p/12173620.html)中我使用表達式樹的技術造了個簡練版的OOM框架。

   這裏貼出核心代碼,方便查看:

   

  1     /// <summary>
  2     /// Auto Fill Adapter
  3     /// => Fill DataRow to Entity
  4     /// </summary>
  5     public class EntityFillAdapter<Entity>
  6     {
  7         private static readonly Func<DataRow, Entity> funcCache = GetFactory();
  8 
  9         public static Entity AutoFill(DataRow row)
 10         {
 11             return funcCache(row);
 12         }
 13 
 14         private static Func<DataRow, Entity> GetFactory()
 15         {
 16             #region get Info through Reflection
 17             var entityType = typeof(Entity);
 18             var rowType = typeof(DataRow);
 19             var convertType = typeof(Convert);
 20             var typeType = typeof(Type);
 21             var columnCollectionType = typeof(DataColumnCollection);
 22             var getTypeMethod = typeType.GetMethod("GetType", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string) }, null);
 23             var changeTypeMethod = convertType.GetMethod("ChangeType", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(object), typeof(Type) }, null);
 24             var containsMethod = columnCollectionType.GetMethod("Contains");
 25             var rowIndexerGetMethod = rowType.GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, new[] { new ParameterModifier(1) });
 26             var columnCollectionIndexerGetMethod = columnCollectionType.GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(int) }, new[] { new ParameterModifier(1) });
 27             var entityIndexerSetMethod = entityType.GetMethod("set_Item", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(string), typeof(object) }, null);
 28             var properties = entityType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
 29             #endregion
 30 
 31             #region some Expression class that can be repeat used
 32             //DataRow row
 33             var rowDeclare = Expression.Parameter(rowType, "row");
 34             //Student entity
 35             var entityDeclare = Expression.Parameter(entityType, "entity");
 36             //Type propertyType
 37             var propertyTypeDeclare = Expression.Parameter(typeof(Type), "propertyType");
 38             //new Student()
 39             var newEntityExpression = Expression.New(entityType);
 40             //row == null
 41             var rowEqualnullExpression = Expression.Equal(rowDeclare, Expression.Constant(null));
 42             //row.Table.Columns
 43             var rowTableColumns = Expression.Property(Expression.Property(rowDeclare, "Table"), "Columns");
 44             //int loopIndex
 45             var loopIndexDeclare = Expression.Parameter(typeof(int), "loopIndex");
 46             //row.Table.Columns[loopIndex].ColumnName
 47             var columnNameExpression = Expression.Property(Expression.Call(rowTableColumns, columnCollectionIndexerGetMethod, loopIndexDeclare), "ColumnName");
 48             //break;
 49             LabelTarget labelBreak = Expression.Label();
 50             //default(Student)
 51             var defaultEntityValue = Expression.Default(entityType);
 52             #endregion
 53 
 54             var setRowNotNullBlockExpressions = new List<Expression>();
 55                         
 56             #region entity = new Student();loopIndex = 0;
 57             setRowNotNullBlockExpressions.Add(Expression.Assign(entityDeclare, newEntityExpression));
 58             setRowNotNullBlockExpressions.Add(Expression.Assign(loopIndexDeclare, Expression.Constant(0)));
 59 
 60             #endregion
 61 
 62             #region loop Fill DataRow's field to Entity Indexer
 63             /*
 64              * while (true)
 65              * {
 66              *     if (loopIndex < row.Table.Columns.Count)
 67              *     {
 68              *         entity[row.Table.Columns[loopIndex].ColumnName] = row[row.Table.Columns[loopIndex].ColumnName];
 69              *         loopIndex++;
 70              *     }
 71              *     else break;
 72              * } 
 73              */
 74 
 75             setRowNotNullBlockExpressions.Add(
 76 
 77                 Expression.Loop(
 78                     Expression.IfThenElse(
 79                         Expression.LessThan(loopIndexDeclare, Expression.Property(rowTableColumns, "Count")),
 80                         Expression.Block(
 81                             Expression.Call(entityDeclare, entityIndexerSetMethod, columnNameExpression, Expression.Call(rowDeclare, rowIndexerGetMethod, columnNameExpression)),
 82                             Expression.PostIncrementAssign(loopIndexDeclare)
 83                         ),
 84                         Expression.Break(labelBreak)
 85                     ),
 86                     labelBreak
 87                 )
 88             );
 89             #endregion
 90 
 91             #region assign for Entity property
 92             foreach (var propertyInfo in properties)
 93             {
 94                 var columnAttr = propertyInfo.GetCustomAttribute(typeof(ColumnAttribute), true) as ColumnAttribute;
 95 
 96                 // no column , no translation
 97                 if (null == columnAttr) continue;
 98 
 99                 if (propertyInfo.CanWrite)
100                 {
101                     var columnName = Expression.Constant(columnAttr.GetName(propertyInfo.Name), typeof(string));
102 
103                     //entity.Id
104                     var propertyExpression = Expression.Property(entityDeclare, propertyInfo);
105                     //row["Id"]
106                     var value = Expression.Call(rowDeclare, rowIndexerGetMethod, columnName);
107                     //default(string)
108                     var defaultValue = Expression.Default(propertyInfo.PropertyType);
109                     //row.Table.Columns.Contains("Id")
110                     var checkIfContainsColumn = Expression.Call(rowTableColumns, containsMethod, columnName);
111                     //!row["Id"].Equals(DBNull.Value)
112                     var checkDBNull = Expression.NotEqual(value, Expression.Constant(System.DBNull.Value));
113                     
114                     var propertyTypeName = Expression.Constant(propertyInfo.PropertyType.ToString(), typeof(string));
115 
116                     /*
117                      * if (row.Table.Columns.Contains("Id") && !row["Id"].Equals(DBNull.Value))
118                      * {
119                      *     propertyType = Type.GetType("System.String");
120                      *     entity.Id = (string)Convert.ChangeType(row["Id"], propertyType);
121                      * }
122                      * else
123                      *     entity.Id = default(string);
124                      */
125                     setRowNotNullBlockExpressions.Add(
126 
127                         Expression.IfThenElse(
128                             Expression.AndAlso(checkIfContainsColumn, checkDBNull),
129                             Expression.Block(
130                                 Expression.Assign(propertyTypeDeclare, Expression.Call(getTypeMethod, propertyTypeName)),
131                                 Expression.Assign(propertyExpression, Expression.Convert(Expression.Call(changeTypeMethod, value, propertyTypeDeclare), propertyInfo.PropertyType))
132                             ),
133                             Expression.Assign(propertyExpression, defaultValue)
134                         )
135                     );
136                 }
137             }
138 
139             #endregion
140 
141             var checkIfRowIsNull = Expression.IfThenElse(
142                 rowEqualnullExpression,
143                 Expression.Assign(entityDeclare, defaultEntityValue),
144                 Expression.Block(setRowNotNullBlockExpressions)
145             );
146 
147             var body = Expression.Block(
148 
149                 new[] { entityDeclare, loopIndexDeclare, propertyTypeDeclare },
150                 checkIfRowIsNull,
151                 entityDeclare   //return Student;
152             );
153 
154             return Expression.Lambda<Func<DataRow, Entity>>(body, rowDeclare).Compile();
155         }
156     }
157 
158     #region
159     //public class Student : EntityDesign.EntityBase
160     //{
161     //    [Column]
162     //    public string Id { get; set; }
163 
164     //    [Column("StudentName")]
165     //    public string Name { get; set; }
166     //}
167     ////this is the template of "GetFactory()" created.
168     //public static Student StudentFillAdapter(DataRow row)
169     //{
170     //    Student entity;
171     //    int loopIndex;
172     //    Type propertyType;
173 
174     //    if (row == null)
175     //        entity = default(Student);
176     //    else
177     //    {
178     //        entity = new Student();
179     //        loopIndex = 0;
180 
181     //        while (true)
182     //        {
183     //            if (loopIndex < row.Table.Columns.Count)
184     //            {
185     //                entity[row.Table.Columns[loopIndex].ColumnName] = row[row.Table.Columns[loopIndex].ColumnName];
186     //                loopIndex++;
187     //            }
188     //            else break;
189     //        }
190 
191     //        if (row.Table.Columns.Contains("Id") && !row["Id"].Equals(DBNull.Value))
192     //        {
193     //            propertyType = Type.GetType("System.String");
194     //            entity.Id = (string)Convert.ChangeType(row["Id"], propertyType);
195     //        }
196     //        else
197     //            entity.Id = default(string);
198 
199     //        if (row.Table.Columns.Contains("StudentName") && !row["StudentName"].Equals(DBNull.Value))
200     //        {
201     //            propertyType = Type.GetType("System.String");
202     //            entity.Name = (string)Convert.ChangeType(row["StudentName"], propertyType);
203     //        }
204     //        else
205     //            entity.Name = default(string);
206     //    }
207 
208     //    return entity;
209     //}
210     #endregion

EntityFillAdapter(表達式樹技術)

 

3、SQL查詢引擎(QueryEngine)

  SQL查詢引擎的功能主要就是以函數的形式來構建查詢SQL的結構。將sql語句使用高級語言的函數來進行構建能大大減輕程序員必須一絲不苟編寫sql語句的壓力。特別是在使用強類型查詢引擎時以Lambda表達式的方式編寫程序,相當舒適的體驗;對於稍微複雜的sql,建議使用弱類型查詢引擎來構建sql查詢語句,同時也提供方便的分頁功能,用法與Dapper類似;再複雜一點的數據庫查詢邏輯可能你就要考慮使用存儲過程查詢引擎了,總之,有了這三個查詢引擎,所有的查詢需求都能滿足了。最後一個是update的執行引擎,它被用來構建update的語句。

 

4、實體數據驗證(EntityValidation)

  實體數據驗證是完全獨立的一部分,主要用來檢驗實體類中字段值的合法性,相當於在高級語言層面對即將持久化到數據庫表中的數據進行預先的字段合法性校驗,避免在持久化過程中發生不必要的字段格式不合法的錯誤。

 

5、ORM緩存機制(ORMCache)

  這裏的ORM緩存主要分為兩級緩存,一級緩存為以sql語句為緩存鍵的緩存,緩存的內容就是當前執行的sql語句的執行結果;而二級緩存則是以表名為緩存鍵的表緩存,就是會把一整個表的數據全部存入緩存中,所以表緩存最適合那些數據量不大且查詢頻繁的表

 

6、SQL命令生成器【強類型】(CommandTextGenerator)

  在使用諸如強類型查詢引擎、Update執行引擎等進行了強類型的SQL語句構造后,相應的sql構造信息都要通過SQL命令生成器來生成最終可由數據庫執行的sql語句。SQL命令生成器扮演的就是類似於翻譯官的角色,將高級語言中的語句轉化為數據庫中的sql語句。在實際的應用場景中還可以根據不同的數據庫類型將SQL命令生成器擴展成諸如Mysql-SQL命令生成器或者Oracle-SQL命令生成器以符合不同類型數據庫的不同sql語法。

 

7、數據庫上下文(DBContext)

  作為整個CoffeeSQL的操作入口,DBContext類涵蓋了各種配置參数字段與增刪改查的API調用函數。其中在事務處理中,由於寫操作都是通過對主庫的操作,所以在事務處理中是以主庫作為事務處理的對象。

二、使用方式

  下載CoffeeSql源碼進行編譯,你會得到 CoffeeSql.Core.dll、CoffeeSql.Oracle.dll、CoffeeSql.Mysql.dll 三個dll文件,其中CoffeeSql.Core.dll為必選,然後根據你的數據庫類型選擇是CoffeeSql.Oracle.dll或者CoffeeSql.Mysql.dll,目前還只支持這兩種數據庫,後續會支持更多數據庫。

 

 

三、展望

  路漫漫其修遠兮,吾將上下而求索,對比市面上火熱的ORM框架,CoffeeSQL還是缺少了一些實用的功能,對這個ORM框架的展望中我會考慮以下一些功能:

    1、CodeFirst、DbFirst功能的支持,可以快捷方便地進行實體類與數據庫建表sql的生成;

    2、批量插入操作的實現,可以提高批量插入數據的性能;

    3、對多表聯合查詢的lambda語法支持;

  

  介紹的再多都不如讀一遍源碼來的實在,有想深入了解orm原理的小夥伴可以閱讀一下源碼,真的SO EASY!

   源碼地址:https://gitee.com/xiaosen123/CoffeeSqlORM

   本文為作者原創,轉載請註明出處:https://www.cnblogs.com/MaMaNongNong/p/12896787.html

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計最專業,超強功能平台可客製化

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家公司費用怎麼算?