javascript中級

張東html

zhangdong@tedu.cnc++

1. ***數組:程序員

   什麼是:正則表達式

   爲何:算法

   什麼時候:小程序

   如何: 建立,訪問元素,遍歷數組

 

1. ***數組:瀏覽器

   什麼是: 內存中連續存儲多個數據的一塊存儲空間數據結構

      vs 變量:  內存中存儲一個數據的存儲空間閉包

   爲何: ***程序=數據結構+算法

                算法: 解決問題的步驟

                數據結構: 數據在內存中的存儲結構

                    好的數據結構能夠極大提升程序的執行效率

   什麼時候: 從此,只要連續存儲多個相關的數據,都要用數組

   如何: 建立,訪問元素

      建立: 3個場景:

         1. 建立空數組: var 變量=[];

                                             =new Array();

             什麼時候: 在建立數組時,暫時不知道數組中的元素內容

         2. 建立數組時,初始化數組內容:

                                var 變量=[值1,值2,...];

                                             =new Array(值1,值2,...);

             什麼時候: 在建立數組時,已經知道元素的內容

             強調: 每一個元素之間,必須用逗號分隔

         3. 建立n個空元素的數組: var 變量=new Array(n);

             什麼時候: 在建立數組時,僅知道元素的個數,暫時不知道元素的內容。

 

    訪問數組中的元素:

       下標: 數組中惟一標識每一個元素存儲位置的序號

              默認從0開始,連續不重複

       arr[i]: 訪問arr數組中下標爲i位置的元素值

          數組中每一個元素的用法和普通變量徹底同樣。

          其實,數組也是一組變量的集合,再起一個統一的變量名

 

    三個不限制:

       1. 不限制元素的數據類型

       2. 不限制元素的個數

       3. 不限制下標越界:

              賦值: 若是下標越界,不報錯!而是在指定位置自動添加新元素。——稀疏數組: 下標不連續的數組

              取值: 若是下標越界,不報錯!而是返回undefined

 

    length屬性: 記錄理論上數組的元素個數

                 length永遠是最大下標+1

       固定套路:

          1. 最後一個元素: arr[arr.length-1]

          2. 倒數第n個元素: arr[arr.length-n]

          3. 在末尾追加新元素: arr[arr.length]=值

          4. 清空數組: arr.length=0;

          5. 刪除末尾最後一個元素: arr.length--;

          6. 刪除末尾的n個元素: arr.length-=n;

 

    遍歷: 依次訪問數組中每一個元素:

       for(var i=0;i<arr.length;i++){

           arr[i]//當前元素

       }

       什麼時候: 從此只要對數組中每一個元素執行相同的操做時

 

***數組是引用類型的對象:

    數據類型: 基礎類型: 值直接存儲在變量本地的數據類型

                    引用類型: 值沒法保存在變量本地的數據類型

                        數據實際存儲在變量外的一個獨立存儲空間

                            同時存儲多個數據的一塊存儲空間-對象

                            每一個對象都有惟一的內存地址

                        變量中僅保存對象的地址值!

                        訪問變量等效於經過地址值找到具體對象去訪問

    數組就是引用類型的對象

 

***按值傳遞:

    兩變量間賦值,或將變量做爲參數傳入函數時,其實僅將原變量中值,複製一個副本給對方變量:

       對基礎類型: 修改新變量的值,不影響原變量;

       對引用類型: 僅複製對象的地址給對方,不建立新對象

                          經過新變量修改對象,等效於修改原對象

 

null vs undefined

  undefined: 空, 專門用於程序自動給變量初始化空值

  null: 空, 專門用於程序員主動釋放對一個對象的引用

     垃圾回收: 內存中引擎會自動釋放再也不被任何變量引用的對象

     垃圾回收器: 在內存中自動執行的小程序

                        自動釋放不被任何變量引用的對象

     好的習慣: 只要一個對象再也不使用,都要主動將變量置爲null

 

 

 

 

正課:

1. ***數組:

   API:

     拼接和選取

     修改

     翻轉

****排序: 自定義排序算法: 冒泡排序

              sort()

 

1. 拼接和選取:

   拼接: 將其它元素或其它數組拼接到當前數組末尾,返回新數組

      var newArr=arr1.concat(值1,值2,arr2,......)

      強調: 1. 無權修改原對象,只能返回新對象

               2. 打散傳入的數組參數——珍貴

   選取: 複製原數組中指定位置的元素組成新數組

      var subArr=arr1.slice(starti,endi+1);

      強調: 1. 無權修改原對象,只能返回新對象

               2. 規律: 全部兩個參數都是下標的API,都含頭不含尾

      簡寫: 1. 省略第二個參數: arr1.slice(starti)

                      從starti位置一直選取到結尾

               2. 不寫參數: arr1.slice()——複製整個數組中全部元素

               3. 若是離結尾近:

                      arr1.slice(arr1.length-n,arr1.length-m+1)

                      選擇倒數第n到倒數第m的元素

                      arr1.slice(-n,-m+1);

 

2. 修改數組splice: 刪除,插入,替換

    刪除: arr.splice(starti,n) 從arr中starti開始,刪除n個元素

        強調: 1. 不遵循含頭不含尾

                 2. 直接修改原數組

                 3. starti也支持負數參數,表示倒數第n個位置

        簡寫: 省略第二個參數: arr.splice(starti) 刪除starti後全部

        返回值: var deletes=arr.splice(starti,n)

              返回被刪除的元素組成的臨時新數組

    插入: arr.splice(starti,0,值1,值2,...)

              在arr中starti位置插入: 值1,值2,...

              原starti位置及其以後的值,向後順移

        強調: 不能打散數組參數

    替換: arr.splice(starti,n,值1,值2,...)

              在arr中先刪除starti位置後的n個元素

                         再在starti位置插入新元素

        強調: 刪除的元素個數和插入的新元素個數沒必要同樣

                數組自動調整length

3. 翻轉數組: arr.reverse();

