JavaScript基礎知識

1. 初識JS

1.1 什麼是JS語言

javascript是一種運行在客戶端 的腳本語言

客戶端: 即接受服務的一端,與服務端相對應,在前端開發中,通常客戶端指的就是瀏覽器。

腳本語言: 也叫解釋型語言,特點是執行一行,解釋一行,如果發現報錯,代碼就停止執行。

1.2 JS的三個組成部分

javascript的三個組成部分:ECMAScript、BOM、DOM

ECMAScript: 定義了javascript的語法規範。

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

DOM: 一套操作頁面元素的API。

1.3>

1、script標籤的書寫方式

書寫Javascript代碼有兩種方式,第一種是直接在script標籤中書寫,第二種是將代碼寫在js文件中,通過script的src屬性進行引入。

直接在script中書寫javascript代碼:

 

通過script標籤引入一個JS文件,需要指定src屬性:



如果script標籤指定了src屬性,說明是想要引入一個js文件,這個時候不能繼續在script標籤中寫js代碼,即便寫了,也不會執行。

2、script標籤的書寫位置

script標籤的書寫位置,原則上來說,可以在頁面中的任意位置書寫。

寫在head標籤中,style標籤之後:





<title>Document/<title>
<link>






瀏覽器有一個特性,就是在遇到標籤時才開始呈現內容。如果在head裡面引用js文件的話,意味著必須要等到全部的javascript代碼都被下載、解析和執行完成之後,才能開始呈現頁面的內容。如果文件數量一旦過多,將會影響頁面加載速度,此時頁面有可能會在加載完成前一片空白。

寫在標籤的前面:





<title>Document/<title>
<link>






在解析javascript代碼之前,頁面的內容已經完全呈現在瀏覽器當中了,用戶會明顯感覺頁面加載變快了。

1.4 js中輸入輸出語句

  • console.log 控制檯輸出日誌
  • console.dir 對象的形式打印一個對象
  • document.write 往頁面中寫入內容
  • alert 彈框警告
  • confirm 確認框
  • prompt 輸入框

1.5 註釋

不被程序執行的代碼。用於程序員標記代碼,在後期的修改,以及他人的學習時有所幫助,在JS中,分為單行註釋和多行註釋以及文檔註釋。

單行註釋

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

多行註釋

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

文檔註釋

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

註釋的作用

  • 模塊劃分,方便代碼查找和維護
  • 用於解釋複雜代碼的邏輯,方便維護和後期開發。

2. 變量

變量,可以變化的量,變量是在計算機中存儲數據的一個標識符。可以把變量看成存儲數據的容器。

變量與字面量:

  • 字面量:10、20、“abc”、true這種從字面上就能看出來類型和值的量叫做字面量。
  • 變量:可以變化的量。
// 1- 同時聲明並且賦值
var num = 100;
console.log(num); // 100
// 2- 先聲明瞭一個變量,再賦值
var num1;
num1 = 100;
console.log(num1); // 100
// 3- 沒有聲明變量,直接賦值(可以,但是不推薦)
num2 = 200;
console.log(num2); // 200
// 4- 有變量聲明,但是沒有賦值(可以,沒有賦值,變量的值默認是個undefined)
var num9;
console.log(num9); // undefined
// 5- 既沒有聲明,也沒有賦值,直接用。
console.log(num3); //報錯 num3
// 6- 一個 var,逗號分隔 可以同時聲明多個變量
var name = "Levi丶",
age = 18,

gender = "男";

2.2 變量的命名規則與規範

命名規則(必須遵守):

  • 由字母、數字、下劃線、$符號組成,開頭不能是數字。
  • 不能使用關鍵字和保留字
  • 區分大小寫

命名規範(建議遵守):

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

2.3 交換兩個變量的值

// 交換 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
// 不使用臨時變量 

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. 數據類型

基本數據類型包括了:number、string、boolean、undefined、null

3.1 如何查看數據類型

使用typeof關鍵字查看數據類型
typeof(name); 
// 括號可以省略
typeof name;

3.2 Number 類型

進制

  • 十進制,我們平時使用的就是十進制,進行運算時,八進制和十六進制的值最終都會轉換成十進制。
  • 二進制,計算機當中用的最多的計算方式,數值序列只有0和1
  • 八進制,0開頭的數值,數值序列:0-7
  • 十六進制,0x開頭的數值,數值序列:0-9、A-F、a-f

浮點數

所謂浮點數,就是該數當中必須包含一個小數點,並且小數點後面至少有一位數字。

