Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 中文字幕第二区,97精品国产高清在线看入口,最近中文字幕视频完整

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          Linux下cgroup的原理及應(yīng)用

          么是cgroup

          是什么

          CGroup 是 Control Groups 的縮寫(xiě),是 Linux 內(nèi)核提供的一種可以限制、記錄、隔離進(jìn)程組 (process groups) 所使用的物力資源 (如 cpu memory i/o 等等) 的機(jī)制。2007 年進(jìn)入 Linux 2.6.24 內(nèi)核,CGroups 不是全新創(chuàng)造的,它將進(jìn)程管理從 cpuset 中剝離出來(lái),作者是 Google 的 Paul Menage。CGroups 也是 LXC 為實(shí)現(xiàn)虛擬化所使用的資源管理手段。

          子系統(tǒng)

          subsystem,子系統(tǒng),一個(gè)通過(guò)cgroup提供的工具和接口來(lái)管理進(jìn)程集合的模塊。一個(gè)子系統(tǒng)就是一個(gè)典型的“資源控制器”,用來(lái)調(diào)度資源或者控制資源使用的上限。其實(shí)每種資源就是一個(gè)子系統(tǒng)。子系統(tǒng)可以是以進(jìn)程為單位的任何東西,比如虛擬化子系統(tǒng)、內(nèi)存子系統(tǒng)。

          hierarchy,層級(jí)樹(shù),多個(gè)cgroup的集合,這些集合構(gòu)成的樹(shù)叫hierarchy??梢哉J(rèn)為這是一個(gè)資源樹(shù),附著在這上面的進(jìn)程可以使用的資源上限必須受樹(shù)上節(jié)點(diǎn)(cgroup)的控制。hierarchy上的層次關(guān)系通過(guò)cgroupfs虛擬文件系統(tǒng)顯示。系統(tǒng)允許多個(gè)hierarchy同時(shí)存在,每個(gè)hierachy包含系統(tǒng)中的部分或者全部進(jìn)程集合。

          cgroupfs是用戶管理操縱cgroup的主要接口:通過(guò)在cgroupfs文件系統(tǒng)中創(chuàng)建目錄,實(shí)現(xiàn)cgroup的創(chuàng)建;通過(guò)向目錄下的屬性文件寫(xiě)入內(nèi)容,設(shè)置cgroup對(duì)資源的控制;向task屬性文件寫(xiě)入進(jìn)程ID,可以將進(jìn)程綁定到某個(gè)cgroup,以此達(dá)到控制進(jìn)程資源使用的目的;也可以列出cgroup包含的進(jìn)程pid。這些操作影響的是sysfs關(guān)聯(lián)的hierarchy,對(duì)其它hierarchy沒(méi)有影響。

          對(duì)于cgroup,其本身的作用只是任務(wù)跟蹤。但其它系統(tǒng)(比如cpusets,cpuacct),可以利用cgroup的這個(gè)功能實(shí)現(xiàn)一些新的屬性,比如統(tǒng)計(jì)或者控制一個(gè)cgroup中進(jìn)程可以訪問(wèn)的資源。舉個(gè)例子,cpusets子系統(tǒng)可以將進(jìn)程綁定到特定的cpu和內(nèi)存節(jié)點(diǎn)上。

          cgroups子系統(tǒng)的特點(diǎn)

          cpu 子系統(tǒng),主要限制進(jìn)程的 cpu 使用率。

          cpuacct 子系統(tǒng),可以統(tǒng)計(jì) cgroups 中的進(jìn)程的 cpu 使用報(bào)告。

          cpuset 子系統(tǒng),可以為 cgroups 中的進(jìn)程分配單獨(dú)的 cpu 節(jié)點(diǎn)或者內(nèi)存節(jié)點(diǎn)。

          memory 子系統(tǒng),可以限制進(jìn)程的 memory 使用量。

          blkio 子系統(tǒng),可以限制進(jìn)程的塊設(shè)備 io。

          devices 子系統(tǒng),可以控制進(jìn)程能夠訪問(wèn)某些設(shè)備。

          net_cls 子系統(tǒng),可以標(biāo)記 cgroups 中進(jìn)程的網(wǎng)絡(luò)數(shù)據(jù)包,然后可以使用 tc 模塊(traffic control)對(duì)數(shù)據(jù)包進(jìn)行控制。

          net_prio — 這個(gè)子系統(tǒng)用來(lái)設(shè)計(jì)網(wǎng)絡(luò)流量的優(yōu)先級(jí)

          freezer 子系統(tǒng),可以掛起或者恢復(fù) cgroups 中的進(jìn)程。

          ns 子系統(tǒng),可以使不同 cgroups 下面的進(jìn)程使用不同的 namespace

          hugetlb — 這個(gè)子系統(tǒng)主要針對(duì)于HugeTLB系統(tǒng)進(jìn)行限制,這是一個(gè)大頁(yè)文件系統(tǒng)。

          cgroups 層級(jí)結(jié)構(gòu)(Hierarchy)

          內(nèi)核使用 cgroup 結(jié)構(gòu)體來(lái)表示一個(gè) control group 對(duì)某一個(gè)或者某幾個(gè) cgroups 子系統(tǒng)的資源限制。cgroup 結(jié)構(gòu)體可以組織成一顆樹(shù)的形式,每一棵cgroup 結(jié)構(gòu)體組成的樹(shù)稱之為一個(gè) cgroups 層級(jí)結(jié)構(gòu)。

          cgroups層級(jí)結(jié)構(gòu)可以 attach 一個(gè)或者幾個(gè) cgroups 子系統(tǒng),當(dāng)前層級(jí)結(jié)構(gòu)可以對(duì)其 attach 的 cgroups 子系統(tǒng)進(jìn)行資源的限制。每一個(gè) cgroups 子系統(tǒng)只能被 attach 到一個(gè) cpu 層級(jí)結(jié)構(gòu)中。

          創(chuàng)建了 cgroups 層級(jí)結(jié)構(gòu)中的節(jié)點(diǎn)(cgroup 結(jié)構(gòu)體)之后,可以把進(jìn)程加入到某一個(gè)節(jié)點(diǎn)的控制任務(wù)列表中,一個(gè)節(jié)點(diǎn)的控制列表中的所有進(jìn)程都會(huì)受到當(dāng)前節(jié)點(diǎn)的資源限制。同時(shí)某一個(gè)進(jìn)程也可以被加入到不同的 cgroups 層級(jí)結(jié)構(gòu)的節(jié)點(diǎn)中,因?yàn)椴煌?cgroups 層級(jí)結(jié)構(gòu)可以負(fù)責(zé)不同的系統(tǒng)資源。所以說(shuō)進(jìn)程和 cgroup 結(jié)構(gòu)體是一個(gè)多對(duì)多的關(guān)系。

          上面這個(gè)圖從整體結(jié)構(gòu)上描述了進(jìn)程與 cgroups 之間的關(guān)系。最下面的P代表一個(gè)進(jìn)程。每一個(gè)進(jìn)程的描述符中有一個(gè)指針指向了一個(gè)輔助數(shù)據(jù)結(jié)構(gòu)css_set(cgroups subsystem set)。 指向某一個(gè)css_set的進(jìn)程會(huì)被加入到當(dāng)前css_set的進(jìn)程鏈表中。一個(gè)進(jìn)程只能隸屬于一個(gè)css_set,一個(gè)css_set可以包含多個(gè)進(jìn)程,隸屬于同一css_set的進(jìn)程受到同一個(gè)css_set所關(guān)聯(lián)的資源限制。

          上圖中的”M×N Linkage”說(shuō)明的是css_set通過(guò)輔助數(shù)據(jù)結(jié)構(gòu)可以與 cgroups 節(jié)點(diǎn)進(jìn)行多對(duì)多的關(guān)聯(lián)。但是 cgroups 的實(shí)現(xiàn)不允許css_set同時(shí)關(guān)聯(lián)同一個(gè)cgroups層級(jí)結(jié)構(gòu)下多個(gè)節(jié)點(diǎn)。 這是因?yàn)?cgroups 對(duì)同一種資源不允許有多個(gè)限制配置。

          一個(gè)css_set關(guān)聯(lián)多個(gè) cgroups 層級(jí)結(jié)構(gòu)的節(jié)點(diǎn)時(shí),表明需要對(duì)當(dāng)前css_set下的進(jìn)程進(jìn)行多種資源的控制。而一個(gè) cgroups 節(jié)點(diǎn)關(guān)聯(lián)多個(gè)css_set時(shí),表明多個(gè)css_set下的進(jìn)程列表受到同一份資源的相同限制。

          CGroup 典型應(yīng)用架構(gòu)圖

          CGroup 技術(shù)可以被用來(lái)在操作系統(tǒng)底層限制物理資源,起到 Container 的作用。圖中每一個(gè) JVM 進(jìn)程對(duì)應(yīng)一個(gè) Container Cgroup 層級(jí),通過(guò) CGroup 提供的各類子系統(tǒng),可以對(duì)每一個(gè) JVM 進(jìn)程對(duì)應(yīng)的線程級(jí)別進(jìn)行物理限制,這些限制包括 CPU、內(nèi)存等等許多種類的資源。下一部分會(huì)具體對(duì)應(yīng)用程序進(jìn)行 CPU 資源隔離進(jìn)行演示。

          CGroup 相關(guān)概念解釋

          任務(wù)(task)。在 cgroups 中,任務(wù)就是系統(tǒng)的一個(gè)進(jìn)程;

          控制族群(control group)??刂谱迦壕褪且唤M按照某種標(biāo)準(zhǔn)劃分的進(jìn)程。Cgroups 中的資源控制都是以控制族群為單位實(shí)現(xiàn)。一個(gè)進(jìn)程可以加入到某個(gè)控制族群,也從一個(gè)進(jìn)程組遷移到另一個(gè)控制族群。一個(gè)進(jìn)程組的進(jìn)程可以使用 cgroups 以控制族群為單位分配的資源,同時(shí)受到 cgroups 以控制族群為單位設(shè)定的限制;

          層級(jí)(hierarchy)。控制族群可以組織成 hierarchical 的形式,既一顆控制族群樹(shù)。控制族群樹(shù)上的子節(jié)點(diǎn)控制族群是父節(jié)點(diǎn)控制族群的孩子,繼承父控制族群的特定的屬性;

          子系統(tǒng)(subsystem)。一個(gè)子系統(tǒng)就是一個(gè)資源控制器,比如 cpu 子系統(tǒng)就是控制 cpu 時(shí)間分配的一個(gè)控制器。子系統(tǒng)必須附加(attach)到一個(gè)層級(jí)上才能起作用,一個(gè)子系統(tǒng)附加到某個(gè)層級(jí)以后,這個(gè)層級(jí)上的所有控制族群都受到這個(gè)子系統(tǒng)的控制。

          相互關(guān)系

          每次在系統(tǒng)中創(chuàng)建新層級(jí)時(shí),該系統(tǒng)中的所有任務(wù)都是那個(gè)層級(jí)的默認(rèn) cgroup(我們稱之為 root cgroup,此 cgroup 在創(chuàng)建層級(jí)時(shí)自動(dòng)創(chuàng)建,后面在該層級(jí)中創(chuàng)建的 cgroup 都是此 cgroup 的后代)的初始成員;

          一個(gè)子系統(tǒng)最多只能附加到一個(gè)層級(jí);

          一個(gè)層級(jí)可以附加多個(gè)子系統(tǒng);

          一個(gè)任務(wù)可以是多個(gè) cgroup 的成員,但是這些 cgroup 必須在不同的層級(jí);

          系統(tǒng)中的進(jìn)程(任務(wù))創(chuàng)建子進(jìn)程(任務(wù))時(shí),該子任務(wù)自動(dòng)成為其父進(jìn)程所在 cgroup 的成員。然后可根據(jù)需要將該子任務(wù)移動(dòng)到不同的 cgroup 中,但開(kāi)始時(shí)它總是繼承其父任務(wù)的 cgroup。

          實(shí)戰(zhàn)

          安裝cgroup服務(wù)

          centos 6
          yum install -y libcgroup
          
          centos 7 
          yum install -y libcgroup libcgroup-tools
          

          配置cgroup配置

          這里需要是限制cpu
          先創(chuàng)建一個(gè)組,把需要限制的進(jìn)程,啟動(dòng)的時(shí)候放到這組下。

          vim /etc/cgconfig.conf

          mount {
          # cpuset = /cgroup/cpuset;
           cpu = /cgroup/cpu;
          # cpuacct = /cgroup/cpuacct;
          # memory = /cgroup/memory;
          # devices = /cgroup/devices;
          # freezer = /cgroup/freezer;
          # net_cls = /cgroup/net_cls;
          # blkio = /cgroup/blkio;
          }
          group yarn { # yarn 為組名
           perm {
           task {
           uid = hadoop; # 權(quán)限設(shè)置,為hadoop
           gid = hadoop;
           }
           admin {
           uid = hadoop;
           gid = hadoop;
           }
           }
           cpu { # 可以用 cpu.cfs_period_us 和 cpu.cfs_quota_us 來(lái)限制該組中的所有進(jìn)程在單位時(shí)間里可以使用的 cpu 時(shí)間。
           cpu.cfs_period_us= 100000; # 就是時(shí)間周期,默認(rèn)為 100000,即百毫秒 值的范圍: 1000-100000 
           cpu.cfs_quota_us= 2160000; # cpu.cfs_quota_us 就是在這期間內(nèi)可使用的 cpu 時(shí)間,默認(rèn) -1,即無(wú)限制
           } # 現(xiàn)在這個(gè)設(shè)置代表,這個(gè)組可以用的cpu為21.6盒,2160000/100000 
          }
          

          啟動(dòng)cgroup服務(wù)

          . 初識(shí)JS

          1.1 什么是JS語(yǔ)言

          javascript是一種運(yùn)行在客戶端 的腳本語(yǔ)言

          客戶端: 即接受服務(wù)的一端,與服務(wù)端相對(duì)應(yīng),在前端開(kāi)發(fā)中,通??蛻舳酥傅木褪菫g覽器。

          腳本語(yǔ)言: 也叫解釋型語(yǔ)言,特點(diǎn)是執(zhí)行一行,解釋一行,如果發(fā)現(xiàn)報(bào)錯(cuò),代碼就停止執(zhí)行。

          1.2 JS的三個(gè)組成部分

          javascript的三個(gè)組成部分:ECMAScript、BOM、DOM

          ECMAScript: 定義了javascript的語(yǔ)法規(guī)范。

          BOM: 一套操作瀏覽器功能的API。

          DOM: 一套操作頁(yè)面元素的API。

          1.3 script 標(biāo)簽

          1、script標(biāo)簽的書(shū)寫(xiě)方式

          書(shū)寫(xiě)Javascript代碼有兩種方式,第一種是直接在script標(biāo)簽中書(shū)寫(xiě),第二種是將代碼寫(xiě)在js文件中,通過(guò)script的src屬性進(jìn)行引入。

          直接在script中書(shū)寫(xiě)javascript代碼:

          <!-- type="text/javascript" 可以省略 -->
          <script type="text/javascript">
           alert("今天天氣真好呀");
          </script>
          

          通過(guò)script標(biāo)簽引入一個(gè)JS文件,需要指定src屬性:

          <!-- 表示引用了test.js文件,并且script標(biāo)簽內(nèi)不可以繼續(xù)寫(xiě)代碼 -->
          <script src="test.js"></script> 
          

          如果script標(biāo)簽指定了src屬性,說(shuō)明是想要引入一個(gè)js文件,這個(gè)時(shí)候不能繼續(xù)在script標(biāo)簽中寫(xiě)js代碼,即便寫(xiě)了,也不會(huì)執(zhí)行。

          2、script標(biāo)簽的書(shū)寫(xiě)位置

          script標(biāo)簽的書(shū)寫(xiě)位置,原則上來(lái)說(shuō),可以在頁(yè)面中的任意位置書(shū)寫(xiě)。

          寫(xiě)在head標(biāo)簽中,style標(biāo)簽之后:

          <!DOCTYPE html>
          <html lang="en">
          <head>
           <meta charset="UTF-8">
           <title>Document</title>
           <link rel="stylesheet" href="demo.css">
           <!-- 寫(xiě)在這里 -->
           <script src="demo.js"></script>
          </head>
          <body>
          </body>
          </html>
          

          瀏覽器有一個(gè)特性,就是在遇到<body>標(biāo)簽時(shí)才開(kāi)始呈現(xiàn)內(nèi)容。如果在head里面引用js文件的話,意味著必須要等到全部的javascript代碼都被下載、解析和執(zhí)行完成之后,才能開(kāi)始呈現(xiàn)頁(yè)面的內(nèi)容。如果文件數(shù)量一旦過(guò)多,將會(huì)影響頁(yè)面加載速度,此時(shí)頁(yè)面有可能會(huì)在加載完成前一片空白。

          寫(xiě)在</body>標(biāo)簽的前面:

          <!DOCTYPE html>
          <html lang="en">
          <head>
           <meta charset="UTF-8">
           <title>Document</title>
           <link rel="stylesheet" href="demo.css">
          </head>
          <body>
           <!-- 寫(xiě)在這里 -->
           <script src="demo.js"></script>
          </body>
          </html>
          

          在解析javascript代碼之前,頁(yè)面的內(nèi)容已經(jīng)完全呈現(xiàn)在瀏覽器當(dāng)中了,用戶會(huì)明顯感覺(jué)頁(yè)面加載變快了。

          1.4 js中輸入輸出語(yǔ)句

          • console.log 控制臺(tái)輸出日志
          • console.dir 對(duì)象的形式打印一個(gè)對(duì)象
          • document.write 往頁(yè)面中寫(xiě)入內(nèi)容
          • alert 彈框警告
          • confirm 確認(rèn)框
          • prompt 輸入框

          1.5 注釋

          不被程序執(zhí)行的代碼。用于程序員標(biāo)記代碼,在后期的修改,以及他人的學(xué)習(xí)時(shí)有所幫助,在JS中,分為單行注釋和多行注釋以及文檔注釋。

          單行注釋

          //這是單行注釋,只能注釋一行
          

          多行注釋

          /*
           這是多行注釋,不能嵌套
          */
          

          文檔注釋

          /**
           * 求圓的面積
           * @param r {number} 圓的半徑
           * @returns {number} 圓的面積
           * 這是文檔注釋
           */
          function getArea (r) {
           return Math.PI * r * r;
          }
          

          注釋的作用

          • 模塊劃分,方便代碼查找和維護(hù)
          • 用于解釋復(fù)雜代碼的邏輯,方便維護(hù)和后期開(kāi)發(fā)。

          2. 變量

          變量,可以變化的量,變量是在計(jì)算機(jī)中存儲(chǔ)數(shù)據(jù)的一個(gè)標(biāo)識(shí)符。可以把變量看成存儲(chǔ)數(shù)據(jù)的容器。

          變量與字面量:

          • 字面量:10、20、“abc”、true這種從字面上就能看出來(lái)類型和值的量叫做字面量。
          • 變量:可以變化的量。

          2.1 變量的聲明與賦值

          // 1- 同時(shí)聲明并且賦值
          var num = 100;
          console.log(num); // 100
          // 2- 先聲明了一個(gè)變量,再賦值
          var num1;
          num1 = 100;
          console.log(num1); // 100
          // 3- 沒(méi)有聲明變量,直接賦值(可以,但是不推薦)
          num2 = 200;
          console.log(num2); // 200
          // 4- 有變量聲明,但是沒(méi)有賦值(可以,沒(méi)有賦值,變量的值默認(rèn)是個(gè)undefined)
          var num9;
          console.log(num9); // undefined
          // 5- 既沒(méi)有聲明,也沒(méi)有賦值,直接用。
          console.log(num3); //報(bào)錯(cuò) num3
          // 6- 一個(gè) var,逗號(hào)分隔 可以同時(shí)聲明多個(gè)變量
          var name = "Levi丶",
           age = 18,
           gender = "男";
          

          2.2 變量的命名規(guī)則與規(guī)范

          命名規(guī)則(必須遵守):

          • 由字母、數(shù)字、下劃線、$符號(hào)組成,開(kāi)頭不能是數(shù)字。
          • 不能使用關(guān)鍵字和保留字
          • 區(qū)分大小寫(xiě)

          命名規(guī)范(建議遵守):

          • 命名要有意義
          • 遵守駝峰命名法。首字母小寫(xiě),后面單詞的首字母需要大寫(xiě)。

          2.3 交換兩個(gè)變量的值

          方法一: 聲明一個(gè)新的變量

          // 交換 num1 和 num2的值
          var num1 = 11;
          var num2 = 22;
          var temp;
          temp = num1; // num1=11 temp=11
          num1 = num2; // num1=22 num2=22
          num2 = temp; // temp=11 num2=11
          

          方法二: 不通過(guò)聲明變量的方式

          // 不使用臨時(shí)變量
          var num1 = 11;
          var num2 = 22;
          // num1 = 11 + 22
          num1 = num1 + num2; // num1=33 
          // num2 = 33 - 22
          num2 = num1 - num2; // num2=11
          // num1 = 33 - 11 
          num1 = num1 - num2; // num1=22
          

          3. 數(shù)據(jù)類型

          基本數(shù)據(jù)類型包括了:number、string、boolean、undefined、null

          3.1 如何查看數(shù)據(jù)類型

          使用typeof關(guān)鍵字查看數(shù)據(jù)類型
          typeof(name); 
          // 括號(hào)可以省略
          typeof name;
          

          3.2 Number 類型

          進(jìn)制

          • 十進(jìn)制,我們平時(shí)使用的就是十進(jìn)制,進(jìn)行運(yùn)算時(shí),八進(jìn)制和十六進(jìn)制的值最終都會(huì)轉(zhuǎn)換成十進(jìn)制。
          • 二進(jìn)制,計(jì)算機(jī)當(dāng)中用的最多的計(jì)算方式,數(shù)值序列只有0和1
          • 八進(jìn)制,0開(kāi)頭的數(shù)值,數(shù)值序列:0-7
          • 十六進(jìn)制,0x開(kāi)頭的數(shù)值,數(shù)值序列:0-9、A-F、a-f

          浮點(diǎn)數(shù)

          所謂浮點(diǎn)數(shù),就是該數(shù)當(dāng)中必須包含一個(gè)小數(shù)點(diǎn),并且小數(shù)點(diǎn)后面至少有一位數(shù)字。

          科學(xué)計(jì)數(shù)法:

          //如何表示0.003和20000?
          var num = 3e-3; // 0.003
          var num2 = 2e+4; // 20000 
          

          浮點(diǎn)數(shù)的精度問(wèn)題:

          0.1 + 0.2 = ? // 0.30000000000000004
          0.07 * 100 = ? // 7.000000000000001
          

          浮點(diǎn)數(shù)在運(yùn)算的時(shí)候會(huì)出現(xiàn)精度丟失的問(wèn)題,因此在做比較運(yùn)算的時(shí)候,盡量不要用小數(shù)進(jìn)行比較。在第五章的時(shí)候會(huì)著重講解這個(gè)問(wèn)題

          數(shù)值范圍

          javascript不能表示世界上所有的數(shù),因此在javascript中,數(shù)值大小是有一定限制的。
          • Number.MIN_VALUE:5e-324 (js里面能表示最小的數(shù))
          • Number.MAX_VALUE:1.7976931348623157e+308 (js里面能表示最大的數(shù))
          • Infinity:正無(wú)窮 (如果超出js里面最大的數(shù),將會(huì)顯示infinity)
          • -Infinity:負(fù)無(wú)窮 (如果超出js里面最小的數(shù),將會(huì)顯示-infinity)

          數(shù)值判斷

          • NaN: 表示一個(gè)非數(shù)值,當(dāng)無(wú)法運(yùn)算或者運(yùn)算錯(cuò)誤的時(shí)候,會(huì)得到一個(gè)NaN,NaN是number類型,表示一個(gè)非數(shù)值。
          • NaN與任何值都不想等,包括它本身
          • isNaN: 用來(lái)判斷是否是一個(gè)數(shù)字,當(dāng)返回true的時(shí)候說(shuō)明是NaN,表示的不是一個(gè)數(shù)字,返回false,說(shuō)明不是NaN,表示的是一個(gè)數(shù)字。

          示例代碼:

          var str = "abc";
          console.log(isNaN(str)); // true 說(shuō)明不是一個(gè)數(shù)字
          

          3.3 String 類型

          字面量

          字符串的字面量:“abc” 、 ‘a(chǎn)bc’ 字符串可以是雙引號(hào),也可以是單引號(hào)引起來(lái)。

          不管是雙引號(hào),還是單引號(hào),都是成對(duì)出現(xiàn)的,假如打印的字符串里有引號(hào)怎么辦呢?

          這里就要活學(xué)活用,如果只有一處有引號(hào),就可以用單雙引號(hào)混合使用:

          console.log('我是"帥哥"'); // ==> 我是"帥哥"
          

          假如引號(hào)非常多的時(shí)候怎么辦呢? 用轉(zhuǎn)義字符:“\”:

          console.log("我是'帥哥',\"哈哈哈\""); // ==> 我是'帥哥',"哈哈哈"
          

          字符串拼接

          拼接字符串使用+號(hào)

          示例代碼:

          console.log(11 + 11); // 22
          console.log("hello" + " world"); // "hello world"
          console.log("100" + "100"); // "100100"
          console.log("11" + 11); // "1111"
          

          總結(jié):

          • 兩邊只要有一個(gè)是字符串,那么+就是字符串拼接功能
          • 兩邊如果都是數(shù)字,那么就是算術(shù)功能。

          字符串長(zhǎng)度

          length屬性用來(lái)獲取字符串的長(zhǎng)度
          var str = "abcdefghij";
          str.length;// 字符串的長(zhǎng)度 10
          

          3.4. boolean 類型

          boolean類型只有兩個(gè)字面量,true和false,區(qū)分大小寫(xiě)(True,F(xiàn)alse不是布爾類型,只是標(biāo)識(shí)符)。

          所有類型的值都可以轉(zhuǎn)化成true或者false

          NaN、""、undefined、null、alse、0 這6個(gè)值可以轉(zhuǎn)換成false,其余的都是true。

          3.5 undefined類型與null類型

          undefined表示一個(gè)聲明了沒(méi)有賦值的變量

          var name ;
          console.log(name); // undefined
          

          null表示一個(gè)空的對(duì)象

          var name = null;
          console.log(typeof name); // Object
          

          如果定義的變量,將來(lái)是準(zhǔn)備用于保存對(duì)象的話,最好將變量初始化為null

          var name = null;
          

          undefined 與 null 的關(guān)系

          undefined == null; // true
          undefined === null; // false
          

          實(shí)際上,undefiner值是派生自null值的,所以判斷相等時(shí)為true,但是兩種用途是完全不一樣的。

          4. 簡(jiǎn)單數(shù)據(jù)類型轉(zhuǎn)換

          如何使用谷歌瀏覽器,快速的查看數(shù)據(jù)類型?
          • 字符串的顏色是黑色的
          • 數(shù)值類型是藍(lán)色的
          • 布爾類型也是藍(lán)色的
          • undefined和null是灰色的

          這個(gè)在調(diào)試過(guò)程中時(shí)非常有用的。

          4.1 轉(zhuǎn)字符串類型

          1、String()函數(shù)轉(zhuǎn)換

          var num = 123;
          console.log(String(num)); // "123"
          

          2、toString() 轉(zhuǎn)換不了undefined 和 null

          var num = 123;
          console.log(num.toString()); // "123"
          console.log(undefined.toString()); // 報(bào)錯(cuò)
          console.log(null.toString()); // 報(bào)錯(cuò)
          

          3、+ "" 加引號(hào)

          var num = 123;
          console.log(num + ""); // "123"
          

          4.2 轉(zhuǎn)數(shù)值類型

          1、Number

          • 如果轉(zhuǎn)換的是空字符串,返回的是0;
          • 如果是數(shù)字字符串,轉(zhuǎn)換后保留原數(shù)據(jù);
          • 非數(shù)字字符串,轉(zhuǎn)換之后為NaN;
          console.log(Number("-123")); // -123
          console.log(Number("")); // 0
          console.log(Number("123abc")); // NaN
          

          2、parseInt(取整)

          • 小數(shù)數(shù)字字符串,轉(zhuǎn)換之后,保留整數(shù)部分(取整);
          • 數(shù)字開(kāi)頭非純數(shù)字字符串,轉(zhuǎn)換之后保留整數(shù)部分;
          • 非數(shù)字字符串,轉(zhuǎn)換之后為NaN;
          console.log(parseInt("123.123")); // 123
          console.log(parseInt("123.123abc")); // 123
          console.log(parseInt("abc123.123")); // NaN
          console.log(parseInt("")); // NaN
          console.log(parseInt("abc")); // NaN
          

          3、parseFloat(取數(shù))

          • 數(shù)字字符串,轉(zhuǎn)換之后保留原數(shù)據(jù);
          • 數(shù)字開(kāi)頭的非純數(shù)字字符串,轉(zhuǎn)換之后保留數(shù)字部分(包括小數(shù));
          • 非數(shù)字字符串轉(zhuǎn)換之后為NaN;
          console.log(parseFloat("123.123")); // 123.123
          console.log(parseFloat("123.123abc")); // 123.123
          console.log(parseFloat("abc123.123")); // NaN
          console.log(parseFloat("")); // NaN
          console.log(parseFloat("abc")); // NaN
          

          4、參與運(yùn)算==> "+" or "-0"

          var str = "-123";
          console.log(+str); // -123
          console.log(str-0); // -123
          

          4.3 轉(zhuǎn)布爾類型

          布爾類型只有true和false,但是所有類型的值都可以轉(zhuǎn)換成布爾類型

          1、能夠轉(zhuǎn)換成false的只有6種:

          • ""
          • 0
          • NaN
          • undefined
          • null
          • false

          其余的都是true

          2、! 轉(zhuǎn)換

          var str = "";
          // Boolean() 判斷這個(gè)參數(shù)的布爾類型
          console.log(Boolean(str)); // false
          console.log(!str); // true
          

          5. JS小數(shù)運(yùn)算精度丟失

          5.1 JS數(shù)字精度丟失的一些典型問(wèn)題

          js在使用小數(shù)進(jìn)行計(jì)算的時(shí)候,會(huì)出現(xiàn)精度丟失的問(wèn)題。不要用來(lái)跟其他的小數(shù)做比較。

          0.1 + 0.2 != 0.3 //true 0.30000000000000004
          // 16位數(shù) 和 17位數(shù)相等
          9999999999999999 == 10000000000000001 // true
          9007199254740992 + 1 == 9007199254740992 // true
          

          5.2 JS數(shù)字丟失精度的原因

          計(jì)算機(jī)的二進(jìn)制實(shí)現(xiàn)和位數(shù)限制有些數(shù)無(wú)法有限表示。就像一些無(wú)理數(shù)不能有限表示,如 圓周率 3.1415926...,1.3333... 等。JS 遵循 IEEE 754 規(guī)范,采用 雙精度存儲(chǔ)(double precision) ,占用 64 bit。如圖

          意義:

          • 1位用來(lái)表示符號(hào)位
          • 11位用來(lái)表示指數(shù)
          • 52位表示尾數(shù)

          浮點(diǎn)數(shù),比如:

          0.1 >> 0.0001 1001 1001 1001…(1001無(wú)限循環(huán))
          0.2 >> 0.0011 0011 0011 0011…(0011無(wú)限循環(huán))
          

          此時(shí)只能模仿十進(jìn)制進(jìn)行四舍五入了,但是二進(jìn)制只有0和1兩個(gè),于是變?yōu)?舍1入。這即是計(jì)算機(jī)中部分浮點(diǎn)數(shù)運(yùn)算時(shí)出現(xiàn)誤差,丟失精度的根本原因。

          大整數(shù)的精度丟失和浮點(diǎn)數(shù)本質(zhì)上是一樣的,尾數(shù)位最大是 52 位,因此 JS 中能精準(zhǔn)表示的最大整數(shù)是 Math.pow(2, 53),十進(jìn)制即 9007199254740992。

          大于 9007199254740992 的可能會(huì)丟失精度:

          9007199254740992 >> 10000000000000...000 // 共計(jì) 53 個(gè) 0
          9007199254740992 + 1 >> 10000000000000...001 // 中間 52 個(gè) 0
          9007199254740992 + 2 >> 10000000000000...010 // 中間 51 個(gè) 0
          

          實(shí)際上:

          9007199254740992 + 1 // 丟失 
          9007199254740992 + 2 // 未丟失
          9007199254740992 + 3 // 丟失
          9007199254740992 + 4 // 未丟失
          

          結(jié)果如圖:

          以上,可以知道看似有窮的數(shù)字,在計(jì)算機(jī)的二進(jìn)制表示里卻是無(wú)窮的,由于存儲(chǔ)位數(shù)限制因此存在“舍去”,精度丟失就發(fā)生了。

          5.3 JS數(shù)字丟失精度的解決方案

          對(duì)于整數(shù),前端出現(xiàn)問(wèn)題的幾率可能比較低,畢竟很少有業(yè)務(wù)需要需要用到超大整數(shù),只要運(yùn)算結(jié)果不超過(guò) Math.pow(2, 53) 就不會(huì)丟失精度。

          對(duì)于小數(shù),前端出現(xiàn)問(wèn)題的幾率還是很多的,尤其在一些電商網(wǎng)站涉及到金額等數(shù)據(jù)。解決方式:把小數(shù)放到位整數(shù)(乘倍數(shù)),再縮小回原來(lái)倍數(shù)(除倍數(shù))

          // 0.1 + 0.2
          (0.1*10 + 0.2*10) / 10 == 0.3 // true
          

          6. 運(yùn)算符

          6.1 一元運(yùn)算符

          • 一元運(yùn)算符有1個(gè)操作數(shù)。例如,遞增運(yùn)算符"++",或者遞減運(yùn)算符"--"就是一元運(yùn)算符。
          • 二元運(yùn)算符有2個(gè)操作數(shù)。例如,除法運(yùn)算符"/"有2個(gè)操作數(shù)。
          • 三元運(yùn)算符有3個(gè)操作數(shù)。例如,條件運(yùn)算符"?:"具有3個(gè)操作數(shù)。
          遞增 "++" 和 遞減 "--" 還分為前自增或后自增,前自減或后自減,兩種自增自減的運(yùn)算結(jié)果是不一樣的;
          • ++num 前自增 --num 前自減 先+1或-1,再返回值
          • num++ 后自增 num-- 后自減 先返回值,再+1或-1

          舉個(gè)例子,看代碼:

          var num = 5;
          console.log(num++); // 5 
          console.log(++num); // 7 (因?yàn)閯倓俷um自增了一次,這里打印的話就等于在6的基礎(chǔ)上前自增了,在計(jì)算機(jī)科學(xué)中,被稱為副效應(yīng))
          console.log(num--); // 7 (這里是后自減,所以先返回值,返回7,再運(yùn)算--,此時(shí)的num實(shí)際是等于6了)
          console.log(--num); // 5
          

          6.2 邏輯運(yùn)算符

          • &&(與運(yùn)算):只要有一個(gè)值為假,結(jié)果就是假。找假值 找到假值就返回,如果都是真,返回最后一個(gè)
          • ||(或運(yùn)算):只要有一個(gè)值為真,結(jié)果就是真。找真值 找到真值就返回,如果都是假,返回最后一個(gè)
          • !(非運(yùn)算):取反

          示例代碼:

          /*細(xì)讀上面三句話,就能理解為什么會(huì)是這個(gè)打印結(jié)果了*/
          console.log(true && true); //true
          console.log(false || false); //false
          console.log(null && undefined); //null
          console.log(null || undefined); //undefined
          console.log("abc" && undefined); //undefined
          console.log("abc" || undefined); //abc
          console.log(null || false || 0 || 1 || null); //1
          console.log("abc" && "bcd" && "def"); //def
          

          6.3 運(yùn)算符的優(yōu)先級(jí)

          • 1、() 優(yōu)先級(jí)最高
          • 2、一元運(yùn)算符 ++ -- !
          • 3、算數(shù)運(yùn)算符 先* / % 后 + -
          • 4、關(guān)系運(yùn)算符 > >= < <=
          • 5、相等運(yùn)算符 == != === !==
          • 6、邏輯運(yùn)算符 先&& 后||

          示例代碼:

          // 第一題 true && true
          console.log(((4 >= 6) || ("人" != "狗")) && !(((12 * 2) == 144) && true)); // true
          // 第二題 
          var num = 10;
          // true && true
          if(5 == num / 2 && (2 + 2 * num).toString() === "22") {
           console.log(true); // true
          }else{
           console.log(false);
          }
          

          7. 選擇語(yǔ)句

          7.1 if..else語(yǔ)句

          語(yǔ)法:

          只有一個(gè)判斷條件的時(shí)候 if..else:

          if(判斷條件){ // 當(dāng)判斷條件為true的時(shí)候執(zhí)行代碼1,為false的時(shí)候執(zhí)行代碼2
           代碼1; 
          }else{
           代碼2;
          }
          

          當(dāng)不止一個(gè)判斷條件的時(shí)候 else用else if 代替:

          if(判斷條件1){ // 判斷條件 1 為 true 的時(shí)候執(zhí)行 代碼 1
           代碼1; 
          }else if(判斷條件2){ // 判斷條件 2 為 true 的時(shí)候執(zhí)行 代碼 2
           代碼2; 
          }else{ // 兩個(gè)條件都不滿足的時(shí)候執(zhí)行代碼 3
           代碼3; 
          }
          

          思考1:

          • 如果滿18,告訴他可以看電影
          • 如果滿了16,告訴他可以在家長(zhǎng)的陪同下觀看
          • 如果不夠16,告訴他不準(zhǔn)看
          var age = 20;
          if(age >= 18){
           console.log("沒(méi)時(shí)間解釋了,趕緊上車(chē)吧"); // 打印這條
          }else if(age >= 16){
           console.log("請(qǐng)?jiān)诩议L(zhǎng)的陪同下觀看");
          }else {
           console.log("回家學(xué)習(xí)吧");
          }
          

          思考2:

          • 根據(jù)new Date().getDay()獲取今天是星期幾
          • 由于獲取到的是純數(shù)字,現(xiàn)在需要根據(jù)這個(gè)數(shù)字輸出"今天是周*"的字符串
          var date = new Date(); // 獲取當(dāng)前的時(shí)間
          var week = date.getDay(); // 獲得 0-6 表示周幾 0:星期日
          if(week == 0){
           console.log("今天是星期天");
          }else if(week == 1){
           console.log("今天是星期一");
          }else if(week == 2){
           console.log("今天是星期二");
          }else if(week == 3){
           console.log("今天是星期三");
          }else if(week == 4){
           console.log("今天是星期四");
          }else if(week == 5){
           console.log("今天是星期五");
          }else if(week == 6){
           console.log("今天是星期六");
          }else{
           console.log("你火星的來(lái)的吧");
          }
          

          7.2 switch..case

          語(yǔ)法:

          // switch: 開(kāi)關(guān); case: 案列;
          switch(變量){ // 判斷變量是否全等于case的值1,或者值2,
           case 值1:
           執(zhí)行代碼1; // 全等于的時(shí)候執(zhí)行代碼1
           break; // 然后break;代碼跳出switch語(yǔ)句, 不加break,會(huì)繼續(xù)執(zhí)行下面的代碼
           case 值2:
           執(zhí)行代碼2;
           break;
           default:
           執(zhí)行代碼3; // 當(dāng)都不滿足條件的時(shí)候,會(huì)執(zhí)行默認(rèn)里的執(zhí)行代碼3
          }
          

          思考:素質(zhì)教育(把分?jǐn)?shù)變成ABCDE)

          // 90-100 : A
          // 80-89: B
          // 70-79: C
          // 60-69: D
          // 0-59 : E
          // 這里的等級(jí)是根據(jù)一個(gè)范圍的分?jǐn)?shù)劃定的,用if..else很容易實(shí)現(xiàn),但是switch..case是一個(gè)具體的條件,怎么辦呢?
          // 方法:將分?jǐn)?shù)除以10再用parseInt屬性取整
           
          var score = 85;
          score = parseInt(score/10); // 8
          switch (score) {
          // score = 10 或者 9 的時(shí)候 返回 A
          case 10:
          case 9:
           console.log("A");
           break;
          // score = 8 的時(shí)候 返回 B
          case 8:
           console.log("B");
           break;
          case 7:
           console.log("C");
           break;
          case 6:
           console.log("D");
           break;
          default:
           console.log("E");
          } 
          

          7.3 三元運(yùn)算符

          這個(gè)運(yùn)算符可以用來(lái)代替if..else條件判斷。但是為什么有這個(gè)運(yùn)算符呢?這里的原因是if..else使用兩個(gè)代碼塊,卻只有一個(gè)會(huì)執(zhí)行,在講究的程序員看來(lái)是一種浪費(fèi)。所以使用三元運(yùn)算符,用一條語(yǔ)句就可以完成功能。

          語(yǔ)法:

          判斷語(yǔ)句?表達(dá)式1:表達(dá)式2; 
          根據(jù)判斷語(yǔ)句返回的布爾值,true的話,返回表達(dá)式1,false的話返回表達(dá)式2
          

          舉個(gè)例子,看代碼:

          var sex = 1;
          sex == 1 ? "男":"女"; // 判斷sex是否等于1,如果true,返回第一個(gè)表達(dá)式:"男"
          

          例題:判斷兩個(gè)數(shù)的大小

          // 用if..else語(yǔ)句解決
          // 這里使用了兩個(gè)代碼塊,有點(diǎn)浪費(fèi)
          var num1 = 18;
          var num2 = 39;
          var max;
          if(num1>num2){
           max = num1;
          }else{
           max = num2;
          }
          console.log(max);
          // 用三元運(yùn)算符
          var num3 = 28;
          var num4 = 49;
          var max1 = num3>num4? num3:num4;
          console.log(max1);
          

          注意(容易出錯(cuò)的地方):

          下面這個(gè)語(yǔ)句判斷如果是會(huì)員,費(fèi)用為2美元,非會(huì)員,為10美元?,F(xiàn)在設(shè)置了非會(huì)員,卻打印出了2美元,顯然出錯(cuò)了。
          var isMember = false;
          console.log("當(dāng)前費(fèi)用" + isMember ? "$2.00" : "$10.00"); // "$2.00"
          
          出錯(cuò)的原因是?號(hào)的優(yōu)先級(jí)比+號(hào)低,所以實(shí)際運(yùn)行的語(yǔ)句是
          // true
          console.log("當(dāng)前費(fèi)用false" ? "$2.00" : "$10.00"); // "$2.00"
          

          8.循環(huán)語(yǔ)句

          8.1 while 循環(huán)

          語(yǔ)法:

          • 1、如果循環(huán)條件的結(jié)果是true的時(shí)候,就會(huì)執(zhí)行循環(huán)體
          • 2、如果循環(huán)條件的結(jié)果是false的時(shí)候,結(jié)束循環(huán)。
          // 1. 如果循環(huán)條件的結(jié)果是true的時(shí)候,就會(huì)執(zhí)行循環(huán)體
          // 2. 如果循環(huán)條件的結(jié)果是false的時(shí)候,結(jié)束循環(huán)。
          while(循環(huán)條件){
           循環(huán)的代碼; // 循環(huán)體
           自增或者自減; // 一定不要忘記自增或自減,否則就會(huì)死循環(huán)
          }
          

          例如,求0~100的和:

          var num = 0;
          var sum = 0;
          while(num <= 100){
           sum += num;
           num++;
          }
          console.log(sum); // 5050
          

          8.2 do..while 循環(huán)

          語(yǔ)法:

          • do..while循環(huán)和while循環(huán)非常像,二者經(jīng)??梢韵嗷ヌ娲?/li>
          • 但是do..while的特點(diǎn)是不管條件成不成立,都會(huì)執(zhí)行1次。
          do{
           循環(huán)的代碼; // 循環(huán)體
           自增或者自減; // 一定不要忘記自增或自減,否則就會(huì)死循環(huán)
          }while(循環(huán)條件);
          

          例如,求0~100的和:

          var num = 0;
          var sum = 0;
          do{
           sum += num;
           num++;
          }while(num<=100);
          console.log(sum); // 5050
          

          8.3 for 循環(huán)

          寫(xiě)while循環(huán)的經(jīng)常會(huì)忘記自增,for循環(huán)其實(shí)是while循環(huán)演化過(guò)來(lái)的,語(yǔ)法更加的簡(jiǎn)潔明了,使用非常的廣泛。

          語(yǔ)法:

          • 初始化表達(dá)式
          • 判斷表達(dá)式
          • 自增表達(dá)式
          • 循環(huán)體
          //主要for循環(huán)的表達(dá)式之間用的是;號(hào)分隔的,千萬(wàn)不要寫(xiě)成,號(hào)
          for(初始化表達(dá)式;判斷表達(dá)式;自增表達(dá)式){
           //循環(huán)體
          }
          

          例如:求0~100的和:

          var sum = 0;
          for(var num = 0; num <= 100; num++){
           sum += num;
          }
          console.log(sum); // 5050
          

          8.4 break 和 continue

          break:立即跳出整個(gè)循環(huán),即循環(huán)結(jié)束,開(kāi)始執(zhí)行循環(huán)后面的內(nèi)容(直接跳到大括號(hào))continue:立即跳出當(dāng)前循環(huán),繼續(xù)下一次循環(huán)(跳到i++的地方)

          1、continue 示例代碼:

          for(var i = 1; i <= 10; i++) {
           if(i == 5) {
           continue;
           }
           console.log(i); // 1,2,3,4,6,7,8,9,10
          }
          

          2、break 示例代碼:

          for(var i = 1; i <= 10; i++) {
           if(i == 5) {
           break;
           }
           console.log(i); // 1,2,3,4
          }
          

          8.5 循環(huán)語(yǔ)句練習(xí)

          1、計(jì)算一個(gè)數(shù)的位數(shù)

          當(dāng)不知道循環(huán)次數(shù)的時(shí)候,用while循環(huán):

          var num = 1234567;
          //因?yàn)椴恢姥h(huán)次數(shù),所以推薦使用while循環(huán)
          var count = 0; // count記錄位數(shù)
          while(num != 0){ // 循環(huán)條件
           num = parseInt(num/10);// 讓num縮小10倍
           count++; // ,每縮小10倍就計(jì)算一次位數(shù)了
          }
          console.log(count); // 7
          

          2、翻轉(zhuǎn)一個(gè)數(shù)

          var num = 12345678;
          //因?yàn)椴恢姥h(huán)次數(shù),所以推薦使用while循環(huán)
          var str = ""; 
          while(num != 0){
           str += num%10; // 將每一位取余
           num = parseInt(num/10);//讓num縮小10倍
          }
          // str 是一個(gè)字符串,所以 +str將它轉(zhuǎn)回Number類型
          console.log(+str); //
          

          3、總結(jié):

          • 循環(huán)有很多種,但是以后用得最多的是for循環(huán)
          • 當(dāng)不明確循環(huán)次數(shù)的時(shí)候,可以使用while循環(huán)
          • 當(dāng)無(wú)論如何都要執(zhí)行一次代碼的時(shí)候,可以使用do..while循環(huán)。
          • 循環(huán)可以相互替代。

          9. 數(shù)組

          所謂數(shù)組,就是將多個(gè)元素(通常是同一類型的),按一定順序排列放到一個(gè)集合中,那么這個(gè)集合就稱之為數(shù)組

          在javascript中,數(shù)組是一個(gè)有序的列表,可以在數(shù)組中存放任意的數(shù)據(jù),并且數(shù)組的長(zhǎng)度可以動(dòng)態(tài)的調(diào)整

          9.1 創(chuàng)建數(shù)組

          1、通過(guò)構(gòu)造函數(shù)創(chuàng)建數(shù)組:

          • var arr = new Array(); 創(chuàng)建了一個(gè)空數(shù)組;
          • var arr = new Array('aa','bb','cc'); 創(chuàng)建了一個(gè)數(shù)組,里面存放了三個(gè)字符串
          • var arr = new Array(11,22,33) 創(chuàng)建了一個(gè)數(shù)組,里面存放了三個(gè)數(shù)字

          2、通過(guò)數(shù)組子面量創(chuàng)建數(shù)組:

          • var arr = []; 創(chuàng)建了一個(gè)空數(shù)組
          • var arr = [11,22,33]; 創(chuàng)建了一個(gè)數(shù)組,里面存放了三個(gè)數(shù)字
          • var arr = ['aa','bb','cc']; 創(chuàng)建了一個(gè)數(shù)組,里面存放了三個(gè)字符串

          9.2 數(shù)組的下標(biāo)與長(zhǎng)度

          數(shù)組的下標(biāo):

          數(shù)組是有序的,數(shù)組中的每一個(gè)元素都對(duì)應(yīng)了一個(gè)下標(biāo),下標(biāo)是從0開(kāi)始的
          var arr = ['aa','bb','cc'];
          arr[0]; // 下標(biāo)是0,對(duì)應(yīng)的值是'aa'
          arr[2]; // 下標(biāo)是2,對(duì)應(yīng)的值是'cc'
          

          數(shù)組的長(zhǎng)度:

          跟字符串一樣,數(shù)組也有一個(gè)length的屬性,指數(shù)組中存放的元素的個(gè)數(shù)
          var arr = ['aa','bb','cc'];
          arr.length; // 數(shù)組的長(zhǎng)度為3
          

          空數(shù)組的長(zhǎng)度為0

          數(shù)組的長(zhǎng)度與下標(biāo)的關(guān)系:

          數(shù)組的最大下標(biāo) = 數(shù)組的長(zhǎng)度 - 1

          9.3 數(shù)組的賦值與取值

          數(shù)組的取值:

          • 格式:數(shù)組名[下標(biāo)]
          • 功能:獲取數(shù)組對(duì)應(yīng)下標(biāo)的那個(gè)值,如果下標(biāo)不存在,返回undefined
          var arr = ['red','blue','green'];
          arr[0]; // red
          arr[2]; // green
          arr[3]; // 返回undefined,因?yàn)閿?shù)組最大的下標(biāo)為2
          

          數(shù)組的賦值:

          • 格式:數(shù)組名[下標(biāo)] = 值;
          • 功能:為數(shù)組新增值,如果下標(biāo)有對(duì)應(yīng)的值,會(huì)把原來(lái)的覆蓋,如果下標(biāo)不存在,會(huì)給數(shù)組新增一個(gè)元素
          • 注意:如果一個(gè)數(shù)組的最大長(zhǎng)度是3,可是卻給數(shù)組下標(biāo)為5賦了一個(gè)值,則下標(biāo)為3、4的值為empty(空)
          var arr = ["red", "green", "blue"];
          arr[0] = "yellow"; // 把red替換成了yellow
          arr[3] = "pink"; // 給數(shù)組新增加了一個(gè)pink的值
          arr[5] = "black"; // 數(shù)組輸出為["red", "green", "blue",empty,empty,"black"]
          

          9.4 數(shù)組的遍歷

          遍歷: 對(duì)數(shù)組的每一個(gè)元素都訪問(wèn)一次,叫做遍歷

          數(shù)組遍歷的基本語(yǔ)法:

          var arr = [1,2,3,4,5,6,7,8,9];
          for(var i = 0; i < arr.length; i++){
           console.log(arr[i]); // 1 2 3 4 5 6 7 8 9 
          }
          

          數(shù)組遍歷的逆向遍歷語(yǔ)法:

          // i= arr.length-1 ==> 表示初始化表達(dá)式 從數(shù)組最后一位開(kāi)始遍歷
          // i>=0 表示判斷條件,下標(biāo)要滿足大于等于0
          // i--,表示每次遍歷 初始值都是自減的
          var arr = [1,2,3,4,5,6,7,8,9];
          for(var i = arr.length-1; i >= 0; i--){
           console.log(arr[i]); // 9 8 7 6 5 4 3 2 1
          }
          

          9.5 數(shù)組綜合練習(xí)

          1、求一個(gè)數(shù)組中的最大值、最小值以及對(duì)應(yīng)的下標(biāo)

          var arr = [298, 1, 3, 4, 6, 2, 23, -88,77,44];
          var max = arr[0]; // 隨機(jī)取數(shù)組中的一個(gè)值與其他值比較
          var maxIndex = 0; // 初始化最大值的下標(biāo)
          var min = arr[0];
          var minIndex = 0;
          for(var i = 0; i< arr.length; i++){
           if(max < arr[i]){ // 用一開(kāi)始選擇的值,與遍歷后的值進(jìn)行比較
           max = arr[i]; // 當(dāng)后面的值比初始值大,就將后面的這個(gè)值賦值給初始值,再用這個(gè)全新的值再v 去與后面的比較
           maxIndex = i; // 比較結(jié)束后,此時(shí)的索引就是最大值的索引
           }
           if(min > arr[i]){
           min = arr[i];
           minIndex = i;
           }
          }
          console.log("最大的值是:" + max);
          console.log("最大值的下標(biāo)是:" + maxIndex);
          console.log("最小的值是:" + min);
          console.log("最小值的下標(biāo)是:" + minIndex);
          

          2、讓數(shù)組倒序保存到一個(gè)新的數(shù)組中

          需要了解數(shù)組的一個(gè)方法 push,在數(shù)組的最后面添加

          var arr = ["大喬", "小喬", "甄姬", "不知火舞"];
          var newArr = [];
          for (var i = arr.length - 1; i >= 0; i--) {
           newArr.push(arr[i]);
          }
          console.log(newArr); // ["不知火舞", "甄姬", "小喬", "大喬"]
          

          3、將字符串?dāng)?shù)組用"|"或其他符號(hào)拼成一個(gè)字符串

          var arr = ["aa","bb","cc","dd"];
          var str = "";
          for(var i = 0; i<arr.length; i++){
           if(i == arr.length-1){
           str = str + arr[i]; // 判斷一下,如果是最后一個(gè)的話就不用加“|”
           }else{
           str = str + arr[i]+"|"; // str初始值是一個(gè)空字符串,遍歷的時(shí)候需要加上前一次的結(jié)果
           }
           
          }
          

          4、數(shù)組去重

          • 定義一個(gè)新的數(shù)組,分別遍歷兩個(gè)數(shù)組,判斷兩個(gè)里的每一項(xiàng)是否相等;
          • 如果發(fā)現(xiàn)兩個(gè)相等,說(shuō)明是重復(fù)的;
          • 當(dāng)兩個(gè)不相等的時(shí)候,將這個(gè)去重?cái)?shù)組的當(dāng)前項(xiàng)push到新數(shù)組中;
          var arr = [1, 1, 5, 7, 8, 3, 2, 5, 7, 2, 4, 6, 2, 5, 7, 2, 5];
          //定義一個(gè)新數(shù)組
          var newArr = [];
          //遍歷需要去重的數(shù)組
          for (var i = 0; i < arr.length; i++) {
           //假設(shè)不存在
           var flag = true;
           //需要判斷arr[i]這個(gè)值是否在新數(shù)組中存在
           for(var j = 0; j < newArr.length; j++){
           //進(jìn)行比較即可
           if(arr[i] == newArr[j]){
           //如果發(fā)現(xiàn)了相等的數(shù),說(shuō)明存在
           flag = false;
           }
           }
           if(flag){
           //如果假設(shè)成立,說(shuō)明不存在
           newArr.push(arr[i]);
           }
          }
          console.log(newArr);
          

          10. 冒泡排序

          10.1 冒泡排序的思路

          一個(gè)有8位元素的數(shù)組,讓它的第一位與后面每一位進(jìn)行比較,前面一位小于后面的時(shí)候,位置不變,前面的大于后面的交換位置,就這樣一共要比七趟(最后一趟不要比,就剩一位,就是最小的);

          實(shí)現(xiàn)原理如下圖:

          10.2 按性能等級(jí)冒泡排序分3個(gè)等級(jí)

          1、冒泡排序 60分:

          var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
          var tang = 0;
          var ci = 0;
          for (var i = 0; i < arr.length - 1; i++) { // 外層for循環(huán),循環(huán)的是比較的趟數(shù),因?yàn)橹灰容^8趟 所以i判斷的條件為length-1
           tang++;
           for (var j = 0; j < arr.length - 1; j++) { // 內(nèi)層for循環(huán),循環(huán)的是比較的次數(shù),每趟比較8次
           ci++;
           if (arr[j] > arr[j + 1]) { // 判斷比較的兩個(gè)數(shù),如果前面的大于后面的一位,交換位置
           var temp = arr[j];
           arr[j] = arr[j + 1];
           arr[j + 1] = temp;
           }
           }
          }
          console.log("趟數(shù):" + tang); // 8趟
          console.log("次數(shù):" + ci); // 64次
          console.log(arr);
          }
          
          • 外層for循環(huán),循環(huán)的是比較的趟數(shù),因?yàn)橹灰容^8趟(數(shù)組長(zhǎng)度為9) 所以i判斷的條件為length-1;
          • 內(nèi)層for循環(huán),循環(huán)的是比較的次數(shù),每趟比較8次,其實(shí)這里次數(shù)多比較了,因?yàn)榈谝惶艘呀?jīng)找到一個(gè)最大值了,第二趟就不需要比8次了 應(yīng)該比7次,這里先不管,下面會(huì)進(jìn)行優(yōu)化;
          • 判斷比較的兩個(gè)數(shù),如果前面的大于后面的一位,交換位置。

          測(cè)試代碼:

          <!DOCTYPE html>
          <html lang="en">
          <head>
           <meta charset="UTF-8">
           <title></title>
          </head>
          <body>
           <span id="demo"></span><br/>
           <button id="stb">從小到大</button>
           <button id="bts">從大到小</button>
           <span id="show">
          </span>
           <script>
           var demo = document.getElementById("demo");
           var show = document.getElementById("show");
           var bts = document.getElementById("bts");
           var stb = document.getElementById("stb");
           var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
           demo.innerHTML = arr;
           bts.onclick = function() {
           bubbleSort(function(a, b) {
           return b - a;
           });
           }
           stb.onclick = function() {
           bubbleSort(function(a, b) {
           return a - b;
           });
           }
           function bubbleSort(fn) {
           var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
           var strArr = [];
           show.innerHTML = "";
           strArr.push("<br/>");
           var inner = 0;
           var outer = 0;
           for (var i = 0; i < arr.length - 1; i++) {
           strArr.push("第" + (i + 1) + "趟");
           for (var j = 0; j < arr.length - 1; j++) {
           if (fn(arr[j], arr[j + 1]) > 0) {
           var tmp = arr[j];
           arr[j] = arr[j + 1];
           arr[j + 1] = tmp;
           }
           inner++;
           }
           strArr.push(arr.toString());
           strArr.push("共" + j + "次" + "<br/>");
           outer++;
           }
           strArr.push("外循環(huán)" + outer + "次");
           strArr.push("內(nèi)循環(huán)" + inner + "次");
           show.innerHTML = strArr.join(" ");
           }
           </script>
          </body>
          </html>
          

          每趟都比較8次?明顯是多余了,下面進(jìn)行優(yōu)化

          2、冒泡排序80分:

          var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
          var tang = 0;
          var ci = 0;
          for (var i = 0; i < arr.length - 1; i++) {
           tang++;
           for (var j = 0; j < arr.length - 1 - i; j++) { // 第二趟只比了7次 依次遞減
           ci++;
           if (arr[j] > arr[j + 1]) {
           var temp = arr[j];
           arr[j] = arr[j + 1];
           arr[j + 1] = temp;
           }
           }
          }
          console.log("趟數(shù):" + tang); // 8趟
          console.log("次數(shù):" + ci); // 36次
          console.log(arr);
          

          i 是從下標(biāo)0開(kāi)始的,第一趟的時(shí)候i=0,比了8次,第二趟i=1,只需要比7次,第三趟i=2,只需要比6次...依次類推,所以 比的次數(shù)應(yīng)該就是arr.length - 1 -i;

          測(cè)試代碼:

          <!DOCTYPE html>
          <html lang="en">
          <head>
           <meta charset="UTF-8">
           <title></title>
          </head>
          <body>
           <span id="demo"></span><br/>
           <button id="stb">從小到大</button>
           <button id="bts">從大到小</button>
           <span id="show">
          </span>
           <script>
           var demo = document.getElementById("demo");
           var show = document.getElementById("show");
           var bts = document.getElementById("bts");
           var stb = document.getElementById("stb");
           var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
           demo.innerHTML = arr;
           bts.onclick = function() {
           bubbleSort(function(a, b) {
           return b - a;
           });
           }
           stb.onclick = function() {
           bubbleSort(function(a, b) {
           return a - b;
           });
           }
           function bubbleSort(fn) {
           var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
           var strArr = [];
           show.innerHTML = "";
           strArr.push("<br/>");
           var inner = 0;
           var outer = 0;
           for (var i = 0; i < arr.length - 1; i++) {
           strArr.push("第" + (i + 1) + "趟");
           for (var j = 0; j < arr.length - 1 - i; j++) {
           if (fn(arr[j], arr[j + 1]) > 0) {
           var tmp = arr[j];
           arr[j] = arr[j + 1];
           arr[j + 1] = tmp;
           }
           inner++;
           }
           strArr.push(arr.toString());
           strArr.push("共" + j + "次" + "<br/>");
           outer++;
           }
           strArr.push("外循環(huán)" + outer + "次");
           strArr.push("內(nèi)循環(huán)" + inner + "次");
           show.innerHTML = strArr.join(" ");
           }
           </script>
          </body>
          </html>
          

          還有什么可以優(yōu)化的嗎? 假如8個(gè)數(shù)在第3趟的時(shí)候就排好了,還需要繼續(xù)排嗎?

          3、冒泡排序100分:

          假設(shè)成立法(3步):

          • 假設(shè)成立
          • 想辦法推翻假設(shè)
          • 如果推翻不了,說(shuō)明假設(shè)成立
          var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
          var tang = 0;
          var ci = 0;
          for (var i = 0; i < arr.length - 1; i++) {
           var flag = true; // 假設(shè)每一次進(jìn)來(lái)都排好了
           tang++;
           for (var j = 0; j < arr.length - 1 - i; j++) {
           ci++;
           if (arr[j] > arr[j + 1]) {
           flag = false; // 如果兩位比較還滿足前面的比后面的大的時(shí)候,說(shuō)明假設(shè)不成立
           var temp = arr[j];
           arr[j] = arr[j + 1];
           arr[j + 1] = temp;
           }
           }
           if (flag == true) { // 最后判斷一下,如果假設(shè)推翻不了,就停止運(yùn)行。
           break;
           }
          }
          console.log("趟數(shù):" + tang); // 4 趟
          console.log("次數(shù):" + ci); // 26 次
          console.log(arr);
          

          當(dāng)順序已經(jīng)排好后,就不用再去執(zhí)行趟數(shù)了;

          測(cè)試代碼:

          <!DOCTYPE html>
          <html lang="en">
          <head>
           <meta charset="UTF-8">
           <title></title>
          </head>
          <body>
           <span id="demo"></span><br/>
           <button id="stb">從小到大</button>
           <button id="bts">從大到小</button>
           <span id="show">
          </span>
           <script>
           var demo = document.getElementById("demo");
           var show = document.getElementById("show");
           var bts = document.getElementById("bts");
           var stb = document.getElementById("stb");
           var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
           demo.innerHTML = arr;
           bts.onclick = function() {
           bubbleSort(function(a, b) {
           return b - a;
           });
           }
           stb.onclick = function() {
           bubbleSort(function(a, b) {
           return a - b;
           });
           }
           function bubbleSort(fn) {
           var arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
           var strArr = [];
           show.innerHTML = "";
           strArr.push("<br/>");
           var inner = 0;
           var outer = 0;
           for (var i = 0; i < arr.length - 1; i++) {
           var sorted = true;
           strArr.push("第" + (i + 1) + "趟");
           for (var j = 0; j < arr.length - 1 - i; j++) {
           if (fn(arr[j], arr[j + 1]) > 0) {
           var tmp = arr[j];
           arr[j] = arr[j + 1];
           arr[j + 1] = tmp;
           sorted = false;
           }
           inner++;
           }
           strArr.push(arr.toString());
           strArr.push("共" + j + "次" + "<br/>");
           outer++;
           if (sorted) {
           break;
           }
           }
           strArr.push("外循環(huán)" + outer + "次");
           strArr.push("內(nèi)循環(huán)" + inner + "次");
           show.innerHTML = strArr.join(" ");
           }
           </script>
          </body>
          </html>
          

          第三趟已經(jīng)排好了,為什么還要排第四趟呢? 原因很簡(jiǎn)單,因?yàn)榈谌说臅r(shí)候js是不知道你已經(jīng)排好的,只有第四趟的時(shí)候,js再進(jìn)行換位比較的時(shí)候,發(fā)現(xiàn)位置都不需要換了,說(shuō)明排好了。

          如果覺(jué)得不錯(cuò)可以關(guān)注微信公眾號(hào):編程成長(zhǎng)記

          JavaScript中,函數(shù)調(diào)用和上下文是理解語(yǔ)言核心機(jī)制的關(guān)鍵。本文將深入探討函數(shù)調(diào)用、this關(guān)鍵字以及apply方法的使用。

          首先,讓我們回顧一下函數(shù)調(diào)用的基礎(chǔ)。在JavaScript中,函數(shù)可以通過(guò)多種方式調(diào)用,包括常見(jiàn)的函數(shù)調(diào)用、方法調(diào)用和構(gòu)造函數(shù)調(diào)用。例如,定義了一個(gè)簡(jiǎn)單的函數(shù)foo:

          function foo(a, b, c) {

          console.log("foo功能...");

          console.log(a, b, c);

          return 123;

          }

          接下來(lái),我們使用對(duì)象字面量創(chuàng)建了一個(gè)對(duì)象p1,其中包含了屬性name和age,以及兩個(gè)方法eat和run:

          var p1 = { name: "yuan",

          age: 22,

          eat: function () {

          console.log(this.name + " is eating");

          },

          run: foo, // 這里將函數(shù)foo作為方法賦值給run屬性

          };

          在這個(gè)例子中,p1對(duì)象的run屬性指向了之前定義的foo函數(shù)。然后,我們調(diào)用了eat和run方法:

          p1.eat();

          p1.run(1, 2, 3);

          這時(shí),我們深入研究了函數(shù)內(nèi)部的this關(guān)鍵字。在對(duì)象方法中,this通常指向調(diào)用該方法的對(duì)象。但是,在JavaScript中,我們可以使用apply方法動(dòng)態(tài)設(shè)置函數(shù)執(zhí)行時(shí)的上下文。

          var _foo = foo;

          foo = function () {

          console.log("截?cái)嚅_(kāi)始...");

          _foo.apply(this, arguments);

          console.log("截?cái)嘟Y(jié)束...");

          };

          在這個(gè)例子中,foo函數(shù)被重新定義,使用apply方法在函數(shù)執(zhí)行前后輸出信息。此時(shí),this在_foo.apply(this, arguments)中指向了foo函數(shù)本身。

          最后,我們遇到了一個(gè)關(guān)于eval函數(shù)的問(wèn)題。在JavaScript中,eval允許執(zhí)行傳入的字符串作為JavaScript代碼。然而,eval的使用需要謹(jǐn)慎,因?yàn)樗赡芤鸢踩院托阅芊矫娴膯?wèn)題。

          eval('console.log("hello")');

          var _eval = eval;

          eval = function (src) {

          console.log("eval截?cái)嚅_(kāi)始...");

          _eval(src);

          console.log("eval截?cái)嘟Y(jié)束...");

          };

          eval("console.log('hello....')");

          在這個(gè)例子中,我們重新定義了eval函數(shù),通過(guò)截?cái)嗟姆绞皆诤瘮?shù)執(zhí)行前后輸出信息。

          通過(guò)這一系列例子,我們深入了解了JavaScript中函數(shù)調(diào)用、上下文和一些關(guān)鍵字的使用。函數(shù)是JavaScript中的核心概念之一,理解函數(shù)的調(diào)用方式和上下文有助于更有效地使用這門(mén)語(yǔ)言。


          主站蜘蛛池模板: 国产一区二区三区91| 在线精品国产一区二区| 国产成人av一区二区三区在线| 色噜噜一区二区三区| 无码人妻品一区二区三区精99| 亚洲电影国产一区| 中文字幕人妻AV一区二区| 精品亚洲av无码一区二区柚蜜| 多人伦精品一区二区三区视频| 无码日韩精品一区二区人妻| 亚欧成人中文字幕一区| 中文字幕日韩欧美一区二区三区 | 无码人妻精品一区二区蜜桃百度| 精品成人一区二区三区四区| 亚洲一区二区三区在线网站| 日本一区二区三区中文字幕| 国产精品一区二区不卡| 久久免费国产精品一区二区| 日本一区二区三区在线看| 亚洲视频免费一区| 少妇激情AV一区二区三区| 国产亚洲一区二区三区在线不卡| 日韩精品无码中文字幕一区二区| 久久精品国产一区二区 | 国产一区二区在线| 亚洲美女一区二区三区| 无码日韩精品一区二区免费暖暖 | 精品国产一区二区三区久久狼 | 波多野结衣一区二区三区88| 国产精品一区二区不卡| 免费无码毛片一区二区APP| 亚洲无线码一区二区三区| 国产一区二区不卡在线播放| 成人乱码一区二区三区av| 97精品国产福利一区二区三区| 精品国产一区二区22| 久久精品国产第一区二区| 一区二区三区视频在线| 日本国产一区二区三区在线观看 | 国产亚洲一区二区三区在线观看 | 秋霞日韩一区二区三区在线观看|