4. ****排序:

    自定義排序算法: 冒泡,快速,插入

       冒泡: 原理:

 

 

 

 

 

 

正課:

1. ***數組:

   排序:

   棧和隊列:

   二維數組:

2. ***String

 

1. 排序:

    自定義排序: 冒泡

    排序API: arr.sort();

       大問題: 默認將全部元素轉爲字符串再按字符串排列

                  只能對字符串類型的元素正確排序

       解決: 自定義比較規則:

         比較器函數: 專門比較任意兩值大小的函數:

                   要求: 兩個參數: a,b

                            返回值: 若是a>b,就返回正數

                                        若是a<b,就返回負數

                                        若是a=b,就返回0

         最簡單的數字比較器函數:

           function compare(a,b){return a-b;}

         如何使用: 將比較器函數名做爲參數傳入sort函數中

           arr.sort(compare) //強調: 不要加()

           compare函數做爲參數傳入sort中,被sort反覆調用

         降序: 顛倒比較器函數的正負號,可改升序爲降序

           最簡單的數字降序比較器函數:

              function compare(a,b){return b-a;}

 

2. 棧和隊列: js中沒有專門的棧和隊列類型

                   一切棧和隊列都是用普通數組模擬的

   棧: 一端封閉,只能從另外一端進出的數組

    特色: FILO

   什麼時候: 從此只要但願始終使用最新的元素時

   如何:

      1. 從結尾出入棧:

          入: arr.push(值) => arr[arr.length]=值

          出: var last=arr.pop()

          特色: 每次出入棧,都不影響其餘元素的位置

      2. 從開頭出入棧:

          入: arr.unshift(值)

          出: var first=arr.shift()

          特色: 每次出入棧,其它元素位置都會依次順移

        

   隊列: 只能從一端進入,從另外一端出的數組

     特色: FIFO

   什麼時候: 只要但願按前後順序使用數組中的元素時

     1. 結尾入: 入: arr.push(值)

     2. 開頭出: var first=arr.shift()

       

3. 二維數組:

  什麼是: 數組中的元素又引用了另外一個子數組

  什麼時候: 1. 保存橫行豎列的二維數據結構

           2. 對一組數據,再進行細緻分類時

  如何:

     建立: 2種:

        1. 建立數組時,還不知道子數組的內容:

            var arr=[];

            arr[0]=[值1,值2,...];

            arr[1]=[值1,值2,...];

        2. 建立數組同時初始化元素:

             var arr=[

                   [值1,值2,...],

                   [值1,值2,...],

                   ...

             ]

     訪問: arr[r][c]->用法和普通數組元素的用法徹底同樣

         強調: 二維數組,行下標r不能越界!——報錯!

     遍歷: 外層循環控制行,內層循環控制列

        for(var r=0; r<arr.length; r++){//遍歷每一行

            for(var c=0;c<arr[r].length;c++){//遍歷第r行中每一列

             arr[r][c]//當前元素

            }

        }

 

     練習: Math.random() 生成0~1之間的一個隨機小數

             

 

 

正課:

1. ***數組:

    關聯數組:

    API:

      轉字符串

      拼接和選取

      修改

      翻轉

 

1. 關聯數組:

   索引數組: 下標爲數字的數組

   問題: 每一個元素,只有值,沒有有意義的名稱

   解決: 關聯數組: 可自定義下標名稱的數組

   如何:

      建立: 2步: 1. 先建立空數組: var scores=[]

                       2. 在空數組中添加新元素,使用自定義的下標名

                              scores["MATH"]=81;

      訪問元素: 用自定義的下標名稱:

            scores["MATH"] 用法和普通變量徹底同樣

   關聯數組原理:

       hash算法: 散列: 接收一個字符串,而後根據字符串計算出一個儘可能不重複的數字。

           相同字符串,計算出的數字必定相同

           不一樣的字符串,計算出的數字幾乎不一樣的

       關聯數組: hash數組

          存入元素: 將下標名交給hash算法,計算出一個儘可能不重複的序號,將元素存儲到數組中序號指定的位置

          獲取元素: 將下標名交給hash算法,計算出和存入時徹底同樣的序號,直接去數組中序號位置獲取元素值——不用遍歷

    爲何: 1. 由於下標有意義,便於維護

                 2. 查找極快——和總元素個數以及存儲位置無關!

    什麼時候: 1. 從此只要快速查找某個元素時,都用hash數組

             2. 從此只要存儲有意義的一組元素時,都用hash數組

    鄙視: 談談對hash的理解:

      hash算法; 存入;  獲取;   優;

 

   特色: length屬性失效,永遠爲0

   遍歷: for in循環:

      for(var key in hash){//in依次得到每一個元素的下標名稱

         key//自動得到當前元素的下標名

         hash[key]//當前元素值

      }

 

2. 數組API: 瀏覽器已經實現的,咱們直接用的函數

    數組對象: 存儲一組數據,提供操做數據的API

    1. 數組轉爲字符串: 2種:

        1. var str=String(arr): 將arr中每一個元素轉爲字符串,再用逗號連接成一個字符串。

        2. 可自定義鏈接符:

            var str=arr.join("自定義鏈接符")

            固定套路: 1. 無縫拼接: arr.join("")

                            2. 判斷數組是空數組: arr.join("")===""

                            3. 動態生成頁面元素的內容

 

 

 

 

 

 

 

 

 

正課:

1. ***String

   什麼是:

***內置對象:

***包裝類型:

   字符串API

 

1. 什麼是: 多個字符組成的只讀字符數組

      vs 數組: 下標i

                   length

                   slice()  concat

      不一樣: 數組中凡是直接修改原數組的API,字符串都不能用!

 

2. 內置對象: ES標準中規定的,瀏覽器廠商已經實現的現成的對象和API

    11個: Number  String  Boolean

              Array Date RegExp Math

              Error

              Function  Object

              Global(瀏覽器中被替換爲window)