科學計數法:

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

浮點數的精度問題:

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

浮點數在運算的時候會出現精度丟失的問題,因此在做比較運算的時候,儘量不要用小數進行比較。在第五章的時候會著重講解這個問題

數值範圍

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

數值判斷

  • NaN: 表示一個非數值,當無法運算或者運算錯誤的時候,會得到一個NaN,NaN是number類型,表示一個非數值。
  • NaN與任何值都不想等,包括它本身
  • isNaN: 用來判斷是否是一個數字,當返回true的時候說明是NaN,表示的不是一個數字,返回false,說明不是NaN,表示的是一個數字。

示例代碼:

var str = "abc";
console.log(isNaN(str)); // true 說明不是一個數字

3.3 String 類型

字面量

字符串的字面量:“abc” 、 ‘abc’ 字符串可以是雙引號,也可以是單引號引起來。

不管是雙引號,還是單引號,都是成對出現的,假如打印的字符串裡有引號怎麼辦呢?

這裡就要活學活用,如果只有一處有引號,就可以用單雙引號混合使用:

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

假如引號非常多的時候怎麼辦呢? 用轉義字符:“\”:

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

字符串拼接

拼接字符串使用+號

示例代碼:

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

總結:

  • 兩邊只要有一個是字符串,那麼+就是字符串拼接功能
  • 兩邊如果都是數字,那麼就是算術功能。

字符串長度

length屬性用來獲取字符串的長度
var str = "abcdefghij";
str.length;// 字符串的長度 10

3.4. boolean 類型

boolean類型只有兩個字面量,true和false,區分大小寫(True,False不是布爾類型,只是標識符)。

所有類型的值都可以轉化成true或者false

NaN、""、undefined、null、alse、0 這6個值可以轉換成false,其餘的都是true。

3.5 undefined類型與null類型

undefined表示一個聲明瞭沒有賦值的變量

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

null表示一個空的對象

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

如果定義的變量,將來是準備用於保存對象的話,最好將變量初始化為null

var name = null;

undefined 與 null 的關係

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

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

4. 簡單數據類型轉換

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

這個在調試過程中時非常有用的。

4.1 轉字符串類型

1、String()函數轉換

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

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

var num = 123;
console.log(num.toString()); // "123"
console.log(undefined.toString()); // 報錯
console.log(null.toString()); // 報錯

3、+ "" 加引號

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

4.2 轉數值類型

1、Number

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

2、parseInt(取整)

  • 小數數字字符串,轉換之後,保留整數部分(取整);
  • 數字開頭非純數字字符串,轉換之後保留整數部分;
  • 非數字字符串,轉換之後為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(取數)

  • 數字字符串,轉換之後保留原數據;
  • 數字開頭的非純數字字符串,轉換之後保留數字部分(包括小數);
  • 非數字字符串轉換之後為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、參與運算==> "+" or "-0"

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

4.3 轉布爾類型

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

1、能夠轉換成false的只有6種:

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

其餘的都是true

2、! 轉換

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

5. JS小數運算精度丟失

5.1 JS數字精度丟失的一些典型問題

js在使用小數進行計算的時候,會出現精度丟失的問題。不要用來跟其他的小數做比較。

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

5.2 JS數字丟失精度的原因

計算機的二進制實現和位數限制有些數無法有限表示。就像一些無理數不能有限表示,如 圓周率 3.1415926...,1.3333... 等。JS 遵循 IEEE 754 規範,採用 雙精度存儲(double precision) ,佔用 64 bit。如圖

JavaScript基礎知識

意義:

  • 1位用來表示符號位
  • 11位用來表示指數
  • 52位表示尾數

浮點數,比如:

0.1 >> 0.0001 1001 1001 1001…(1001無限循環)
0.2 >> 0.0011 0011 0011 0011…(0011無限循環)

此時只能模仿十進制進行四捨五入了,但是二進制只有0和1兩個,於是變為0舍1入。這即是計算機中部分浮點數運算時出現誤差,丟失精度的根本原因。

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

大於 9007199254740992 的可能會丟失精度:

9007199254740992 >> 10000000000000...000 // 共計 53 個 0
9007199254740992 + 1 >> 10000000000000...001 // 中間 52 個 0
9007199254740992 + 2 >> 10000000000000...010 // 中間 51 個 0

實際上:

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

結果如圖:

JavaScript基礎知識

以上,可以知道看似有窮的數字,在計算機的二進制表示裡卻是無窮的,由於存儲位數限制因此存在“捨去”,精度丟失就發生了。

