標籤: 台北網頁設計

  • 一文讀懂:防止過擬合的所有方法

    一文讀懂:防止過擬合的所有方法

    什麼是過擬合

    過擬合就是在訓練集上表現得非常好,在測試集上表現得不好。也就是我們俗稱的泛化能力弱

    過擬合無法避免,只能緩解,那麼如何緩解呢?方法太多了。這篇文章一一介紹。

    數據集增強Augmentation

    圖像上,翻轉,平移,縮放,旋轉,鏡像,增強對比度,增強亮度等諸多方式。
    我在下面的內容中介紹了圖像處理的圖像增強的方法:
    【預處理庫函數】albumentations庫的簡單了解和使用

    Early Stopping

    訓練模型的時候,訓練誤差往往是不斷下降的,但是驗證數據集的誤差,是先下降後上升。 兩個數據集的誤差出現分歧的時候,說明模型開始過擬合了。所以Early Stopping就是當驗證數據集的誤差不在下降的時候,結束訓練,保存模型參數。

    正則化regularization

    L1正則:模型中只有少部分特徵對模型的泛化能力有貢獻,所以L1就是限制模型中非零參數的數量。讓大部分的模型參數都是0,只有真正對泛化能力其作用的參數才是非零的。

    L2正則:我們希望模型找到的極小值是平坦的,為什麼呢?

    圖中表示的意思,就是平坦的極小值,可以有更多的容忍,容忍什麼呢?容忍訓練數據集和測試數據集之前的分佈偏差。現在,如果模型的某些參數特別大,那麼就算輸入的樣本只有很小的區別,但是經過特別大的參數之後,模型給出的結果很可能是非常不同的。這就是太陡峭。所以L2正則就是限制模型參數的大小。參數的平方的和作為損失的一部分,當參數數值越大,那麼梯度下降的損失越大,就會強迫參數變小。

    這裡有兩幅圖:

    這一幅圖體現的是假設只有兩個參數的情況下,增加L1正則的情況。圓圈圈體現的是損失等值線,方框是L1正則的損失。假設沒有L1正則,那麼參數應該收斂到最小的那個圓圈中的。但是因為增加了L1正則,所以需要權衡兩個部分的損失,然後找到接觸的交點位置。因為圓形和矩形在矩形的頂點相交的可能性大,而矩形的頂點就是某一個參數為0的情況。所以L1正則會讓模型參數有更大的可能性為0.
    【在更多參數的模型中,會有更多的頂點。不過二維圖像就畫不出來了】

    這個是L2正則的示意圖。L2正則式一個原型因為是參數的平方和。相比L1的(0,1)這樣的交點,L2更希望每一個參數都普遍較小,不希望某一個參數特別大。

    Dropout

    這個就是神經網絡中,在全連接網絡中經常用到的。

    在每一個Batch數據訓練的時候,Dropout層按照概率P隨機讓一些神經元失活,然後保留下來的神經元的參數被更新。dropout是只有在訓練的時候才使用的,在測試的時候並不適用。

    我個人理解的dropout其實就相當於一個多模型融合的過程。因為每一次都會失活一部分的神經元,所以每一次的模型都是不那麼一樣的,相當於不同的模型吧。

    增加噪音

    輸入中增加噪音

    輸入中有噪音\(\epsilon\),那麼輸出中就會有一個類似於\(\epsilon \omega\),這樣的損失項。 從而限制權值的大小。

    當然這樣也可以增加模型對輸入的容忍度,我覺得也可以理解為一種數據增強。 去噪自編碼器DAE就是利用這樣的方法的。

    權值中加噪音

    這個用的不多,在初始化網絡的時候,用0均值的高斯分佈作為參數的初始化。

    集成

    集成主要是bagging,boosting,之前說的dropout我覺得也可以算作集成的方法

    bagging

    將數據集抽取一部分,比如抽取70%的樣本,然後用這些樣本去訓練一個模型。然後再從數據集中抽取70%的樣本,再訓練一個新的。典型的就是隨機森林。
    【神經網絡因為訓練速度的問題,所以一般不用這樣的方法。決策樹lgb啥的可以用】

    boosting

    訓練複雜神經網絡比較慢,所以可以通過訓練多個簡單的分類器,然後加權平均每一個分類器的輸出。這就是Boost的思想。【這句話給我背下來!】

    之後整理一下Adaboost和XGBoost的這些算法。

    其他

    • 限制網絡的層數和複雜度

    **END**

    喜歡的話請關注我們的微信公眾號~《你好世界煉丹師》或者知乎【你好世界煉丹師】。

    • 公眾號主要講統計學,數據科學,機器學習,深度學習,以及一些參加Kaggle競賽的經驗。
    • 公眾號內容建議作為課後的一些相關知識的補充,飯後甜點。
    • 此外,為了不過多打擾,公眾號每周推送一次,每次4~6篇精選文章。

    微信搜索公眾號:你好世界煉丹師。期待您的關注。

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

    【其他文章推薦】

    USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

    台北網頁設計公司這麼多該如何選擇?

    ※智慧手機時代的來臨,RWD網頁設計為架站首選

    ※評比南投搬家公司費用收費行情懶人包大公開

    ※回頭車貨運收費標準

  • 區塊鏈系列教程之:比特幣的錢包與交易

    區塊鏈系列教程之:比特幣的錢包與交易

    目錄

    • 簡介
    • 比特幣密碼學的基礎
      • 單向散列函數(hash算法)
      • 非對稱加密算法
      • 擴展閱讀:同態加密
    • 密鑰,地址和錢包
    • 比特幣中的交易
    • 擴展閱讀:圖靈非完備性
    • 總結

    簡介

    錢包在比特幣中是做什麼的呢?比特幣的交易又有什麼特點呢?怎麼才能偽造比特幣的交易呢?今天和大家一起學習一下比特幣中的錢包和交易。

    比特幣密碼學的基礎

    之前我們提到過比特幣使用的並不是什麼新技術,只是對於老的技術比如:P2P網絡,分佈式系統,密碼學,共識算法的重新而又巧妙的應用。

    在錢包和交易生成驗證的過程中,都需要使用到密碼學的計算。這裏我們先介紹一下比特幣中會使用到的幾種密碼學技術。

    更多精彩內容且看:

    • 區塊鏈從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特幣等持續更新
    • Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
    • Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
    • java程序員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程

    單向散列函數(hash算法)

    在介紹單向散列函數之前,我們先了解一下什麼情況下需要使用到單向散列函數。

    如果你需要從國外的網站上下載一個軟件,但是因為種種原因,國外的網絡太慢了,下載幾個G的數據幾乎是不可能的。剛好國內有鏡像網站,可以從國內下載數據。但是如何保證國內的鏡像不是被篡改過後的呢?這個時候就需要單向散列函數了。一般來說網站會提供MD5或者SHA的值作為驗證值。

    單向散列函數有一個輸入和輸出。輸入稱為消息,輸出稱為散列值。

    散列值的長度跟消息的長度無關,不論多少大小的長度的消息,都會計算出固定長度的散列值。

    hash算法有下面幾個特點:

    1. 能夠根據任意長度的消息計算出固定長度的散列值。

    2. 計算速度要快。

    3. 消息不同,散列值也不同。

      這就意味着,如果僅僅是一點點的變動都會引起整個散列值的巨大變化。

      因為散列值的大小是固定的,所以有可能會出現不同的消息產生相同散列值的情況。這種情況叫做碰撞。

      難以發現碰撞的性質被稱為抗碰撞性。當給定某條消息的散列值時,必須保證很難找到和該消息具有相同散列值的另一條消息。

    4. 單向散列函數必須具有單向性。所謂單向性是指無法通過散列值來反推出消息的性質。

    比特幣使用的散列算法是SHA256,他是安全散列算法SHA(Secure Hash Algorithm)系列算法的一種(另外還有SHA-1、SHA-224、SHA-384 和 SHA-512 等變體),SHA是美國國家安全局 (NSA) 設計,美國國家標準與技術研究院(NIST) 發布的,主要適用於数字簽名標準(DigitalSignature Standard DSS)裏面定義的数字簽名算法(Digital Signature Algorithm DSA)。

    RIPEMD(RACE Integrity Primitives Evaluation Message Digest,RACE原始完整性校驗消息摘要),是Hans Dobbertin等3人在md4,md5的基礎上,於1996年提出來的。

    非對稱加密算法

    非對稱加密算法也叫公鑰密碼算法,通過生成的公私鑰來對明文密文進行加密解密。

    非對稱加密算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;如果用私有密鑰對數據進行加密,那麼只有用對應的公開密鑰才能解密。因為加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。

    擴展閱讀:同態加密

    同態加密是一種加密形式,它允許人們對密文進行特定的代數運算得到仍然是加密的結果,將其解密所得到的結果與對明文進行同樣的運算結果一樣。換言之,這項技術令人們可以在加密的數據中進行諸如檢索、比較等操作,得出正確的結果,而在整個處理過程中無需對數據進行解密。其意義在於,真正從根本上解決將數據及其操作委託給第三方時的保密問題,例如對於各種雲計算的應用。

    密鑰,地址和錢包

    比特幣的所有權是通過数字密鑰、比特幣地址和数字簽名來確立的。数字密鑰實際上並不是存儲在網絡中,而是由用戶生成並存儲在一個文件或簡單的數據庫 中,稱為錢包。存儲在用戶錢包中的数字密鑰完全獨立於比特幣協議,可由用戶的錢包軟件生成並管理,而無需區塊鏈或網絡連接。密鑰實現了比特幣的許多有趣特性,包括去中心化信任和控制、所有權認證和基於密碼學證明的安全模型。

    比特幣錢包只包含私鑰而不是比特幣。每一個用戶有一個包含多個私鑰的錢包。錢包中包含成對的私鑰和公鑰。用戶用這些私鑰來簽名交易,從而證明它們擁有交易的輸出(也就是其中的比特幣)。比特幣是以交易輸出的形式來儲存在區塊鏈中(通常記為vout或txout)。

    如果錢包只包含私鑰,那麼錢包地址是什麼呢?錢包地址是從公鑰的hash值的出來的,如下圖所示:

    1. 首先使用隨機數發生器生成一個『私鑰』。一般來說這是一個256bits的數,擁有了這串数字就可以對相應『錢包地址』中的比特幣進行操作,所以必須被安全地保存起來。

    2. 『私鑰』經過SECP256K1算法處理生成了『公鑰』。SECP256K1是一種橢圓曲線算法,通過一個已知『私鑰』時可以算得『公鑰』,而『公鑰』已知時卻無法反向計算出『私鑰』。這是保障比特幣安全的算法基礎。

    3. 同SHA256一樣,RIPEMD160也是一種Hash算法,由『公鑰』可以計算得到『公鑰哈希』,而反過來是行不通的。

    4. 將一個字節的地址版本號連接到『公鑰哈希』頭部(對於比特幣網絡的pubkey地址,這一字節為“0”),然後對其進行兩次SHA256運算,將結果的前4字節作為『公鑰哈希』的校驗值,連接在其尾部。

    5. 將上一步結果使用BASE58進行編碼(比特幣定製版本),就得到了『錢包地址』。 比如,1A1zP1eP5QGefi2DMPTfTL5TTmv7DivfNa。

    所以私鑰,公鑰和錢包地址的關係如下圖所示:

    大家看到錢包地址1A1zP1eP5QGefi2DMPTfTL5TTmv7DivfNa有什麼想法呢?

    肯定有人在想,這麼一大長串字母和数字實在是太不好記憶了。能不能生產一個比較好記的錢包地址呢? 比如MyNameIsHanMeiMei….這樣開頭的地址呢?

    當然可以,這叫做靚號地址,只不過需要大量的算力才行。

    比特幣中的交易

    簡單來說,交易就是告知全網:比特幣的持有者已授權把比特幣轉帳給其他人。而新持有者能夠再次授權,轉移給該比特幣所有權鏈中的其他人。

    注意, 在比特幣的世界里既沒有賬戶,也沒有餘額,只有分散到區塊鏈里的UTXO(Unspent Transaction Outputs)。

    怎麼理解這個UTXO呢?沒有賬戶也沒有餘額,那麼錢包裏面的金額是怎麼計算出來的呢?

    別急,讓我們一一道來。

    話說,在比特幣中,比特幣錢包間的轉賬是通過交易(Transaction)實現的。

    我們看一個標準的交易流程。

    那麼問題來了,世界上第一個比特幣是哪裡來的呢?

    答,是挖礦來的。好了,我們的001交易表示的就是一個挖礦的過程,在這個交易中,輸入就是挖礦,輸出編號1,BTC數目是50,目的地址是A,表示這50個BTC給A了。

    接下來,A想發25個BTC給B,怎麼構造這個交易呢?

    同樣的,我們需要一個輸入,這個輸入就是001交易的1號輸出,我們用001.1來表示。輸出分為兩個,第一個輸出編號1,表示要付25個BTC給B。第二個輸出編號2,表示剩下的BTC要還給A。

    大家可能會問了,輸入是50BTC,兩個輸出加起來才45個BTC,好像還少了5個BTC?沒錯,這個5個BTC就是給礦工的挖礦所得。

    接下來,A又繼續轉賬給C,同樣的道理,把一個一個的交易連接起來。

    從上面的例子我們可以看到,實際上錢是存在一個一個的交易記錄裏面的,那些未被花費的輸出,就叫做UTXO(Unspent Transaction Outputs)。

    那麼怎麼保證轉賬給B的錢,不會被其他的人消費呢?這就涉及到交易的加密過程了。

    我們以單個輸入和輸出為例來詳細了解一下交易的構成:

    上圖中,交易的輸入就是txid,也就是之前生成的還有未花費暑輸出的交易ID。output index就是交易的輸出id。

    一個非常重要的ScriptSig是輸入交易的驗證,表明這個用戶擁有這個賬戶的轉賬權限。

    輸出是一個腳本,只有滿足腳本運行條件的人才能花費這個output。這也就是ScriptSig需要驗證的腳本。

    我們看下腳本是怎麼做認證的吧。

    比特幣的標準輸出形式有兩種。Pay To Public Key Hash (P2PKH) 和 Pay To Script Hash (P2SH)。兩者的區別在於,一個是輸出到public key的hash,一個是輸出到任意的一個腳本輸出hash。

    為了保證輸出只能由特定的人來花費,一般的情況下是直接輸出到對方的public key hash。由於只有對方擁有的私鑰能夠生成這個public key hash,也就是說只有對方才能夠對這個輸出進行驗證。

    但每次都需要知道對方的public key hash還是比較麻煩的,更簡單的做法就是,發送者直接輸出到一個特定的hash值就行了,只要對方能夠生成這個hash就可以。

    下面的例子是一個P2PKH的腳本形式。

    P2PKH的輸出是一個腳本,裏面一個重要的值就是PK hash。

    怎麼驗證呢?

    驗證方提供兩個值,一個是sig,一個是PubKey。因為比特幣的虛擬機是棧結構的,我們先把這兩個值入棧。

    然後調用OP_DUP對最上層的PubKey進行拷貝,然後調用OP_HASH160算法來計算Pk Hash,然後將發送方保存的Pk Hash入棧。接下來調用OP_EQUALVERIFY對兩個PK Hash進行對比。

    如果對比成功,最後一步就是驗證Sig和PubKey是否匹配。

    如果都成功,說明接收方的確是這個PK Hash的擁有者。那麼對方就可以盡情使用了。

    擴展閱讀:圖靈非完備性

    和馮·諾伊曼同為現代計算機奠基人的阿蘭·圖靈(AlanTurin)在1950年提出了判定計算機能否像人那般實際“思考”的標準,也就是著名的“圖靈檢驗”。

    他設想一台超級計算機和一個人躲藏在幕後回答提問者的問題,而提問者則試圖分辨哪個是人哪個是計算機。

    圖靈爭辯說,假如計算機偽裝得如此巧妙,以致沒有人可以在實際上把它和一個真人分辨開來的話,那麼我們就可以聲稱,這台計算機和人一樣具備了思考能力,或者說,意識(他的原詞是“智慧”)。

    在可計算性理論里,如果一系列操作數據的規則(如指令集、編程語言、細胞自動機)按照一定的順序可以計算出結果,被稱為圖靈完備(turing complete)。

    比特幣腳本語言不是圖靈完備的,具有一定的局限性,它沒有循環語句和複雜的條件控制語句。

    總結

    本文介紹了比特幣的錢包和交易的概念,希望大家能夠喜歡。

    本文作者:flydean程序那些事

    本文鏈接:http://www.flydean.com/bitcoin-transactions/

    本文來源:flydean的博客

    歡迎關注我的公眾號:程序那些事,更多精彩等着您!

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

    【其他文章推薦】

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

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

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

    ※超省錢租車方案

  • Spring中基於xml的AOP

    Spring中基於xml的AOP

    1、Aop 全程是Aspect Oriented Programming 即面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的同一維護的一種技術。Aop是oop的延續,是軟件開發中的 一個熱點,也是Spring框架中一個重要的內容。是函數式編程的一個衍生範例,利用Aop可以對業務邏輯各個部分進行分割,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用行,提高了開發效率。簡單的說就是把我們程序中的重複代碼抽取出來,在需要執行的時候,使用動態代理的技術,在不修改源碼的基礎上已有的方法進行增強,(使用動態代理的方式實現)

    相關術語

    JoinPoint:鏈接點 那些被攔截到的點,在spring中,這些點指的是方法,因為spring只支持方法類型的連接點

    Pointcut:切入點   是指我們要對哪些JoinPont進行攔截的定義

    Advice:通知/增強  攔截到Joinpoint之後所要做的事情就是通知

    通知類型:前置通知、後置通知、異常通知、最終通知、環繞通知

    Introduction:引介   是一種特殊的通知,在不修改類代碼的前提下,Introduction可以在運行期為類動態的添加一些方法或field

    Target:目標對象,代理的目標對象

    Weaving 織入   是指把增強應用到目標對象來創建新的代理對象的過程,spring採用動態代理織入,而AspectJ採用編譯期織入和類裝載期織入

    Proxy:代理,一類類被Aop織入增強后,就產生一個結果代理類

    Aspect:切面   是切入點和通知(引介)的結合

    在 spring 中,框架會根據目標類是否實現了接口來決定採用哪種動態代理的方式。

    基於XMl的AOP步驟

    1、創建Maven項目引入spring坐標

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.mingqi</groupId>
        <artifactId>SpringIOC</artifactId>
        <packaging>pom</packaging>
        <version>1.0-SNAPSHOT</version>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.0.2.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.7</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>

    2、創建業務層接口:

    package com.mingqi.services;
    public interface IAccountService {
        /**
         * 模擬登陸賬戶
         */
        void saveAccount();
    
        /**
         * 模擬更新賬戶
         * @param id
         */
        void updateAccount(int id);
    
        /**
         * 模擬刪除賬戶
         * @return
         */
        int deleteAccount();
    
    }

    3.創建業務層實現類

    package com.mingqi.services.impl;
    import com.mingqi.services.IAccountService;
    public class AccountServicesImpl implements IAccountService {
        public void saveAccount() {
            System.out.println("執行了保存");
        }
    
        public void updateAccount(int id) {
            System.out.println("執行了更新"+id);
        }
    
        public int deleteAccount() {
            System.out.println("執行了刪除");
            return 0;
        }
    }

    4、創建工具類

    package com.mingqi.utils;
    import org.aspectj.lang.ProceedingJoinPoint;
    /**
     * 用戶記錄日誌的工具類,裏面提供公共的代碼
     */
    public class Logger {
        /**
         * 用於打印日誌:計劃讓其在切入點方法執行前執行(切入點方法就是業務層方法)
         */
        public  void beforePrintLog(){
            System.out.println("Logger類中的pringLog方法開始記錄日誌了。。。");
        }
        public  void afterReturningPrintLog()
        {
            System.out.println("後置通知Logger類中的beforePrintLog方法開始記錄日誌了。。。");
        }
        /**
         * 異常通知
         */
        public void afterThrowingPrintLog()
        {
            System.out.println("異常通知Logger類中的afterThrowingPrintLog方法開始記錄日誌了。。。");
    
        }
        /**
         * 最終通知
         */
        public void afterPrintLog()
        {
            System.out.println("最終通知Logger類中的afterPrintLog方法開始記錄日誌了。。。");
        }
    
        /**
         * 環繞通知
         * 問題  當我們配置了環繞通知以後,切入點方法沒有執行,而通知方法執行了
         * 分析: 通過對比動態代理中的環繞通知代碼,發現動態代理中的環繞通知有明確的切入點方法調用,而我們的代碼中沒有
         * 解決: Spring 框架為我們提供了一個接口:ProceedingJoinPoint。該接口有一個方法proceed(),此方法就相當於明確調用切入點的方法
         *        該接口可以作為環繞通知的參數方法,在程序執行時,spring框架會為我們提供該接口的實現類供我們使用
         * spring中的環繞通知
         *      他是spring框架為我們提供的一種可以在代碼中手動控制增強方法何時會執行的方式
         * @param pjp
         * @return
         */
        public Object aroundPringLog(ProceedingJoinPoint pjp){
            Object rtValue = null;
            try{
                Object[] args = pjp.getArgs();//得到方法執行所需的參數
    
                System.out.println("Logger類中的aroundPringLog方法開始記錄日誌了。。。前置");
    
                rtValue = pjp.proceed(args);//明確調用業務層方法(切入點方法)
    
                System.out.println("Logger類中的aroundPringLog方法開始記錄日誌了。。。後置");
    
                return rtValue;
            }catch (Throwable t){
                System.out.println("Logger類中的aroundPringLog方法開始記錄日誌了。。。異常");
                throw new RuntimeException(t);
            }finally {
                System.out.println("Logger類中的aroundPringLog方法開始記錄日誌了。。。最終");
            }
        }
    }

    4、創建bean配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd">
           <!-- 配置spring的IOC,把service對象配置進來-->
           <bean id="accountSevice" class="com.mingqi.services.impl.AccountServicesImpl"></bean>
           <!-- spring 中基於xml的Aop配置步驟
             1、把通知Bean也交給spring來管理
             2、使用aop:config標籤表名開始aop的配置
             3、使用aop:aspect標籤表明配置切面
                 id屬性:是給切面提供一個唯一標識
                 ref屬性:是指定通知類的id
             4、在aop:aspect標籤的內部使用對應的標籤來配置通知的類型
                 我們現在的示例是讓printlog方法在切入點方法執行之前執行,所以是前置通知
                 aop:before:標識前置通知
                    method屬性: 用於指定Logger類中的方法哪個是前置通知
                    pointcut屬性: 用於指定切入點表達式,該表達式的含義指的是對業務層中的哪些方法增強
                    切入點表達式的寫法:
                       關鍵字:execution(表達式)
                       表達式:  訪問修飾符 返回值 包名.包名.包名....類名.方法名(參數列表)
                       標準的寫法: public void com.mingqi.service.impl.AccountServiceImpl.saveAccount()
                       訪問修飾符可以省略:void com.mingqi.service.impl.AccountServiceImpl.saveAccount()
                       返回值可以使用通配符,標識任意返回值:* com.mingqi.service.impl.AccountServiceImpl.saveAccount()
                       包名可以使用通配符,表示任意包,但是有幾級包就需要寫幾個*  *.*.*.*.*.AccountServiceImpl.saveAccount()
                       包名可以使用..代表當前包及其子包:* *.AccountServiceImpl.saveAccount()
                       類名和方法名都可以使用*來實現統配 * *..*.*();
                       參數列表: 可以直接寫數據類型:
                                     基本類型直接寫名稱:int
                                     引用類型寫包名.類名的方式: java.lang.String
                                    可以使用通配符來標識任意類型,單必須有參數
                                    可以使用..標識有無參數均可,有參數可以是任意類型
    
                          全通配寫法:
                        * *..*.*(..)
                       實際開發中 切入點表達式的通常寫法:
                              切到業務層實現類的所有方法,* com.mingqi.service.impl.*.*(..);
             -->
           <!-- 配置Logger類-->
           <bean id="logger" class="com.mingqi.utils.Logger"></bean>
           <!--使用aop:config標籤表名開始aop的配置-->
           <aop:config>
                  <aop:pointcut id="pt1" expression="execution(* com.mingqi.services.impl.*.*(..))"></aop:pointcut>
                  <!--使用aop:aspect標籤表明配置切面-->
                  <aop:aspect id="LogAdvice" ref="logger">
                         <!-- 配置前置通知:在切入點方法執行之前執行
                         <aop:before method="beforePrintLog" pointcut-ref="pt1"></aop:before>-->
    
                         <!-- 配置後置通知:在切入點方法正常執行之後值。它和異常通知永遠只能執行一個
                              <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>-->
                         <!-- 配置異常通知:在切入點方法執行產生異常之後執行。它和後置通知永遠只能執行一個
                             <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>-->
                         <!-- 配置最終通知:無論切入點方法是否正常執行它都會在其後面執行
                            <aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>-->
                         <!-- 配置環繞通知 詳細的註釋請看Logger類中-->
                            <aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around>
                        </aop:aspect>
                 </aop:config>
           </beans>

    6、創建測試類

    package com.mingqi.test;
    import com.mingqi.services.IAccountService;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    public class SpringIoc {
        @Test
        public void TestAccount()
        {
            ApplicationContext ac= new ClassPathXmlApplicationContext("beam.xml");
            IAccountService accountService=(IAccountService) ac.getBean("accountSevice");
            accountService.saveAccount();
            accountService.updateAccount(22);
            accountService.deleteAccount();
        }
    }

     

     

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

    【其他文章推薦】

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

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

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

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

  • 深入了解C#(TPL)之Parallel.ForEach異步

    深入了解C#(TPL)之Parallel.ForEach異步

    前言

    最近在做項目過程中使用到了如題并行方法,當時還是有點猶豫不決,因為平常使用不多, 於是藉助周末時間稍微深入了下,發現我用錯了,故此做一詳細記錄,希望對也不是很了解的童鞋在看到此文後不要再犯和我同樣的錯誤。

    并行遍歷異步表象

    這裏我們就不再講解該語法的作用以及和正常遍歷處理的區別,網上文章比比皆是,我們直接進入主題,本文所演示程序在控制台中進行。可能大部分童鞋都是如下大概這樣用的

    Parallel.ForEach(Enumerable.Range(0, 10), index =>
    {
        Console.WriteLine(index);
    });

     

    我們採取并行方式遍歷10個元素,然後結果也隨機打印出10個元素,一點毛病也沒有。然而我是用的異步方式,如下:

    Parallel.ForEach(Enumerable.Range(0, 10), async index =>
    {
        await AsyncTask(index);
    });
    static async Task<int> AsyncTask(int i)
    {
        await Task.Delay(100);
        
        var calculate = i * 2;
        
        Console.WriteLine(calculate);
    
        return calculate;
    }

    我們只是將并行操作更改為了異步形式,然後對每個元素進行對應處理,打印無序結果,一切也是如我們所期望,接下來我再來看一個例子,經過并行異步處理后猜猜最終字典中元素個數可能或一定為多少呢?

    var dicts = new ConcurrentDictionary<string, int>();
    
    Parallel.ForEach(Enumerable.Range(0, 10), async index =>
    {
        var result = await AsyncTask(index);
    
        dicts.TryAdd(index.ToString(), result);
    });
    
    Console.WriteLine($"element count in dictionary {dicts.Count}");

     

    如果對該并行方法沒有深入了解的話,大概率都會猜錯,我們看到字典中元素為0,主要原因是用了異步后引起的,為何會這樣呢?我們首先從表象上來分析,當我們在控制台上對并行方法用了異步后,你會發現編譯器會告警(主函數入口已用異步標識),如下:

    接下來我們再來看看調用該并行異步方法的最終調用構造,如下:

    public static ParallelLoopResult ForEach<TSource>(IEnumerable<TSource> source, Action<TSource> body);

    第二個參數為內置委託Action,所以我們也可以看出並不能用於異步,因為要是異步至少也是Func<Task>,比如如下方法參數形式

    static async Task AsyncDemo(Func<int,Task> func)
    {
        await func(1);
    }

    并行遍歷異步本質

    通過如上表象的分析我們得出并行遍歷方法應該是並不支持異步(通過最終結果分析得知,表述為不能用於異步更恰當),但是在實際項目開發中我們若沒有注意到該方法的構造很容易就會誤以為支持異步,如我一樣寫完也沒報錯,也就草草了事。那麼接下來我們反編譯看下最終實際情況會是怎樣的呢。

    進入主函數,我們已將主函數進行異步標識,所以將主函數放在狀態機中執行(狀態機類,<Main>d_0),這點我們毫無保留的贊同,接下來實例化字典,並通過并行遍歷異步處理元素集合併將其結果嘗試放入到字典中

    由上我們可以看到主函數是在狀態機中運行且構造為AsyncTaskMethodBuilder,當我們通過并行遍歷異步處理時每次都會實例化一個狀態機類即如上<<Main>b__0>d,但我們發現此狀態機的構造是AsyncVoidMethodBuilder,利用此狀態機類來異步處理每一個元素,如下

    最終調用AsyncTask異步方法,這裏我就不再截圖,同樣也是生成一個此異步方法的狀態機類。稍加分析想必我們已經知曉結果,AsyncTaskMethodBuilder指的就是(async task),而AsyncVoidMethodBuilder指的是(async void),所以對并行遍歷異步操作是將其隱式轉換為async void,而不是async task,這也和我們從其構造為Action得出的結論一致,我們知道(async void)僅限於基於事件的處理程序(常見於客戶端應用程序),其他情況避免用async void,也就是說將返回值放在Task或Task<T>中。當并行執行任務時,由於返回值為void,不會等待操作完成,這也就不難解釋為何字典中元素個數為0。

    總結

    當時並沒有過多的去了解,只是想當然的認為用了異步也沒出現編譯報錯,但是又由於沒怎麼用過,我還是抱着懷疑的態度,於是再深究了下,發現用法是大錯特錯。通過構造僅接受為Action委託,這也就意味着根本無法等待異步操作完成,之所以能接受異步索引其本質是隱式轉換為(async void),從另外一個角度看,異步主要用於IO密集型,而并行處理用於CPU密集型計算,基於此上種種一定不能用於異步,否則結果你懂的。

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

    【其他文章推薦】

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

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

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

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

  • 【服務器】VMware Workstation Pro虛擬機搭建本地服務器CentOs7和寶塔面板(保姆式教程)

    【服務器】VMware Workstation Pro虛擬機搭建本地服務器CentOs7和寶塔面板(保姆式教程)

    內容繁多,請耐心跟着流程走,在過程中遇到問題請在下面留言(我只是小白,請專業人士噴輕點)。

    前言

    這幾天一直在複習thinkphp5.1,學習環境是phpStudy8.1,但是遇到了文件有緩存的問題(thinkphp5.1.39,修改文件后刷新沒有效果那種,需要隔幾分鐘才正常),百度也沒有解決方法,搞了幾天,一直沒解決,就氣着去折騰本地虛擬機服務器,使用阿里雲的CentOs7鏡像(本站的服務器也是阿里雲的CentOs7,運維環境也是寶塔哦),運維環境是寶塔面板

    說到寶塔就有一些故事了,買服務器的時候是想用windows server2008的,配置了IIS一段時間,搞不定,然後往nginx方向走,又搞不定,後來用windows寶塔面板,還是搞不定,不管怎麼折騰都沒辦法搞定,網站一直打不開,然後就轉CentOs7了,安裝寶塔,配置域名,訪問域名,網站就可以显示了,回想當初,不知道自己腦子抽了哪條經。

    工具

    • VMware Workstation Pro 15.5.5(虛擬機,自己去下載安裝哦,安裝步驟:下一步,我同意,修改安裝路徑,下一步,完成)

    • CentOs7(iso鏡像,推薦使用IDM或者迅雷下載,鏡像大小4.6GB上下)
      阿里雲鏡像:http://mirrors.aliyun.com/centos/7.8.2003/isos/x86_64/

    • Xshell(用於連接虛擬機,方便使用Linux命令,是一個遠程工具,右鍵就可以複製粘貼哦,還可以拉滾動條。)

    查看並保持vmnet8 ip

    本地vmnet8 ip

    查看本地的vmnet8 ip(安裝好虛擬機后才會自動生成的),打開cmd輸入ipconfig
    按win鍵+R,輸入cmd,回車就能打開cmd

    或者按win鍵+S,搜索“cmd”,也能打開“命令提示符”

    還有左下角的“田”形右鍵,然後選擇“Windows Powershell”;
    還有Git的Git Bash等等。。。。。。。。。。。。。。。。

    輸入ipconfig后,就显示下面界面

    這裏主要的內容是以太網適配器VIware Network Adapter VInet8,把細框里的IPv4地址子網掩碼默認網關(我這裏沒有,我也不知道為什麼)用文本記下來,或者不關這個窗口,後面要用到的。

    虛擬機vmnet8 ip

    虛擬機裏面的虛擬網絡需要設置一下虛擬機裏面的虛擬網絡需要處理一下虛擬機裏面的虛擬網絡需要編輯一下

    下圖標記2的地方,勾勾要去掉,去掉之後點擊NAT設置,查看虛擬機的vmnet8 ip,把紅框里的子網IP子網掩碼默認網關用文本記下來,然後點擊確定。

    現在整理一下要用文本記下來的東西

    創建虛擬機

    點擊創建新的虛擬機

    點擊自定義,下一步。

    選擇虛擬機版本,我這裡是15.5.5,下一步

    點擊稍後安裝操作系統,下一步。

    選擇Linux操作系統,現在安裝的是entOs7,所以版本選擇CentOs7 64位,下一步。

    虛擬機名稱隨意,可以中文,這裏我寫的是服務器ip名(可以重命名的),為了方便定位,不用我說都懂的啦,從左邊欄就可以看出100、101、102沒有102,哎?我跳過102了?我是把流程走一遍再碼字的,碼字的時候,服務器已經ok了,不過問題不大,下一步。。。。

    默認(本站的核心是2個,但是我100、101都是1個核心,這裏默認1個核心夠用了),本地服務器,也就自己一個人訪問,而且這裏配置是跟本機電腦配置有關的,服務器一核心足矣(只要電腦帶得動,給八核我也沒意見),下一步。

    默認(本站的內存是1GB,但是我100、101都是2GB,這裏默認1GB夠用了),同上(如果在阿里雲買服務器,我建議是1核心2GB內存哦),下一步。

    點擊使用網絡地址轉換(NAT),下一步。

    默認,下一步。

    默認,下一步。

    默認,下一步。

    默認(磁盤大小自己改,20GB實際上夠了,下面選項默認),下一步。

    默認,下一步。

    點擊自定義硬件

    點擊打印機,然後點擊移除

    跟着数字的步驟走(步驟3:選擇下載好的CentOs7鏡像,我個人是推薦放在服務器根目錄下,看我圖中的路徑,這裏不明白要留言哦)。

    點擊完成

    安裝CentOs7系統

    點擊開啟此虛擬機

    這裏說一下,默認選中的是Test this this media & install CentOS 7(白色字體是選中狀態),按方向鍵↑然後回車(如果按鍵沒效果,需要把鼠標點一下虛擬機显示屏)。

    中文在最下面,滾下去或者拉到下面才看到(下面的搜索chinese),點擊繼續

    這裏看一下自己的日期和時間是不是亞洲/上海 時區,不是的話自己進去調一下(百度)。

    點擊軟件選擇

    把紅框里的兩個勾勾點上,完成。

    點擊安裝位置

    點擊我要配置分區,完成。

    點擊點這裏自動創建他們,完成。

    默認,/boot(啟動文件),swap(交換分區,類似windows虛擬內存。看內存總大小,如果內存足夠大,這個空間就要設置很大,如果內存小於2G,那麼這個空間設置成內存的2倍大小。),/(根分區),完成。

    點擊接受更改

    點擊網絡和主機名

    打開以太網,修改主機名(也闊以使用默認的啦),然後點擊應用(點完應用后看看以太網是不是關閉了,如果關閉了再點開),完成。

    點擊開始安裝

    點擊ROOT密碼

    設置密碼,我這裏設置123456(本機的,起個好記的就好),完成(點兩次)。

    等待安裝(根據自己的需求去創建用戶吧,但是創建后可能某些操作需要root權限,不折騰就不要創了,昨晚搞CentOs8服務器差點崩潰,CentOs8是規定要創建用戶的,CentOs7和CentOs8就跟windows7和windows10一樣)。

    安裝完畢,點擊重啟。

    選擇第一個。

    我的用戶名是root,密碼123456
    輸入用戶名root,回車。

    輸入密碼123456(不可見的,輸入就行了),回車。

    噔噔噔噔,革命成功

    配置服務器靜態ip(需要配置服務器動態ip的自己百度一下)

    到了這一步,你已經回不了頭了,還學會一丟丟Linux命令,建議多去看看Linux命令

    打開目錄:cd /etc/sysconfig/network-scripts/(複製粘貼就好,這個複製粘貼有點麻煩,找不到的就手敲,正是這樣才要用Xshell工具來遠程,得先配置ip,忍一忍吧),回車。

    我這裏显示的是ifcfg-ens33,這裏要說一下,我百度過,有些是32,也有1667777,先用cd /etc/sysconfig/network-scripts/進入目錄,然後ll显示列表(ls也可以显示列表,只显示列表名)。

    編輯ifcfg-ens33:vi ifcfg-ens33(vi:進入編輯模式,文件名別敲錯。),回車。

    i 字母鍵進入編輯模式(如果不显示下圖的,肯定是vi ifcfg-ens33輸入錯了,自己檢查一下,退出vi方法:按Esc(注意左下角),輸入:q!(不保存退出))。

    看圖IPADDR=192.168.157.103NETMASK=255.255.255.0GATEWAY=192.168.157.2,這裏不建議複製粘貼了,好好敲,我擔心會亂(如果一定要複製粘貼的話,先把裏面的複製出來,加上IPADDR、NETMASK、GATEWAY再粘貼回去,不知道能不能明白我的意思,咱們還是敲吧!!!)。

    保存並退出:按Esc鍵,然後輸入:wq(必須小寫),回車。

    重啟網絡:systemctl restart network,回車。
    查看ip:ip addr, 回車。
    出現下圖就可以了,萬歲。

    配置本地的網絡(只需要配置一次)

    這是本地訪問虛擬機要配置的,文本中記下來的本機ip用這裏(因為我這沒有默認網關,所以不填)。

    使用Xshell連接虛擬機服務器(右鍵就可以複製粘貼哦)

    新建會話,這裏隧道要取消轉發X11連接到:(可能會有人奇怪,為什麼這張步驟和下面步驟在正常思路來說調換了,我其實是忘了,後面才補回來的)。

    新建會話,輸入名稱192.168.157.103(輸入名稱后,下面的主機也是同步的。),然後點擊連接。

    出現這個彈窗就說明99.99%成功了,如果沒有就說明配置出錯,大概率在上一個步驟[配置本地的網絡(點擊跳轉)][60]

    輸入用戶名root

    輸入用戶名123456

    okay。

    安裝寶塔面板

    寶塔官網:https://www.bt.cn/
    寶塔Linux面板命令大全:https://www.bt.cn/btcode.html(一定要多看)

    這裏標註幾個常用的命令(本文章用到的):cd(不用說了吧)、clear(清屏,也可以用Ctrl+L)、ll(當前列表,詳細的展示列表),ls(當前列表,簡潔的展示列表)、vi 文件名(編輯文件,按Esc::wq保存並退出、:q(退出)、:q!強制不保存並退出)。

    安裝

    安裝腳本:yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh
    PS:此腳本從官方複製過來的時間為2020年6月19日,僅限CentOs系統,如果距離已久,請到官網複製

    右鍵隨意複製粘貼,Xshell工具的好處(佛主:https://www.kancloud.cn/jiangguowu/kfjsdkfjskd/1076752)。

    DO you want to install Bt Panel tothe /www directory now?(y/n):(現在是否要將Bt面板安裝到/www目錄?(是/否):)。
    按y,回車。

    寶塔面板訪問地址:http://192.168.157.103:8888/7a81976f119.137.3.117換成192.168.157.103自己設置的服務器ip(別傻了,只有本地才能訪問)。

    username: yq0g4uxd
    password: c937d4a9

    是闊一。

    點擊一鍵安裝(也可以不選擇,然後自己去左邊的軟件商店自己選擇安裝)。

    建議設置一下安全入口面板用戶面板密碼(只能設置8位數,為了方便,我強行使用命令行將密碼設置為123456,命令:cd /www/server/panel && python tools.py panel 123456,更多的寶塔命令請到寶塔Linux面板命令大全查看:https://www.bt.cn/btcode.html)

    報錯、錯誤、問題大雜燴(此目錄處理教程中遇到的問題,請在下面留言)

    安裝寶塔 -> 14: curl#6 – “Could not resolve host: mirrorlist.centos.org; 未知的錯誤

    打開:vi /etc/resolv.conf
    加入:nameserver 8.8.8.8nameserver 8.8.4.4

    完美結束!!!

    圖片太多,碼字的時候都卡了,大概68張圖片,感覺還是錄製視頻好啊

    如果有錯誤的地方,歡迎糾正。

    我已經想好下一篇的文章了,出一個寶塔面板使用教程。

    原文鏈接:https://blog.langting.top/archives/117.html

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

    【其他文章推薦】

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

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

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

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

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

  • 09.DRF-ModelSerializer

    四、模型類序列化器ModelSerializer

    如果我們想要使用序列化器對應的是Django的模型類,DRF為我們提供了ModelSerializer模型類序列化器來幫助我們快速創建一個Serializer類。

    ModelSerializer與常規的Serializer相同,但提供了:

    • 基於模型類自動生成一系列字段
    • 基於模型類自動為Serializer生成validators,比如unique_together
    • 包含默認的create()和update()的實現

    4.1 定義

    比如我們創建一個BookInfoSerializer

    class BookInfoSerializer(serializers.ModelSerializer):
        """圖書數據序列化器"""
        class Meta:
            model = BookInfo
            fields = '__all__'
    
    • model 指明參照哪個模型類
    • fields 指明為模型類的哪些字段生成

    我們可以在python manage.py shell中查看自動生成的BookInfoSerializer的具體實現

    >>> from booktest.serializers import BookInfoSerializer
    >>> serializer = BookInfoSerializer()
    >>> serializer
    BookInfoSerializer():
        id = IntegerField(label='ID', read_only=True)
        btitle = CharField(label='名稱', max_length=20)
        bpub_date = DateField(allow_null=True, label='發布日期', required=False)
        bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=-2147483648, required=False)
        bcomment = IntegerField(label='評論量', max_value=2147483647, min_value=-2147483648, required=False)
        image = ImageField(allow_null=True, label='圖片', max_length=100, required=False)
    

    4.2 指定字段

    4.2.1) 使用fields來明確字段,__all__表名包含所有字段,也可以寫明具體哪些字段,如

    class BookInfoSerializer(serializers.ModelSerializer):
        """圖書數據序列化器"""
        class Meta:
            model = BookInfo
            fields = ('id', 'btitle', 'bpub_date')
    

    4.2.2) 使用exclude可以明確排除掉哪些字段

    class BookInfoSerializer(serializers.ModelSerializer):
        """圖書數據序列化器"""
        class Meta:
            model = BookInfo
            exclude = ('image',)
    

    4.2.3) 默認ModelSerializer使用主鍵作為關聯字段,但是我們可以使用depth來簡單的生成嵌套表示,depth應該是整數,表明嵌套的層級數量。如:

    class HeroInfoSerializer2(serializers.ModelSerializer):
        class Meta:
            model = HeroInfo
            fields = '__all__'
            depth = 1
    

    形成的序列化器如下:

    HeroInfoSerializer():
        id = IntegerField(label='ID', read_only=True)
        hname = CharField(label='名稱', max_length=20)
        hgender = ChoiceField(choices=((0, 'male'), (1, 'female')), label='性別', required=False, validators=[<django.core.valators.MinValueValidator object>, <django.core.validators.MaxValueValidator object>])
        hcomment = CharField(allow_null=True, label='描述信息', max_length=200, required=False)
        hbook = NestedSerializer(read_only=True):
            id = IntegerField(label='ID', read_only=True)
            btitle = CharField(label='名稱', max_length=20)
            bpub_date = DateField(allow_null=True, label='發布日期', required=False)
            bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=-2147483648, required=False)
            bcomment = IntegerField(label='評論量', max_value=2147483647, min_value=-2147483648, required=False)
            image = ImageField(allow_null=True, label='圖片', max_length=100, required=False)
    

    4.2.4) 显示指明字段,如:

    class HeroInfoSerializer(serializers.ModelSerializer):
        hbook = BookInfoSerializer()
    
        class Meta:
            model = HeroInfo
            fields = ('id', 'hname', 'hgender', 'hcomment', 'hbook')
    

    4.2.5) 指明只讀字段

    可以通過read_only_fields指明只讀字段,即僅用於序列化輸出的字段

    class BookInfoSerializer(serializers.ModelSerializer):
        """圖書數據序列化器"""
        class Meta:
            model = BookInfo
            fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
            read_only_fields = ('id', 'bread', 'bcomment')
    

    4.3 添加額外參數

    我們可以使用extra_kwargs參數為ModelSerializer添加或修改原有的選項參數

    class BookInfoSerializer(serializers.ModelSerializer):
        """圖書數據序列化器"""
        class Meta:
            model = BookInfo
            fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
            extra_kwargs = {
                'bread': {'min_value': 0, 'required': True},
                'bcomment': {'min_value': 0, 'required': True},
            }
    
    # BookInfoSerializer():
    #    id = IntegerField(label='ID', read_only=True)
    #    btitle = CharField(label='名稱', max_length=20)
    #    bpub_date = DateField(allow_null=True, label='發布日期', required=False)
    #    bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=0, required=True)
    #    bcomment = IntegerField(label='評論量', max_value=2147483647, min_value=0, required=True)
    

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

    【其他文章推薦】

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

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

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

    ※超省錢租車方案

    FB行銷專家,教你從零開始的技巧

  • 一起玩轉微服務(6)——通信協議如何統一

    一起玩轉微服務(6)——通信協議如何統一

    一、接口調用

    接口調用如果是遠程調用,那麼就構成了簡單的分佈式。最簡單的遠程接口實現方式是web service或rest。當然一個合理的分佈式應用不僅僅是遠程接口調用這麼簡單。還需要有負載均衡、緩存等功能。最簡單實現分佈式的技術是Rest接口,因為Rest接口可以使用現存的各種服務器,比如負載均衡服務器和緩存服務器來實現負載均衡和緩存功能。

    二、統一通信協議

    關於通信協議,不同的公司有不同的選擇,但是建議同一公司內部使用統一的通信協議,比較典型的有grpc和brpc。

    1. gRPC簡介

    gRPC是Google發布的基於HTTP 2.0傳輸層協議承載的高性能開源軟件框架,提供了支持多種編程語言的、對網絡設備進行配置和納管的方法。由於是開源框架,通信的雙方可以進行二次開發,所以客戶端和服務器端之間的通信會更加專註於業務層面的內容,減少了對由gRPC框架實現的底層通信的關注。如下圖,DATA部分即業務層面內容,下面所有的信息都由gRPC進行封裝。

     

     

    grpc是一個高性能、開源和通用的 RPC 框架,面向移動和 HTTP/2 設計。目前提供 C、Java 和 Go 語言版本,分別是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持.
    grpc基於 HTTP/2 標準設計,帶來諸如雙向流、流控、頭部壓縮、單 TCP 連接上的多復用請求等特。這些特性使得其在移動設備上表現更好,更省電和節省空間佔用。
    關於具體gRPC報文的結構,可以參考下圖:

     

     

    下面展示一下gRPC的交互過程

     

     

    1. 交換機在開啟gRPC功能后充當gRPC客戶端的角色,採集服務器充當gRPC服務器角色;
    2. 交換機會根據訂閱的事件構建對應數據的格式(GPB/JSON),通過Protocol Buffers進行編寫proto文件,交換機與服務器建立gRPC通道,通過gRPC協議向服務器發送請求消息;
    3. 服務器收到請求消息后,服務器會通過Protocol Buffers解譯proto文件,還原出最先定義好格式的數據結構,進行業務處理;
    4. 數據梳理完后,服務器需要使用Protocol Buffers重編譯應答數據,通過gRPC協議向交換機發送應答消息;
    5. 交換機收到應答消息后,結束本次的gRPC交互。

    上圖展示的是gRPC交互過程的具體流程,這也是Telemetry觸發方式其中之一,稱為Dial-out模式。簡單地說,gRPC就是在客戶端和服務器端開啟gRPC功能后建立連接,將設備上配置的訂閱數據推送給服務器端。

    2. brpc

    與grpc類似,brpc源自百度,目前支撐百度內部大約 75 萬個同時在線的實例。
    其實基於以上的幾種選擇都能夠完成高效的開發,團隊內部使用統一的標準,這樣更有利於模塊化和統一標準。
    服務間的通信是通過輕量級的web服務,使用同步的REST API進行通信。在實際的項目應用中,一般推薦在查詢的時候使用同步機制,在增刪改使用異步的方式,結合消息隊列來實現數據的操作,以保證最終的數據一致性。
    具體可以使用BRPC做如下

    1. 搭建能在一個端口支持多協議的服務, 或訪問各種服務
    2. Server能同步或異步處理請求
    3. Client支持同步、異步、半同步,或使用組合channels簡化複雜的分庫或併發訪問
    4. 通過http界面調試服務, 使用cpu, heap, contention profilers
    5. 獲得更好的延時和吞吐
    6. 把你組織中使用的協議快速地加入brpc,或定製各類組件, 包括命名服務 (dns, zk, etcd), 負載均衡 (rr, random, consistent hashing)

    三、rest API

     

     

    REST API 應為創建、檢索、更新和刪除操作使用標準 HTTP 動詞,而且應特別注意操作是否冪等。
    POST 操作可用於創建資源。POST 操作的明顯特徵是它不是冪等的。舉例而言,如果使用 POST 請求創建資源,而且啟動該請求多次,那麼每次調用后都會創建一個新的唯一資源。
    GET 操作必須是冪等的且不會產生意外結果。具體來講,帶有查詢參數的 GET 請求不應用於更改或更新信息(而應使用 POST、PUT 或 PATCH)。
    PUT 操作可用於更新資源。PUT 操作通常包含要更新的資源的完整副本,使該操作具有冪等性。
    PATCH 操作允許對資源執行部分更新。它們不一定是冪等的,具體取決於如何指定增量並應用到資源上。例如,如果一個 PATCH 操作表明一個值應從 A 改為 B,那麼它就是冪等的。如果它已啟動多次而且值已是 B,則沒有任何效果。對 PATCH 操作的支持仍不一致。例如,Java EE7 中的 JAX-RS 中沒有 @PATCH 註釋。
    DELETE 操作用於刪除資源。刪除操作是冪等的,因為資源只能刪除一次。但是,返回代碼不同,因為第一次操作將成功 (200),而後續調用不會找到資源 (204)。

     

    四、你們怎麼解決

    不同項目組之間使用的語言有可能不同,框架有可能不同,同樣的,通信協議有可能不同,你們怎麼解決的呢?

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

    【其他文章推薦】

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

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

    ※超省錢租車方案

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

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

  • 一文梳理JavaScript中的this

    一文梳理JavaScript中的this

    最近零零碎碎看了許多關於this的文章,本着“好記性不如爛筆頭”的思想,特在這裏整理一下this有關的知識點。【長文警告!!!】

    接下來,筆者將按照以下目錄對this進行闡述:

    • this是什麼?
    • this指向
      • this在全局範圍內
      • this在對象的構造函數內
      • this在對象的方法內
      • this在簡單函數內
      • this在箭頭函數內
      • this在一個事件偵聽器內
    • this綁定規則
      • 默認綁定
      • 隱式綁定
      • 显示綁定(this修改)
      • 優先級
    • 箭頭函數

    1. this是什麼?

    this是JavaScript的一個關鍵字,但它時常矇著面紗讓人無法捉摸,許多對this不明就裡的同學,常常會有這樣的錯誤認知:

    • this在函數內指向函數自身

      •   function foo(num){
              console.log("foo: " + num);
          
              //記錄foo被調用次數
              this.count++;
          }
          foo.count = 0;
          for(let i=0; i<10; i++){
              if(i > 5){
                  foo(i);
              }
          }
          console.log(foo.count); // 0, this並沒有指向foo函數,foo.count沒有進行任何操作
        
    • this在函數內指向函數的作用域

      •   function foo(){
              var a = 2;
              this.bar();
          }
          function bar(){
              console.log(this.a);
          }
          foo();// undefined, window對象沒有bar這一屬性
        

    2. this指向

    this的指向取決於他所處的環境. 大致上,可以分為下面的6種情況:

    • this在全局範圍內
    • this在對象的構造函數內
    • this在對象的方法內
    • this在一個簡單的函數內
    • this在箭頭函數內
    • this在一個事件偵聽器內

    2.1 this在全局範圍內

    this在全局範圍內綁定什麼呢?這個相信只要學過JS,應該都知道答案。如果不知道,同學真的應該反思自己的學習態度和方法是否存在問題了。話不多說,直接上代碼,一探究竟,揭開this在全局範圍下的真面目:

    console.log(this); // Window
    

    不出意外,this在全局範圍內指向window對象()。通常, 在全局環境中, 我們很少使用this關鍵字, 因此對它也沒那麼在意. 讓我們繼續看下一個環境.

    2.2 this在對象的構造函數內

    當我們使用new創建構造函數的實例時會發生什麼呢?以這種方式調用構造函數會經歷以下四個步驟:

    • 創建一個空對象;

    • 將構造函數的作用域賦給新對象(this指向了這個新對象),繼承函數的原型;

    • 執行構造函數中的代碼;

    • 返回新對象。

    看完上面的內容,大家想必也知道this在對象的構造函數內的指向了吧!當你使用new關鍵字創建一個對象的新的實例時, this關鍵字指向這個實例 .

    舉個栗子:

    function Human (age) {
        this.age = age;
    }
    let greg = new Human(22);
    let thomas = new Human(24);
    
    console.log(greg); // this.age = 22
    console.log(thomas); // this.age = 24
    
    // answer
    Person { age:22}
    Person { age:24}
    

    2.3 this在對象方法內

    方法是與對象關聯的函數的通俗叫法, 如下所示:

    let o = {
        sayThis(){
            console.log(this);
        }
    }
    

    如上所示,在對象的任何方法內的this都是指向對象本身 .

    好了,繼續下一個環境!

    2.4 this在簡單函數內

    可能看到這裏,許多同學心裏會有疑問,什麼是簡單函數?

    其實簡單函數大家都很熟悉,就像下面一樣,以相同形式編寫的匿名函數也被認為是簡單函數(非箭頭函數)。

    function hello(){
        console.log("hello"+this);
    }
    

    這裏需要注意,在瀏覽器中,不管函數聲明在哪裡,匿名或者不匿名,只要不是直接作為對象的方法,this指向始終是window對象(除非使用call,apply,bind修改this指向)。

    舉個栗子說明一下:

    // 显示函數,直接定義在sayThis方法內,this指向依舊不變
    function simpleFunction() {
        console.log(this);
    }
    
    var o = {
        sayThis() {
            simpleFunction();
        }
    }
    
    simpleFunction(); // Window
    o.sayThis(); // Window
    
    
    // 匿名函數
    var o = {
        sayThis(){
            (function(){consoloe.log(this);})();
        }
    } 
    o.sayThis();// Window
    

    對於初學者來說,this在簡單函數內的表現時常讓他們懵逼不已,難道this不應該指向對象本身?這個問題曾經也出現在我的腦海里過,沒錯,在寫代碼時我也踩過這個坑。

    通常的,當我們要在對象方法內調用函數,而這個函數需要用到this時,我們都會創建一個變量來保存對象中的this的引用. 通常, 這個變量名稱叫做self或者that。具體說下所示:

    const o = {
        doSomethingLater() {
            const self = this;
            setTimeout(function() {
                self.speakLeet();
            }, 1000);
        },
        speakLeet() {
            console.log(`1337 15 4W350M3`);
        }
    }
    
    o.doSomethingLater(); // `1337 15 4W350M3`
    

    心細的同學可能已經發現,這裏的簡單函數沒有將箭頭函數包括在內,那麼下一個環境是什麼想必也能猜到啦,那麼現在進入下一個環境,看看this指向什麼。

    2.5 this在箭頭函數內

    和簡單函數表現不太一樣,this在箭頭函數中總是跟它在箭頭函數所在作用域的this一樣(在它直接作用域). 所以, 如果你在對象中使用箭頭函數, 箭頭函數中的this總是指向這個對象本身, 而不是指向Window.

    下面我們使用箭頭函數,重寫一下上面的案例:

    const o = {
        doSomethingLater() {
            setTimeout(() => this.speakLeet(), 1000);
        },
        speakLeet() {
            console.log(`1337 15 4W350M3`);
        }
    }
    o.doSomethingLater(); // `1337 15 4W350M3`
    

    最後,讓我們來看看最後一種環境 – 事件偵聽器.

    2.6 this在事件偵聽器內

    在事件偵聽器內, this被綁定的是觸發這個事件的元素:

    let button = document.querySelector('button');
    
    button.addEventListener('click', function() {
        console.log(this); // button
    });
    

    3. this綁定規則

    事實上,只要記住上面this在不同環境的綁定值,足以應付大部分工作。然而,好學的同學總是會忍不住想說,為什麼呢?對,為什麼this在這些情況下綁定這些值呢?學習,我們不能只知其然,而不知所以然。所以,現在就讓我們來探尋,this值獲取的真相吧。

    現在,讓我們回憶一下,在講什麼是this的時候,我們說到“this的綁定取決於他所處的環境”。這句話其實不是十分準確,準確的說,this不是編寫時綁定,而是運行時綁定。它依賴於函數調用的上下文條件this綁定和函數聲明的位置無關,反而和函數被調用的方式有關

    當一個函數被調用時,會建立一個活動記錄,也稱為執行環境。這個記錄包含函數是從何處(call-stack)被調用的,函數是 如何被調用的,被傳遞了什麼參數等信息。這個記錄的屬性之一,就是在函數執行期間將被使用的this引用。this實際上是在函數被調用時建立的一個綁定,它指向什麼是完全由函數被調用的調用點來決定的

    僅僅是規則

    現在我們將注意力轉移到調用點 如何 決定在函數執行期間this指向哪裡。

    你必須考察call-site並判定4種規則中的哪一個適用。我們將首先獨立的解釋一下這4種規則中的每一種,之後我們來展示一下如果有多種規則可以適用調用點時,它們的優先級。

    3.1 默認綁定規則

    第一種規則來源於函數調用的最常見的情況:獨立函數調用。可以認為這種this規則是在沒有其他規則適用時的默認規則。我們給它一個稱呼“默認綁定”.

    現在來看這段代碼:

    function foo(){
        console.log(this); 
    }
    var a = 2;
    demo(); // 2
    

    當foo()被調用時,this.a解析為我們的全局變量a。為什麼?因為在這種情況下,對此方法調用的this實施了 默認綁定,所以使this指向了全局對象。

    在我們的代碼段中,foo()是被一個直白的,毫無修飾的函數引用調用的。沒有其他的我們將要展示的規則適用於這裏,所以 默認綁定 在這裏適用。

    如果strict mode在這裏生效,那麼對於 默認綁定 來說全局對象是不合法的,所以this將被設置為undefined。

    'use strict'
    function foo(){
        console.log(this.a); // TypeError: Cannot read property 'a' of undefined
    }
    const a = 1;
    foo();
    
    function foo(){
    	'use strict'
        console.log(this.a); // TypeError: Cannot read property 'a' of undefined
    }
    const a = 1;
    foo();
    

    微妙的是,即便所有的this綁定規則都是完全基於調用點,如果foo()的 內容 沒有在strint mode下執行,對於 默認綁定 來說全局對象是 唯一 合法的;foo()的call-site的strict mode狀態與此無關。

    function foo(){
        console.log(this.a); 
    }
    var a = 1;
    (function(){
    	'use strict';
    	foo(); // 1
    })();
    

    注意: 在代碼中故意混用strict mode和非strict mode通常是讓人皺眉頭的。你的程序整體可能應當不是 Strict 就是非Strict。然而,有時你可能會引用與你的 Strict 模式不同的第三方包,所以對這些微妙的兼容性細節要多加小心。

    3.2 隱式綁定

    另一種要考慮的規則是:調用點是否有一個環境對象(context object),也稱為擁有者(owning)或容器(containing)對象。

    讓我們來看這段代碼:

    function foo() {
        console.log(this.a);
    }
    let o = {
        a: 2,
        foo,
    }
    o.foo(); // 2
    

    這裏,我們注意到foo函數被聲明然後作為對象o的方法,無論foo()是否一開始就在obj上被聲明,還是後來作為引用添加(如上面代碼所示),都是這個 函數 被obj所“擁有”或“包含”。這裏,調用點使用obj環境來引用函數,所以可以說 obj對象在函數被調用的時間點上“擁有”或“包含”這個 函數引用。

    當一個方法引用存在一個環境對象時,隱式綁定 規則會說:是這個對象應當被用於這個函數調用的this綁定。

    只有對象屬性引用鏈的最後一層是影響調用點的。比如:

    function foo(){
        console.log(this.a);
    }
    
    var obj1 = {
        a:2,
        obj2:obj2
    };
    var obj2 = {
        a:42,
        foo:foo
    };
    obj1.obj2.foo(); // 42
    

    隱式綁定的隱患

    當一個 隱含綁定丟失了它的綁定,這通常意味着它會退回到 默認綁定, 根據strict mode的狀態,結果不是全局對象就是undefined。

    下面來看這段代碼:

    function foo(){
        console.log(this.a);
    }
    
    var obj = {
        a:2,
        foo
    };
    var bar = obj.foo;
    var a = "Global variable";
    bar(); // "Global variable"
    

    儘管bar似乎是obj.foo的引用,但實際上它只是另一個foo自己的引用而已。另外,起作用的調用點是bar(),一個直白,毫無修飾的調用,因此 默認綁定 適用於這裏。

    這種情況發生的更加微妙,更常見,更意外的方式,是當我們考慮傳遞一個回調函數時:

    function foo(){
        console.log(this.a);
    }
    
    function doFoo(fn){
    	fn();
    }
    
    var obj = {
        a:2,
        foo,
    };
    var a = "Global variable";
    dooFoo(obj.foo); // "Global variable"
    

    參數傳遞僅僅是一種隱含的賦值,而且因為我們在傳遞一個函數,它是一個隱含的引用賦值,所以最終結果和我們前一個代碼段一樣。同樣的,語言內建,如setTimeout也一樣,如下所示

    function foo(){
        console.log(this.a);
    }
    
    var obj = {
        a:2,
        foo,
    };
    var a = "Global variable";
    setTimeout(obj.foo, 100); // "Global variable"
    

    把這個粗糙的setTimeout()假想實現當做JavaScript環境內建的實現的話:

    function setTimeout(fn, delay){
        // 等待delay毫秒
        fn();
    }
    

    正如我們看到的, 隱含綁定丟失了它的綁定是十分常見的,不管哪一種意外改變this的方式,你都不能真正地控制你的回調函數引用將如何被執行,所以你(還)沒有辦法控制調用點給你一個故意的綁定。但是我們可以使用显示綁定強行固定this。

    3.3 显示綁定

    我們看到隱含綁定,需要我們不得不改變目標對象使它自身包含一個對函數的引用,而後使用這個函數引用屬性來間接地(隱含地)將this綁定到這個對象上。

    但是,如果你想強制一個函數調用使用某個特定對象作為this綁定,而不在這個對象上放置一個函數引用屬性呢?

    js有提供call()、apply()方法,ES5中也提供了內置的方法 Function.prototype.bind,可以引用一個對象時進行強制綁定調用。

    考慮這段代碼:

    function foo(){
        console.log(this.a);
    }
    var obj = {
        a:2,
    };
    foo.call(obj); // 2
    

    通過foo.call(..)使用 明確綁定 來調用foo,允許我們強制函數的this指向obj。

    如果你傳遞一個簡單原始類型值(string,boolean,或 number類型)作為this綁定,那麼這個原始類型值會被包裝在它的對象類型中(分別是new String(..),new Boolean(..),或new Number(..))。這通常稱為“boxing(封箱)”。

    注意: 就this綁定的角度講,call(..)和apply(..)是完全一樣的。它們確實在處理其他參數上的方式不同,但那不是我們當前關心的。

    單獨依靠call和apply,仍然可能出現函數“丟失”自己原本的this綁定,或者被第三方覆蓋等問題。

    但有一個技巧可以避免出現這些問題

    考慮這段代碼:

    function foo(){
        console.log(this.a);
    }
    var obj = {
    	a:2
    };
    var bar = function(){
    	foo.call(obj);
    }
    bar(); // 2
    setTimeout(bar, 100); // 2
    bar.call(window); // 2
    

    我們創建了一個函數bar(),在它的內部手動調用foo.call(obj),由此強制this綁定到obj並調用foo。無論你過後怎樣調用函數bar,它總是手動使用obj調用foo。這種綁定即明確又堅定,該方法被開發者稱為 硬綁定(显示綁定的變種)(hard binding)

    用硬綁定將一個函數包裝起來的最典型的方法,是為所有傳入的參數和傳出的返回值創建一個通道:

    function foo(something){
        console.log(this.a, something);
        return this.a + something;
    }
    var obj = {
        a:2
    };
    var bar = function() {
        return foo.apply(obj, arguments);
    }
    var b = bar(3);
    console.log(b); //  5
    

    另一種表達這種模式的方法是創建一個可復用的幫助函數:

    function foo(something){
        console.log(this.a, something);
        return this.a + something;
    }
    
    function bind(fn, obj){
        return function(){
            return fn.apply(obj, arguments);
        };
    }
    
    var obj = { a:2};
    var bar = bind(foo, obj);
    var b = bar(3);
    console.log(b); // 5
    

    由於 硬綁定 是一個如此常用的模式,它已作為ES5的內建工具提供,即前文提到的Function.prototype.bind:

    function foo(something){
        console.log(this.a, something);
        return this.a + something;
    }
    var obj = { a:2};
    var bar = foo.bind(obj);
    var b = bar();
    cobsole.log(b); // 5
    
    

    bind(..)返回一個硬編碼的新函數,它使用你指定的this環境來調用原本的函數。

    注意: 在ES6中,bind(..)生成的硬綁定函數有一個名為.name的屬性,它源自於原始的 目標函數(target function)。舉例來說:bar = foo.bind(..)應該會有一個bar.name屬性,它的值為”bound foo”,這個值應當會显示在調用棧軌跡的函數調用名稱中。

    3.4new 綁定

    第四種也是最後一種this綁定規則

    當在函數前面被加入new調用時,也就是構造器調用時,下面這些事情會自動完成:

    • 一個全新的對象會憑空創建(就是被構建)
    • 這個新構建的對象會被接入原形鏈([[Prototype]]-linked)
    • 這個新構建的對象被設置為函數調用的this綁定
    • 除非函數返回一個它自己的其他 對象,這個被new調用的函數將 自動 返回這個新構建的對象。

    考慮這段代碼:

    function foo(a){
        console.log(this.a);
    }
    var bar = new foo(2);
    console.log(bar.a); // 2
    

    通過在前面使用new來調用foo(..),我們構建了一個新的對象並這個新對象作為foo(..)調用的this。 new是函數調用可以綁定this的最後一種方式,我們稱之為 new綁定(new binding)。

    3.5 優先級

    • new綁定
    • 显示綁定
    • 隱式綁定
    • 默認綁定(嚴格模式下會綁定到undefined)

    4. 箭頭函數

    箭頭函數並非使用function關鍵字進行定義,而是通過所謂的“大箭頭”操作符:=>,所以不會使用上面所講解的this四種標準規範,箭頭函數從封閉它的(function或global)作用域採用this綁定,即箭頭函數會繼承自外層函數調用的this綁定。

    執行 fruit.call(apple)時,箭頭函數this已被綁定,無法再次被修改。

    function fruit(){
        return () => {
            console.log(this.name);
        }
    }
    var apple = {
        name: '蘋果'
    }
    var banana = {
        name: '香蕉'
    }
    var fruitCall = fruit.call(apple);
    fruitCall.call(banana); // 蘋果
    

    5. 小結

    this是JavaScript的一個關鍵字,this不是編寫時綁定,而是運行時綁定。它依賴於函數調用的上下文條件。this綁定和函數聲明的位置無關,反而和函數被調用的方式有關。為執行中的函數判定this綁定需要找到這個函數的直接調用點。找到之後,4種規則將會以 這個 優先順序施用於調用點:

    • 被new調用?使用新構建的對象。
    • 被call或apply(或 bind)調用?使用指定的對象。
    • 被持有調用的環境對象調用?使用那個環境對象。
    • 默認:strict mode下是undefined,否則就是全局對

    與這4種綁定規則不同,ES6的箭頭方法使用詞法作用域來決定this綁定,這意味着它們採用封閉他們的函數調用作為this綁定(無論它是什麼)。它們實質上是ES6之前的self = this代碼的語法替代品。

    參考文章:

    深入理解JavScript中的this

    詳解JavaScript中的this

    你不懂this:豁然開朗

    你不懂this:this是什麼?

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

    【其他文章推薦】

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

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

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

    ※超省錢租車方案

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

  • 北加州野火再起安全性斷電 2000多人撤離

    摘錄自2019年10月24日中央社報導

    北加州酒鄉有超過一萬公頃的土地遭到森林野火侵襲,2000多人被迫離家,目前沒有人員傷亡,以公共安全為理由的民生斷電又展開。美國媒體ABC News在推特放上現場畫面。

    這場名為金凱德(Kincade)的火災,起火地點距離太平洋瓦斯電力公司(Pacific Gas and Electric Company,PG&E)切斷電源的索諾馬郡(Sonoma County)不遠,索諾馬是與納帕山谷(Napa Valley)齊名的北加州葡萄酒鄉。

    今年季節性的高熱乾風再度來襲,PG&E近日兩度以公共安全為考量,在非常短的時間、突襲式通知警戒區域的民眾斷電消息,引發擾民爭議,也被批評沒有及早檢查、更新輸電線等相關設備。

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

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

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

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

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

  • 迎接Model 3試產,Tesla發股債籌資11.5億美元

    迎接Model 3試產,Tesla發股債籌資11.5億美元

    美國電動車大廠特斯拉(Tesla)15 日公布最新增資計畫,由於即將進入Model 3 電動車的試產階段,預計將透過發行股票和優先債券融資11.5 億美元(約355 億台幣)。

    華爾街日報(Wall Street Journal)報導,特斯拉預計將發行2.5 億美元普通股及7.5 億美元可轉換優先債券來籌措資金,執行長馬斯克(Elon Musk)本人也將認購2,500 美元的普通股,所得資金將用來強化資產負債表,並降低近期業務擴張可能帶來的風險。

    特斯拉表示,2016 年共生產了8.4 萬輛汽車,未來也將持續投資、創造產品並提升產能,希望至2018 年底總產量能達到50 萬輛,2020 年則達到100 萬輛。在公布計畫後,特斯拉盤後股價上漲2.3% 至261.5 美元。

    報導指出,不僅是汽車,馬斯克也計畫將電動車運用在更多車款上,如公共汽車及載貨卡車;隨著去年收購SolarCity Corp,馬斯克希望未來將特斯拉打造成一家永續能源公司,提供包含電動車、電池及太陽能發電在內相關產品。

    AutoCar 網站則提到,除了今年將試產的Model 3 電動車,特斯拉也已經在著手進行另一部迷你SUV 車款Model Y 的開發,相對於特斯拉其他車款來說,Model Y 和Model 3 一樣將會相對平價,市場估計Model 3 售價約為3.7 萬美元(約113 萬台幣),考量到迷你SUV 的機能與客群的不同,Model Y 的售價可能將再比Model 3 車款高上數千美元。

     

    ▲由 Autocar 製作的 Model Y 概念圖

    (合作媒體:。首圖來源:Tesla)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

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

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

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

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