3. 包裝類型對象:

    什麼是: 專門封裝基礎類型的值,並提供操做基礎類型值的API的對象

    爲何: 基礎類型的值,自己不包含任何API功能

    什麼時候: 只要試圖對基礎類型的值調用API時,都會自動建立對應類型的包裝類型對象來封裝基礎類型的值。

    調用後: 包裝類型對象,自動釋放!

       好比: var n=345.678;

                n.toFixed(2)=>345.678.toFixed(2)

                                    =>new Number(345.678).toFixed(2)

4. String的API:

***全部字符串API都無權修改原字符串,只能返回新字符串!

   大小寫轉換: 將字符串中全部英文字母轉爲統一的大小寫

      什麼時候: 只要不區分大小寫時,都要先轉爲一致的大小寫,再判斷。 好比: 用戶名,郵箱地址,驗證碼

      如何: str.toUpperCase() //都轉大寫

               str.toLowerCase() //都轉小寫

 

   得到指定位置的字符: str[i]

       var char=str.charAt(i);

       得到指定字符的unicode號:

       var unicode=str.charCodeAt(i); //省略i,默認是0

           將unicode號反向轉回文字

           var char=String.fromCharCode(unicode);

 

    選取子字符串: str.slice(starti,endi+1)

       str.substring(starti,endi+1) 不支持負數參數

       str.substr(starti,n): 選取starti開始的n個元素

 

 

 

 

 

 

正課:

1. ***String API

   查找關鍵詞

   替換

   切割字符串

2. *****正則表達式

 

1. 查找關鍵詞: 4種

   1. 查找一個固定的關鍵詞出現的位置:

       var i=str.indexOf("關鍵詞",fromi)

         在str中,從fromi位置開始查找"關鍵詞"的位置

         若是找到,返回關鍵詞所在位置的下標

                找不到,返回-1

         簡寫: 省略fromi,默認從0開始

       專門找最後一個關鍵詞的位置:

       var i=str.lastIndexOf("關鍵詞")

         在str中,找最後一個關鍵詞出現的位置

 

      問題: 只能找第一個關鍵詞

      解決: 正則表達式:

 

   2. 使用正則表達式查找指定的一類關鍵詞的位置:

       按模式匹配:

       var i=str.search(/正則表達式/);

           在str中查找第一個符合正則表達式要求的關鍵詞的位置

           返回值: 找到的關鍵詞的下標, 若是找不到返回-1

       什麼時候: 僅判斷是否包含敏感詞時,就用search

                若是返回不是-1,說明包含,不然說明沒找到

       忽略大小寫: /正則/i

       問題: 1. 只能得到第一個的位置,不能得到全部敏感詞

                2. 只能返回位置,不能返回內容

    3. 使用正則表達式查找指定的一類關鍵詞的內容:

        var arr=str.match(/正則/ig);

        默認只找第一個,找全部,必須加g

        返回值: 全部敏感詞組成的數組

               沒找到返回null!

           強調: 若是一個API有可能返回null,就必須先判斷不是null,再使用!

        arr.length 表示找到的關鍵詞個數

        問題: 僅返回全部關鍵詞的內容,沒法返回每一個關鍵詞位置

    4. 即找全部關鍵詞內容,又找每一個關鍵詞的位置?

        reg.exec();

 

2. 替換: 將字符串中全部敏感詞替換爲新內容

    基本替換:

    str=str.replace(/正則/ig,「替換值」);

   

 

4. *****正則表達式:

   什麼是: 專門定義一類字符串統一規則的表達式

   什麼時候: 1. 按照指定規則模糊查找一類關鍵詞時

            2. 表單中驗證輸入項的格式

   如何: 語法:  

      1. 最簡單的正則其實就是關鍵詞原文

      2. 字符集: 規定字符串中一位字符可用的備選字符列表

         什麼時候: 只要某一位字符,有多個備選字時

         如何: [備選字符列表]

           強調: 一個字符集只能匹配一位字符

           簡寫: 若是備選字符列表是連續的,就可用-省略中間字符

              一位字母: [a-zA-Z]

              一位數字: [0-9]

              一位漢字: [\u4e00-\u9fa5]

         特殊: 除了: [^排除的字符列表]

                    強調: ^必須寫在[開頭]

     3. 預約義字符集: 4個:

          \w  一位字母數字或_  =>[a-zA-Z0-9_]

          \d  一位數字  => [0-9]

          \s  一位空字符: 空格,Tab,...

          .    一位任意字符

        強調: 一個預約義字符集僅匹配一位字符

                 只有規則和預約義字符徹底一致時,才能使用

                      若是不一致, 依然須要手寫普通字符集

         字符集僅控制每一個字符的內容

     4. 量詞: 專門固定字符出現的次數

         有明確數量邊界:

           字符集{min,max}   規定字符集必須最少出現min次

                                                                 最多max次

           字符集{min,}   最少min次, 多了不限

           字符集{n}        必須n次

         沒有明確數量邊界:

           字符集?     無關緊要,最多一次

           字符集*     無關緊要,多了不限

           字符集+    {1,}

         強調: 僅修改相鄰的前一個字符集

     5. 選擇和分組:

         分組: 將多個字符集分紅一組:

             什麼時候: 若是但願一個量詞同時修飾多個字符集時

            好比: 我(了個?)?去: 我去   我了去   我了個去    我個去X

         regexper.com

         選擇: 其實就是"或"   規則1|規則2

            只要匹配任意一個規則便可

            (微|w(ei)?)\s*(信|x(in)?)

      

     手機號:

         (\+86|0086)?      +86或0086  無關緊要,最多一次

         \s*                        空字符 無關緊要,多了不限

         1

         [34578]               34578中挑一個

         \d{9}                    9位數字

         (\+86|0086)?\s*1[34578]\d{9}

     郵箱:

         字母/數字或_   一次以上

         @

         字母或數字      2位以上

         (.和 字母或數字      2到3位)   1到2次

         \w+@[a-zA-Z0-9]{2,}(.[a-zA-Z0-9]{2,3}){1,2}

        

 