5.3 JS數字丟失精度的解決方案

對於整數,前端出現問題的幾率可能比較低,畢竟很少有業務需要需要用到超大整數,只要運算結果不超過 Math.pow(2, 53) 就不會丟失精度。

對於小數,前端出現問題的幾率還是很多的,尤其在一些電商網站涉及到金額等數據。解決方式:把小數放到位整數(乘倍數),再縮小回原來倍數(除倍數)

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

6. 運算符

6.1 一元運算符

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

舉個例子,看代碼:

var num = 5;
console.log(num++); // 5
console.log(++num); // 7 (因為剛剛num自增了一次,這裡打印的話就等於在6的基礎上前自增了,在計算機科學中,被稱為副效應)
console.log(num--); // 7 (這裡是後自減,所以先返回值,返回7,再運算--,此時的num實際是等於6了)
console.log(--num); // 5

6.2 邏輯運算符

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

示例代碼:

/*細讀上面三句話,就能理解為什麼會是這個打印結果了*/
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 運算符的優先級

  • 1、() 優先級最高
  • 2、一元運算符 ++ -- !
  • 3、算數運算符 先* / % 後 + -
  • 4、關係運算符 > >= < <=
  • 5、相等運算符 == != === !==
  • 6、邏輯運算符 先&& 後||

示例代碼:

// 第一題 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. 選擇語句

7.1 if..else語句

語法:

只有一個判斷條件的時候 if..else:

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

當不止一個判斷條件的時候 else用else if 代替:

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

代碼3;
}

思考1:

  • 如果滿18,告訴他可以看電影
  • 如果滿了16,告訴他可以在家長的陪同下觀看
  • 如果不夠16,告訴他不準看
var age = 20;
if(age >= 18){
console.log("沒時間解釋了,趕緊上車吧"); // 打印這條
}else if(age >= 16){
console.log("請在家長的陪同下觀看");
}else {
console.log("回家學習吧");
}

思考2:

  • 根據new Date().getDay()獲取今天是星期幾
  • 由於獲取到的是純數字,現在需要根據這個數字輸出"今天是周*"的字符串
var date = new Date(); // 獲取當前的時間
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("你火星的來的吧");
}

7.2 switch..case

語法:

// switch: 開關; case: 案列;
switch(變量){ // 判斷變量是否全等於case的值1,或者值2,
case 值1:
執行代碼1; // 全等於的時候執行代碼1
break; // 然後break;代碼跳出switch語句, 不加break,會繼續執行下面的代碼
case 值2:
執行代碼2;
break;
default:
執行代碼3; // 當都不滿足條件的時候,會執行默認裡的執行代碼3
}

思考:素質教育(把分數變成ABCDE)

// 90-100 : A
// 80-89: B
// 70-79: C
// 60-69: D
// 0-59 : E
// 這裡的等級是根據一個範圍的分數劃定的,用if..else很容易實現,但是switch..case是一個具體的條件,怎麼辦呢?
// 方法:將分數除以10再用parseInt屬性取整

var score = 85;
score = parseInt(score/10); // 8
switch (score) {
// score = 10 或者 9 的時候 返回 A
case 10:
case 9:
console.log("A");
break;
// score = 8 的時候 返回 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 三元運算符

這個運算符可以用來代替if..else條件判斷。但是為什麼有這個運算符呢?這裡的原因是if..else使用兩個代碼塊,卻只有一個會執行,在講究的程序員看來是一種浪費。所以使用三元運算符,用一條語句就可以完成功能。

語法:

判斷語句?表達式1:表達式2; 
根據判斷語句返回的布爾值,true的話,返回表達式1,false的話返回表達式2

舉個例子,看代碼:

var sex = 1;
sex == 1 ? "男":"女"; // 判斷sex是否等於1,如果true,返回第一個表達式:"男"

例題:判斷兩個數的大小

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

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

下面這個語句判斷如果是會員,費用為2美元,非會員,為10美元。現在設置了非會員,卻打印出了2美元,顯然出錯了。
var isMember = false;
console.log("當前費用" + isMember ? "$2.00" : "$10.00"); // "$2.00"
出錯的原因是?號的優先級比+號低,所以實際運行的語句是
// true
console.log("當前費用false" ? "$2.00" : "$10.00"); // "$2.00"

8.循環語句

8.1 while 循環

語法:

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

}

例如,求0~100的和:

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

8.2 do..while 循環

語法:

  • do..while循環和while循環非常像,二者經常可以相互替代
  • 但是do..while的特點是不管條件成不成立,都會執行1次。