正課:

1. 正則:

 指定匹配位置

2. ***String API:

    替換: 衍生: 刪除和格式化

    切割

3. ***RegExp對象

 

1. 正則:

    指定匹配位置: 三個位置:

      字符串的開頭  ^

      字符串的結尾  $

         好比: 開頭的空字符: ^\s+

                  結尾的空字符: \s+$

                  開頭或結尾的空字符^\s+|\s+$

         固定套路: 只要但願字符串和正則從頭至尾徹底匹配

                         好比同時前加^後加$

                只要用正則表達式執行驗證時,必須前加^後加$

      單詞邊界        \b  包含: ^  $   空格    標點

         好比: 單詞首字母: \b[a-z]

                  單詞尾字母: [a-z]\b

                  單獨的一個單詞no: \bno\b

 

2. ***StringAPI

  替換: 簡單替換: str=str.replace(/正則/ig, "替換值");

           問題: 不能根據不一樣的關鍵詞,選擇不一樣的值替換

     解決: 高級替換:

      str=str.replace(/正則/ig,function(kw){

          //kw會自動得到本次找到的關鍵詞內容

          return //根據不一樣kw,返回不一樣的替換值

      })

     什麼時候: 只要根據不一樣的關鍵詞,替換不一樣內容時

  衍生:

    刪除: 將關鍵詞替換爲""

    格式化: 將原字符串從新拼接爲新的格式

      好比: "19831226" => "1983年12月26日"

      2步: 1. 正則將原字符串分組

                 /(\d{4})(\d{2})(\d{2})/

               //    1         2         3

             2. 使用簡單替換: str.replace(/正則/,"...$n...")

                  $n可自動得到第n個分組的子內容

                    n從1開始

  切割: 將原字符串,按指定字符,分隔爲多個子字符串

      如何: var substrs=str.split(/正則/)

         返回切割後的多個子字符串組成的數組

                結果中,再也不包含分隔符

      固定套路: 將字符串打散成字符數組: var chars=str.split("")

 

3. ***RegExp:

    什麼是: 封裝一條正則表達式, 提供了使用正則表達式進行查找和驗證的API

    什麼時候: 1. 查詢關鍵詞的第四種狀況: 即查內容,又查位置

             2. 利用正則表達式執行驗證

    如何:

       建立: 2種:

          1. 若是正則表達式是固定不變的: var reg=/正則/ig;

               強調: /正則/中正則中的/都要轉義爲\/

          2. 若是正則表達式是動態生成的:

               var reg=new RegExp("正則"[,"ig"]);

               強調: "正則"中的" \ 都要轉義爲\"  \\

                 好比: "\d{6}" => "\\d{6}"

                

 

 

 

 

 

 

 

 

 

正課:

1. ***RegExp:

2. Math

3. ***Date

 

1. ***RegExp

   API:

     驗證: 檢查字符串是否徹底符合正則表達式的要求!

      如何: var bool=reg.test(待檢測字符串)

         強調: 只要驗證,reg中必須前加^後加$

    

     查找關鍵詞: 第四種狀況: 即找內容,又找位置

      如何: var arr=reg.exec(待查找的完整字符串)

              在"待查找的完整字符串"中,依次查找每一個符合reg要求得關鍵詞。

          返回值: 本次找到的一個關鍵詞及其位置

             arr[0]: 關鍵詞內容

                若是正則中有分組

                arr[n]: 自動保存第n個分組匹配的子內容

             arr["index"]: 當前關鍵詞位置 -> 可簡寫爲arr.index

             若是沒找到,返回null

          每次查找後,都將reg.lastIndex屬性(下次開始位置)修改成當前index+關鍵詞長度,至關跳過當前關鍵詞繼續向後找

  

      固定套路: 找全部關鍵詞:

         while((arr=reg.exec(str))!=null){

              arr[0] 關鍵詞內容

                 arr[n]  自動得到第n個分組的子內容

              arr.index 當前關鍵詞位置

         }

         若是隻須要分組的子字符串,不須要完整關鍵詞:

            可省略arr,用RegExp.$n

         while(reg.exec(str)!=null){

               RegExp.$n   自動得到第n個分組的子內容

         }

 

      練習:

       貪婪模式: 正則表達式默認匹配最長的符合條件的子字符串

              默認使用貪婪模式

              .*    .+

       懶惰模式: 僅匹配最短的符合條件的子字符串

          貪婪->懶惰:  .*?   .+?

 

2. Math:

   什麼是: 專門封裝數學計算所用常量,並提供數學計算所用API

   什麼時候: 只要數學計算時

   特色: 不能new!

   API:

     1. 取整:

         Math.ceil(num) 上取整: 只要超過,就取下一個整數

         Math.floor(num) 下取整: 省略小數部分

         Math.round(num) 四捨五入取整:

         vs toFixed(d):

           1. 小數位數: Math.round()只能取整,不能規定小數位數

                                    toFixed(d)可取整,也可規定小數位數

           2. 返回值: Math.round()返回number

                           toFixed(d)返回string

         自定義round函數:

    2. 乘方和開平方:

      乘方: Math.pow(底數, 冪)

      開平方: Math.sqrt(n)

    3. 最大值和最小值:

      Math.max(值1,值2,...);

      Math.min(值1,值2,...);

        問題: 不支持數組

        解決: Math.max.apply(null,arr)

    4. 隨機數:

        Math.random()  0<=r<1 隨機小數

        從min~max之間取隨機整數:

        Math.floor(Math.random()*(max-min+1)+min)

        從0~n之間去隨機:

        Math.floor(Math.random()*(n+1));

 

3. ***Date

   什麼是: 封裝一個時間,提供操做時間的API

   什麼時候: 只要存儲時間,都要用Date對象

   如何:

      建立: 4種:

      1. 建立日期對象,並自動得到當前客戶端系統時間

         var now=new Date();

      2. 建立日期對象,並封裝自定義時間:   

         var date=new Date("yyyy/MM/dd hh:mm:ss");

         var date=new Date(yyyy,MM-1,dd,hh,mm,ss)

      3. 複製一個日期對象:

         問題: 日期對象的計算都是直接修改原日期對象

                      計算後沒法保留計算前的舊時間

         解決: 從此若是須要同時保留開始和結束時間時

                     都要先將開始時間複製一個副本,再用副本計算

         var date1=new Date(...);

         var date2=new Date(date1);

      4. 用毫秒數建立日期對象:

         Date對象的原理:

            Date對象中保存了一個巨大的毫秒數

               起始時間爲: 1970年1月1日0點至今的毫秒數

         var date=new Date(ms);

         兩個日期對象可相減: 獲得毫秒差

 

 

 

 

 

 

 

 

 

 

正課:

1. ***日期API

2. ***Error

 

1. ***日期API

   單位:  FullYear   Month     Date          Day

             Hours      Minutes   Seconds    Milliseconds

   API: 1. 每一個單位都有一個對兒get/set方法

            好比: var year=date.getFullYear()//獲取單位的值    

                     date.setFullYear(year)//設置單位的值

            特殊: Day沒有set方法

          2. 命名: 年月日星期沒有s結尾

                      時分秒毫秒都有s結尾

          3. 取值範圍: 只有Date從1~31

                   不考慮FullYear, 其他都是從0開始,到進制-1結束

               Month: 0~11 總比現實中小1, 須要修正

               Date: 1~31   不用修正

               Day: 0~6      不用修正

               Hours: 0~23 不用修正

               Minutes/Seconds: 0~59 不用修正

   日期計算:

      1. 計算兩個日期的時間差: 兩日期相減,得毫秒數,再換算

      2. 對任意單位作加減: 3步:

           1. 取份量: var d=date.getDate();

           2. 作加減: d+=60

           3. 放回去: date.setDate(d);

                強調: 全部set方法可自動調整時間進制

          其實可簡寫爲: date.setDate(date.getDate()+60)

   轉字符串:

       date.toString() -> 當地時間的完整時間格式

       date.toLocaleString() ->當地時間的簡化版格式

       date.toLocaleDateString() -> 當地時間的日期部分

       date.toLocaleTimeString() -> 當地時間的時間部分

       date.toGMTString() -> 標準時區的標準時間

 

   做業: 自定義format函數: 2_format.html

 

2. ***Error

   什麼是錯誤(bug): 程序執行過程當中遇到的異常中斷。

          一旦發生錯誤,程序馬上退出。

   什麼是錯誤處理: 即便程序發生錯誤,也能保證程序不異常中斷的一種機制。

   如何:

       try{

           可能發生錯誤的代碼

       }catch(err){//僅在發生錯誤時,才執行

           錯誤處理代碼: 1. 提示用戶錯誤信息(String(err))

                                  2. 記錄系統日誌

       }finally{

           不管是否發生錯誤,都必須執行的代碼。

           好比: 釋放資源!

       }

  err: Error對象: 在錯誤發生時,自動建立的,保存錯誤信息的對象。

    錯誤類型6種:

        SyntaxError   語法錯誤

        ReferenceError   要使用的變量沒找到

        TypeError   錯誤的調用了對象的方法

        RangeError  參數範圍越界 好比: toFixed(d) 0~20

 

        EvalError   URIError

 

 

 

 

 

 

 

 

 

 

 

 

 

正課:

1. ***錯誤處理

2. ***Function

   *****閉包

 

1. ***錯誤處理

    只要能夠提早預料的錯誤,都要用if...else...來代替try catch

    只有沒法提早預料的錯誤,採用try catch

 

    主動拋出錯誤:

    爲何: 拋出錯誤一般是爲了提醒使用者錯誤的使用的程序

    如何: throw new Error("錯誤消息")

 

2. ***Function:

    什麼是: js中一切函數都是對象

                函數對象是專門封裝函數定義的對象。

    建立: 3種:

      1. 聲明: function 函數名(參數列表){函數體; return 返回值;}

          什麼時候: 只要一段代碼被反覆使用,都要先定義在一個專門的函數中,再反覆調用函數便可——複用

             什麼時候使用參數: 只要函數步驟中必須某些數據才能正常執行時,就要定義參數。

             什麼時候使用返回值: 若是函數的調用者須要函數的執行結果時,函數就必須返回值。

         可被聲明提早:

      2. 函數直接量:

       var  函數名=function(參數列表){函數體; return 返回值;};

         不會被聲明提早。

****聲明提早(hoist): 在開始執行程序前,將全部var聲明的變量和function聲明的函數提早到*當前做用域*的頂部,集中建立。

          賦值留在原地!

       什麼時候: 只要不但願被聲明提早時。

        揭示了: 函數名僅是一個普通的變量

                    函數定義實際上是一個對象

                    函數名中僅保存了函數對象的地址——引用

 

      3. 用new:

var fun=

     new Function("參數1","參數2",...,"函數體; return 返回值")

 

     好比: function compare(a,b){return a-b;}

              var compare=function(a,b){return a-b;}

              var compare=new Function("a","b","return a-b;");

 

***重載(overload):

  什麼是: 相同函數名,不一樣參數列表的多個函數,在調用時,可根據傳入參數的不一樣,自動選擇對應的函數調用!

   爲何: 減輕調用者的負擔,一個函數名,可執行多種操做

   什麼時候: 一項任務,根據不一樣的參數,執行不一樣的操做流程時

   如何:   js語法不支持重載效果

      變通:  全部函數對象內,都自動內建了一個arguments對象

         arguments對象:

            專門保存傳入函數的全部參數值的類數組對象

             類數組對象: (object like array)

                vs 數組: 相同: 下標, length, for遍歷

                             不一樣: 類數組對象是Object,不是Array,沒法使用Array的API

                                     數組是Array類型,可使用數組類型全部的API

 

    匿名函數:

    什麼是: 函數建立時,不被任何變量引用的函數

    爲何: 節約內存

    什麼時候: 若是一個函數只用一次,用完但願自動釋放時

        1. 回調callback: 將函數做爲參數傳遞給另外一個函數去調用 

            好比: arr.sort(function (a,b){return a-b});

                     str.replace(/reg/g,function(kw,$1,...){return ...})

        2. 自調: 建立函數後馬上調用本身!

            什麼時候: 若是一個函數只執行一次,不會再重用時

            爲何: 創建臨時做用域!避免全局污染!

            如何:

               (function(參數列表){函數體; return 返回值})();

 

 

 

 

 

 

 

 

 

 