do{
循環的代碼; // 循環體
自增或者自減; // 一定不要忘記自增或自減,否則就會死循環
}while(循環條件);

例如,求0~100的和:

var num = 0;
var sum = 0;
do{

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

8.3 for 循環

寫while循環的經常會忘記自增,for循環其實是while循環演化過來的,語法更加的簡潔明瞭,使用非常的廣泛。

語法:

  • 初始化表達式
  • 判斷表達式
  • 自增表達式
  • 循環體
//主要for循環的表達式之間用的是;號分隔的,千萬不要寫成,號
for(初始化表達式;判斷表達式;自增表達式){
//循環體
}

例如:求0~100的和:

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

8.4 break 和 continue

break:立即跳出整個循環,即循環結束,開始執行循環後面的內容(直接跳到大括號)continue:立即跳出當前循環,繼續下一次循環(跳到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 循環語句練習

1、計算一個數的位數

當不知道循環次數的時候,用while循環:

var num = 1234567;
//因為不知道循環次數,所以推薦使用while循環
var count = 0; // count記錄位數
while(num != 0){ // 循環條件

num = parseInt(num/10);// 讓num縮小10倍
count++; // ,每縮小10倍就計算一次位數了
}
console.log(count); // 7

2、翻轉一個數

var num = 12345678;
//因為不知道循環次數,所以推薦使用while循環
var str = "";
while(num != 0){
str += num%10; // 將每一位取餘
num = parseInt(num/10);//讓num縮小10倍
}
// str 是一個字符串,所以 +str將它轉回Number類型
console.log(+str); //

3、總結:

  • 循環有很多種,但是以後用得最多的是for循環
  • 當不明確循環次數的時候,可以使用while循環
  • 當無論如何都要執行一次代碼的時候,可以使用do..while循環。
  • 循環可以相互替代。

9. 數組

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

在javascript中,數組是一個有序的列表,可以在數組中存放任意的數據,並且數組的長度可以動態的調整

9.1 創建數組

1、通過構造函數創建數組:

  • var arr = new Array(); 創建了一個空數組;
  • var arr = new Array('aa','bb','cc'); 創建了一個數組,裡面存放了三個字符串
  • var arr = new Array(11,22,33) 創建了一個數組,裡面存放了三個數字

2、通過數組子面量創建數組:

  • var arr = []; 創建了一個空數組
  • var arr = [11,22,33]; 創建了一個數組,裡面存放了三個數字
  • var arr = ['aa','bb','cc']; 創建了一個數組,裡面存放了三個字符串

9.2 數組的下標與長度

數組的下標:

數組是有序的,數組中的每一個元素都對應了一個下標,下標是從0開始的
var arr = ['aa','bb','cc'];
arr[0]; // 下標是0,對應的值是'aa'
arr[2]; // 下標是2,對應的值是'cc'

數組的長度:

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

空數組的長度為0

數組的長度與下標的關係:

數組的最大下標 = 數組的長度 - 1

9.3 數組的賦值與取值

數組的取值:

  • 格式:數組名[下標]
  • 功能:獲取數組對應下標的那個值,如果下標不存在,返回undefined
var arr = ['red','blue','green'];
arr[0]; // red
arr[2]; // green
arr[3]; // 返回undefined,因為數組最大的下標為2

數組的賦值:

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

9.4 數組的遍歷

遍歷: 對數組的每一個元素都訪問一次,叫做遍歷

數組遍歷的基本語法:

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
}

數組遍歷的逆向遍歷語法:

// i= arr.length-1 ==> 表示初始化表達式 從數組最後一位開始遍歷
// i>=0 表示判斷條件,下標要滿足大於等於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 數組綜合練習

1、求一個數組中的最大值、最小值以及對應的下標

var arr = [298, 1, 3, 4, 6, 2, 23, -88,77,44];
var max = arr[0]; // 隨機取數組中的一個值與其他值比較
var maxIndex = 0; // 初始化最大值的下標
var min = arr[0];
var minIndex = 0;
for(var i = 0; i< arr.length; i++){
if(max < arr[i]){ // 用一開始選擇的值,與遍歷後的值進行比較

max = arr[i]; // 當後面的值比初始值大,就將後面的這個值賦值給初始值,再用這個全新的值再v 去與後面的比較
maxIndex = i; // 比較結束後,此時的索引就是最大值的索引
}
if(min > arr[i]){
min = arr[i];
minIndex = i;
}
}
console.log("最大的值是:" + max);
console.log("最大值的下標是:" + maxIndex);
console.log("最小的值是:" + min);
console.log("最小值的下標是:" + minIndex);

2、讓數組倒序保存到一個新的數組中

需要了解數組的一個方法 push,在數組的最後面添加

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

3、將字符串數組用"|"或其他符號拼成一個字符串

var arr = ["aa","bb","cc","dd"];
var str = "";

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

}
/<arr.length>