正課:

1. *****做用域和做用域鏈

2. *****閉包

 

1. *****做用域和做用域鏈

   做用域scope:

     什麼是: 一個變量的使用範圍——使用

                 本質上做用域是一個對象——存儲

                     做用域中的變量都是對象的成員

     程序/函數的執行過程:

        1. 開始執行程序前:

            建立ECS(執行環境棧):

                依次保存每一個調用的函數的執行環境

            在ECS中壓入第一個全局執行環境(全局EC)

            建立window對象,全局EC引用window對象

            window就是全局做用域對象

        2. 開始執行程序:

            全部全局變量都保存在全局做用域對象window中

        3. 定義函數時:

            在全局添加函數名變量

            建立函數對象封裝函數定義

            函數名變量引用函數對象

            函數對象中有一個scope屬性,引用回建立函數時的做用域對象。一般都是window。

        4. 調用函數時:

            在ECS中壓入一個新的EC

            爲本次函數調用建立專門的活動對象(AO)

            在AO中建立全部函數定義中規定的局部變量

            其實AO就是函數做用域對象

                 全部局部變量都是AO的成員

            新的EC引用活動對象AO

            AO的parent指向window

            變量的使用順序:

               先用AO(函數做用域)中的局部變量

               若是AO中沒有,纔去window(全局做用域)中找

        5. 函數調用後:

            本次函數調用的EC出棧

                致使函數做用域對象AO釋放

                       致使局部變量一同釋放

   做用域鏈(scope chain): 由多個做用域對象連續引用造成的鏈式結構。

      順序: 先函數做用域對象AO->全局做用域對象window

      全部的變量都保存在做用域鏈上的對象中

          局部變量都保存在函數做用域對象AO中

          全局變量都保存在全局做用域對象window中

      控制了: 變量的使用順序

        先用AO(函數做用域)中的局部變量

               若是AO中沒有,纔去window(全局做用域)中找

 

   閉包:

     什麼是: 即重用變量,又防止變量被污染的一種機制

     爲何: 全局變量: 優: 可重用     缺: 易被全局污染

                 局部變量: 優: 不會被污染    缺: 不可重用

     什麼時候: 即重用變量,又防止變量被污染

     如何: 3步:

        1. 用外層函數包裹住受保護的變量和操做變量的內層函數

        2. 外層函數將內層函數返回到外部,被外部的變量保存

        3. 經過外部變量調用內層函數,訪問受保護的變量

     缺: 1. 佔用更多內存: 外層函數的AO

          2. 容易形成內存泄漏

     三特色: 1. 函數嵌套:

                  2. 外層函數包含一個受保護的局部變量

                 3. 外層函數將內層函數對象返回

 

 

 

 

 

 

回顧:

1. *****閉包:

   鄙視: 快速繪製閉包圖

       1. 受保護的變量,並肯定外層函數調用後,變量的值

       2. 找全部操做受保護變量的內層函數

 

正課:

1. *****面向對象OOP:

   什麼是: 程序中都是先用對象來定義數據和功能,再按照邏輯的須要,訪問對象中的數據和功能。

   爲何: 和現實中人的想法很是接近。

   什麼是對象: 內存中同時存儲多個數據和功能的存儲空間

              描述現實中一個具體事物的屬性和功能的程序結構

                     事物的屬性,會成爲對象中的屬性

                     事物的功能,會成爲對象中的方法

   什麼時候: 從此開始寫程序前,都要先用對象,描述好要操做的事物的屬性和功能,再按需使用對象的功能,訪問對象的屬性

   如何: 面向對象三大特色: 封裝,繼承,多態

      封裝: 將一個具體事物的屬性和功能集中定義在一個對象中

      建立自定義對象: ——封裝   3種:

         1. 使用對象直接量:

              var obj={

                  屬性名: 屬性值,

                         ... : ... ,

                  方法名: function(){... this.屬性名 ...},

                         ... : ... ,

              }

          強調: 對象本身的方法,要訪問本身的屬性,必須用this.屬性名.

           this->正在調用函數的當前對象本身

 

       2. 使用new: 2步: 

          var obj=new Object(); //建立一個空對象

          //向空對象中添加屬性和方法

          obj.屬性名=屬性值;

          obj.方法名=function(){...this.屬性名...};

         

     對象的本質: js中一切對象的底層都是關聯數組

                        每一個屬性/方法都是關聯數組中的元素

                        屬性名/方法名是key,屬性值/函數對象是value

 

      問題: 一次只能建立一個對象

       3. 解決: 用構造函數:

          什麼是構造函數: 專門描述一類對象統一結構的函數

          什麼時候: 從此只要反覆建立多個相同結構的對象時,都要先定義構造函數

          爲何: 複用對象的結構代碼

          如何: 2步:

            1. 定義構造函數

                function 類型名(屬性參數列表){

                     this.屬性名=屬性參數值;

                               ...=...;

                     this.方法名=function(){ ... this.屬性名 ...  }

                }

            2. 用new調用構造函數,建立並裝修新對象

                var obj=new 類型名(屬性值列表);

                     建立一個指定「類型」的對象

                     用new調用指定"類型"的構造函數來建立對象

              new: 4件事:

                1. 建立新的空對象

                2. 讓新對象繼承構造函數的原型對象

                3. 用新對象去調用構造函數

                      向新對象中添加構造函數規定的屬性

                      將屬性參數的值,保存到新對象的新屬性中

                      向新對象中添加構造函數規定的方法

                4. 將新對象的地址保存在變量

 

      按需訪問對象的屬性,調用對象的方法: 

         訪問對象的屬性: obj.屬性名   用法和普通的變量徹底同樣

                屬性就是保存在對象中的一個變量

         調用對象的方法: obj.方法名() 用法和普通的函數徹底同樣

            強調: 方法中的this,默認指.前的對象

 

      構造函數的問題: 只能複用代碼,不能節約內存

 

      繼承: 父對象的成員,子對象不用重複建立,也可直接使用

      爲何: 即節約內存,又代碼重用

      什麼時候: 只要一類子對象,須要相同的屬性或功能時,都要將相同的屬性和功能僅在父對象中定義一次便可

      如何:

        原型對象: 集中存儲同一類型的子對象所需的全部共有屬性和方法的父對象

 

 

 

 

 

 

 

正課:

1. *****OOP

   內置對象的原型對象

   共有屬性和自有屬性

   原型鏈

   原型相關API

*****自定義繼承

 

1. 內置對象的原型對象:

   全部內置對象都是一個構造函數(除Math外)

   每類內置對象都有本身的原型對象(prototype)

   全部內置對象的API都保存在類型.prototype對象中

   什麼時候: 解決瀏覽器兼容問題: 2步:

      若是類型.prototype.方法===undefined

         類型.prototype.方法=function(...){

            this->自動得到未來調用該方法的當前對象

         }

 

2. 共有屬性和自有屬性:

   自有屬性: 直接保存在對象本地的屬性

   共有屬性: 保存在父級原型對象中的屬性

   訪問共有/自有屬性:

      讀取屬性值: 便可用子對象讀取,也可用原型對象讀取

      修改屬性值:

          自有屬性: 子對象.屬性名=值

          共有屬性: 原型對象.屬性名=值

   如何判斷自有仍是共有:

      自有: var bool=obj.hasOwnProperty("屬性名")

          判斷obj中是否包含自有屬性"屬性名"

      共有: 不是自有! 且 子對象可訪問到!

 

3. ***原型鏈(prototype chain):

   什麼是原型鏈: 多級父對象連續繼承,造成的鏈式結構

      保存了: 對象的屬性和方法

      控制了: 對象的成員的使用順序

         優先使用自有成員

         本身沒有才延原型鏈向父級查找,只要找到就再也不向上

         若是整個原型鏈上都沒有,才返回undefind

   vs 做用域鏈(scope chain)

      保存了: 全局/局部的變量

      控制了: 變量的使用順序

         優先在當前函數調用的函數做用域對象(AO)中查找

         若是函數做用域對象(AO)中沒有,才延做用域鏈向全局方向查找。只要找到,就再也不繼續

         若是整個做用域鏈上都沒有,才報錯

 

鄙視題: 判斷一個對象是否是數組類型,有幾種方式

   0. typeof只能區分基礎類型和function

              沒法進一步區分對象的類型

   1. 判斷原型對象:

     若是obj的原型是Array.prototype說明是數組

      obj.__proto__==Array.prototype

      問題: __proto__是內部屬性,原本瀏覽器是禁止使用的

      解決: Object.getPrototypeOf(obj)

               得到obj的原型對象

     

 

 

 

 

 

 

正課:

1. *****OOP

   原型鏈

*****自定義繼承

 

1. 原型鏈:

  判斷一個對象是否是數組類型,有幾種方法: 4種

  0. typeof X

  1. 判斷原型對象:

     obj.__proto__==Array.prototype

         問題: __proto__是內部屬性,可能不容許使用

         Object.getPrototypeOf(obj)==Array.prototype

              問題: 只能判斷直接父對象是Array.prototype的狀況

                       沒法判斷間接繼承Array.prototype的狀況

              解決: var bool=father.isPrototypeOf(child)

                  判斷father是不是child的父級對象

                     不但檢查直接父對象,且檢查整個原型鏈!

   2. 判斷構造函數:

       每一個原型對象都有一個constructor屬性指回構造函數

       obj.constructor==Array

       還能夠用: obj instanceof Array

          instance: 實例-用一個構造函數建立出的一個具體對象

         好比: var lilei=new Student(...);

                 稱lilei是Student類型的一個實例

                 實例化一個Student類型的對象lilei

          檢查整個原型鏈

 

   要求不夠嚴格: 只要有繼承關係,就認爲是數組

   要求嚴格: 只有用數組類型建立的對象,纔是真正的數組。

 

   3. 檢查對象的class屬性

      什麼是class: 對象的內部屬性,專門保存建立對象時使用的類型名。

       只有一個辦法得到class屬性值:

          調用Object.prototype.toString();->"[object Class]"

      問題: 全部內置對象都重寫了Object中的toString

         重寫(override): 若是子對象以爲,父對象的成員很差用,可在本地定義同名的自有成員,覆蓋父對象中的。

         ——多態

      解決: 用call強行借用

        call: 強行借用一個本沒法調用的方法

        什麼時候:  想調用一個本來沒法調用的方法

        如何: 想借用的函數.call(要替換的對象)

             好比: Object.prototype.toString.call(obj)

                         至關於: obj.toString()

                         返回: "[object Class]"

 

   4. Array.isArray(obj);

      問題: ES5   IE9+

      解決: 自定義isArray方法

 

鄙視題: 對象實例方法 vs 構造函數方法

     對象實例方法: 必須用一個對象實例才能調用的方法

                            僅當前類型的對象可用!

        對象實例方法一概保存在該類型的原型對象中,全部子對象共用。

        什麼時候: 一個方法只但願當前類型的子對象才能使用時

     構造函數方法: 不須要任何對象實例,用構造函數便可直接調用的方法。

       構造函數方法一概保存在構造函數對象上

        什麼時候: 一個方法的執行和對象的類型無關時

 

2. *****自定義繼承關係:

    1. 修改單個對象的繼承關係:

       obj.__proto__=father;

       問題: 內部屬性: Object.setPrototypeOf(child,father);

                   設置child繼承father

    2. 批量修改多個對象的繼承關係:

       直接修改構造函數的prototype引用新的父對象

       obj.prototype=father

       強調: 必須在建立第一個子對象以前就換

    3. 兩種類型間的繼承: 最像Java的繼承

      什麼時候: 只要兩種類型間包含相同的屬性結構定義或相同的方法。

      如何: 3步:

         1. 抽象出一個父類型

             共同的屬性定義,集中到父類型的構造函數中

             共同的方法,集中到父類型的原型對象中

         2. 在子類型構造函數中借用父類型構造函數

              不能直接調用: this->window

             應該用call,將this替換爲當前正在建立的新對象

               父類型構造.call(this,參數...)

         3. 讓子類型原型對象繼承父類型原型對象

 

 

 

 

 

 

 

 

正課:

1. *****ES5

  對對象的保護:

     對單個屬性的保護:

         數據屬性:

         訪問器屬性:

 

對對象的保護:

   問題: 屬性可隨時直接用=賦值任何值

            屬性可隨時被訪問

            可隨時添加和刪除屬性

            ——不嚴格!

   解決: 對對象提供保護:

  

   如何:

     1. 對對象的屬性提供保護

         將對象的屬性分兩大類:

            1. 命名屬性: 可隨時經過.屬性名方式訪問的屬性

                  又分爲2類:

                     1. 數據屬性: 實際存儲屬性值的屬性

                         如何保護: 每一個屬性都包含四大特性:

                            {

                              value: 實際存儲屬性值,

                              writable: true/false, //是否可修改

                              enumerable: true/false,//是否可for in遍歷

                                    //依然可用.訪問到

                              configurable: true/false,

                                  //1. 是否可修改前兩個特性

                                  //2. 是否可刪除當前屬性

                                  //一旦改成false,不可逆!

                             }

                        特殊: 若是要定義的屬性不存在:

                           defineProperty會自動添加:

                               自動添加後,屬性的特性值都爲false

                        問題: 只能提供基本(只讀,遍歷,刪除)保護

                                沒法按照自定義規則保護屬性

                        解決:

                     2. 訪問器屬性: 不實際存儲屬性值

                                            專門對其它屬性提供驗證保護

                         什麼時候: 只要按照自定義規則保護屬性

                         如何: 也有四大特性:

                            {

                       get:function(){return 受保護的屬性值},

                               set:function(val){

                                   驗證要賦的新值val

                                   驗證經過纔將val保存到受保護的屬性中

                               },

                               enumerable:true/false,

                               configurable:true/false,

                            }

                         當經過訪問器屬性獲取受保護的屬性值時

                                自動調用get方法

                         當經過訪問器屬性爲受保護的屬性賦值時

                                自動調用set方法

                                    參數val,自動得到要賦的新值

                         大問題: 受保護的屬性值應該保存在哪兒?

                                      才能作到比人不能直接用,只能經過訪問器屬性訪問

                         解決: 閉包!

            2. 內部屬性: 沒法經過.屬性名方式訪問到的屬性

                  class    Object.prototype.toString.call(obj)

                  __proto__  Object.getPrototypeOf(obj)

                                    Object.setPrototypeOf(child,father)

     2. 對整個對象提供保護

 

 

 

 

 

 

 

正課:

1. *****ES5

  對對象的保護:

    對屬性的保護

    防篡改

  Object.create();

  數組API:

*****bind()

 

1. 對對象的保護:

   對屬性:

     命名屬性

        數據屬性:

        訪問器屬性:

           大問題: 受保護的屬性值應該保存在?

           解決: 閉包

     內部屬性

 

   防篡改: 禁止修改對象的屬性結構

     3個級別:

     1. 防擴展: 禁止向對象中添加新屬性

         Object.preventExtensions(obj)

     2. 密封: 即防擴展,又禁止刪除舊屬性

         Object.seal(obj)

            實際上是將全部屬性的configurable設置爲false

     3. 凍結: 即密封,又禁止修改全部屬性值!

          什麼時候: 若是一個對象中保存了大量不變的屬性值時

             Object.freeze(obj);

             實際上是將全部屬性的writable設置爲false!

 

2. Object.create():

   var newObj=Object.create(father,{擴展的新屬性})

    建立一個新對象newObj,繼承father,併爲newObj擴展新的自有屬性

   什麼時候: 只要繼承一個現有對象,建立一個新的子對象時

   至關於: var newObj={};

               newObj.__proto__=father;

               Object.defineProperties(newObj,{

          擴展的新屬性

               })

 

3. 數組API:

   1. 判斷: 數組中的元素是否符合要求

      1. 全部元素是否都符合要求

          var bool=

         arr.every(function(val,i,arr){ return 判斷條件 })              2. 是否包含符合要求的元素

          var bool=

              arr.some(function(val,i,arr){ return 判斷條件 })

   2. 遍歷API: 依次對數組中每一個元素執行相同的操做

      1. 對原數組中每一個元素執行相同的操做,結果保存回原數組

        arr.forEach(function(val,i,arr){  arr[i]=新值;  });

      2. 取出原數組中每一個元素的值,執行相同的操做後,保存到一個新數組中

        var newArr=arr.map(function(val,i,arr){ 

            return 操做後的元素值

        });

   3. 過濾和彙總:

       過濾: 選擇原數組中符合條件的元素,組成新數組

       var subArr=arr.filter(function(val,i,arr){

          return 判斷條件;

       });

 

       彙總: 將原數組中每一個元素統計出一個彙總結果

         var r=arr.reduce(function(prev,val,i,arr){

             return prev+val;

         },0);

         其中: 0: 表示初始值

                  prev: 截止到目前的階段彙總值

                  回調函數的返回值,自動做爲下次的prev值

相關文章
相關標籤/搜索