4、數組去重

  • 定義一個新的數組,分別遍歷兩個數組,判斷兩個裡的每一項是否相等;
  • 如果發現兩個相等,說明是重複的;
  • 當兩個不相等的時候,將這個去重數組的當前項push到新數組中;
var arr = [1, 1, 5, 7, 8, 3, 2, 5, 7, 2, 4, 6, 2, 5, 7, 2, 5];
//定義一個新數組
var newArr = [];
//遍歷需要去重的數組
for (var i = 0; i < arr.length; i++) {
//假設不存在
var flag = true;
//需要判斷arr[i]這個值是否在新數組中存在
for(var j = 0; j < newArr.length; j++){
//進行比較即可
if(arr[i] == newArr[j]){
//如果發現了相等的數,說明存在

flag = false;
}
}
if(flag){
//如果假設成立,說明不存在
newArr.push(arr[i]);
}
}
console.log(newArr);

10. 冒泡排序

10.1 冒泡排序的思路

一個有8位元素的數組,讓它的第一位與後面每一位進行比較,前面一位小於後面的時候,位置不變,前面的大於後面的交換位置,就這樣一共要比七趟(最後一趟不要比,就剩一位,就是最小的);

實現原理如下圖:

JavaScript基礎知識

10.2 按性能等級冒泡排序分3個等級

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循環,循環的是比較的趟數,因為只要比較8趟 所以i判斷的條件為length-1
tang++;
for (var j = 0; j < arr.length - 1; j++) { // 內層for循環,循環的是比較的次數,每趟比較8次
ci++;
if (arr[j] > arr[j + 1]) { // 判斷比較的兩個數,如果前面的大於後面的一位,交換位置
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
console.log("趟數:" + tang); // 8趟
console.log("次數:" + ci); // 64次
console.log(arr);
}
  • 外層for循環,循環的是比較的趟數,因為只要比較8趟(數組長度為9) 所以i判斷的條件為length-1;
  • 內層for循環,循環的是比較的次數,每趟比較8次,其實這裡次數多比較了,因為第一趟已經找到一個最大值了,第二趟就不需要比8次了 應該比7次,這裡先不管,下面會進行優化;
  • 判斷比較的兩個數,如果前面的大於後面的一位,交換位置。

測試代碼:





<title>




<button>從小到大/<button>
<button>從大到小/<button>





JavaScript基礎知識

每趟都比較8次?明顯是多餘了,下面進行優化

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("趟數:" + tang); // 8趟
console.log("次數:" + ci); // 36次
console.log(arr);

i 是從下標0開始的,第一趟的時候i=0,比了8次,第二趟i=1,只需要比7次,第三趟i=2,只需要比6次...依次類推,所以 比的次數應該就是arr.length - 1 -i;

測試代碼:





<title>




<button>從小到大/<button>
<button>從大到小/<button>





JavaScript基礎知識

還有什麼可以優化的嗎? 假如8個數在第3趟的時候就排好了,還需要繼續排嗎?

3、冒泡排序100分:

假設成立法(3步):

  • 假設成立
  • 想辦法推翻假設
  • 如果推翻不了,說明假設成立
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; // 假設每一次進來都排好了
tang++;
for (var j = 0; j < arr.length - 1 - i; j++) {
ci++;
if (arr[j] > arr[j + 1]) {
flag = false; // 如果兩位比較還滿足前面的比後面的大的時候,說明假設不成立
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
if (flag == true) { // 最後判斷一下,如果假設推翻不了,就停止運行。
break;
}
}
console.log("趟數:" + tang); // 4 趟
console.log("次數:" + ci); // 26 次
console.log(arr);

當順序已經排好後,就不用再去執行趟數了;

測試代碼:





<title>




<button>從小到大/<button>
<button>從大到小/<button>





JavaScript基礎知識

第三趟已經排好了,為什麼還要排第四趟呢? 原因很簡單,因為第三趟的時候js是不知道你已經排好的,只有第四趟的時候,js再進行換位比較的時候,發現位置都不需要換了,說明排好了。

如果覺得不錯可以關注微信公眾號:編程成長記


分享到:


相關文章: