javascrip

 

# javascript基礎

## 1、javascript的介紹

### (一)javascript的誕生

>1994 年,網景公司(NetScape)發佈了Navigator瀏覽器0.9版, 這是歷史上第一個比較成熟的瀏覽器,引發了普遍關注。可是,這個版本的瀏覽器只能用來瀏覽,不具有與訪問者互動的能力。。。。網景公司急須要一門網頁腳本語言,使得瀏覽器能夠與網頁進行互動。

1995年4月,網景公司錄用了34歲的系統程序員Brendan Eich, 他只用10天時間就把Javascript設計出來。布蘭登·艾奇


### (二)javascript的特色

+ javascript是一個輕量級的語言
+ javascript是能夠插入HTML頁面的編程代碼
+ javascript支持目前全部的瀏覽器
+ 解釋執行不須要編譯
+ 基於對象,內置大量的現成對象,編寫少許的程序就能夠完成目標

### (三)javascript的組成

+ ECMAScript javascript的語法標準
+ DOM(Document Object Model)文檔對象模型: javascript 操做網頁元素的API
+ BOM(Browser Object Model) javascript 操做瀏覽器部分功能的API

### (四)javascript 和 Html css 的關係

+ Html 用來編寫網頁的結構
+ css 美化網頁添加樣式
+ javacript 實現網頁和客戶之間的溝通,讓網頁有活力

## 2、javascript的書寫位置

### 一、在html標籤中使用 **行內式**

```
    <button onclick="alert('wsfsf ')">按鈕</button>
```

### 二、在HTML內部使用

`<script>腳本內容</script>`標籤,能夠放在任意的地方 **頁內式**

   + head標籤中使用

    ```
        <script>
        window.onload = function () {
          alert('wwwww')
        }
        </script>
    ```

   + body標籤中使用

### 三、外部調用

javascript在script標籤的src屬性中設置 `<script src="腳本的路徑"></script>`在外部的腳本中不能包括script標籤。 **外鏈式**

### 四、**js代碼書寫須要注意的問題:**

```
1. 在一對script標籤中,出現錯誤,那麼這對script標籤中的後面的代碼則不會再往下執行;
2. 若是有一對的script標籤中出現錯誤,不會影響其餘script標籤對的執行;
3. script中能夠寫什麼內容:type="text/javascript"是標準的寫法,也能夠寫language="javascript",可是在目前的html中,type和language則能夠省略,由於html是遵循h5的標準。
4. 有時兼容性的問題,type和language會同時出現;
5. script能夠在頁面中出現多對;
6. 若是script是引入外部的js文件,則標籤內不能再寫js代碼,要寫則須要從新寫一行script包裹;
```

## 3、javascript顯示數據的方式

### 一、使用 window.alert() 彈出警告框

```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>text</title>
</head>
<body>
    <h1>個人第一個頁面</h1>
    <p>個人第一個段落</p>
    <script type="text/javascript">
        window.alert("個人第一個彈窗");
    </script>
</body>
</html>
```

### 二、使用document.write() 方法將內容寫到html文檔中

```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>text</title>
</head>
<body>
    <h1>第一個頁面</h1>
    <p>第一個段落</p>
    <script type="text/javascript">
        document.write(Date());
    </script>-
</body>
```


```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>text</title>
</head>
<body>
    <button onclick="myfunction()">來點我呀,com on</button>
    <script type="text/javascript">
        function myfunction(){
            document.write(Date())
        }
    </script>
</body>
</html>
```

### 三、使用innerHTML寫入到HTML元素。

```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>text</title>
</head>
<body>;
    <h1>個人第一個頁面</h1>
    <p id="demo">個人第一個段落</p>
    <script type="text/javascript">
        document.getElementById("demo").innerHTML = "段落被修改了";
    </script>
</body>
</html>
```

### 四、使用console.log()寫入到瀏覽器的控制檯。

F12 啓用調試模式, 在調試窗口中點擊 "Console" 菜單。`console.warn("警告輸出")`,`console.error('這是一個錯誤')`

```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
    <script type="text/javascript">
        var a = 5;
        var b = 6;
        var c = a + b;
        console.log(c);
    </script>
</body>
</html>
```

### 五、用戶輸入 prompt()語句

prompt()語句就是專門用來彈出可以讓用戶輸入的對話框。用一個變量來接收值,且不論用戶輸入的是什麼都是一個字符串。
```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
    <script type="text/javascript">
        var a = prompt('今天的天氣如何');
        console.log(a);
    </script>
</body>
</html>
```

### 六、confirm 

在網頁中彈出提示框,顯示信息,通常和if 判斷來配合使用,相比alert多了一個取消的按鈕。

```
<script>
       comfirm("Hello,JavaScript!"); 
</script>
```

### 七、javascript顯示方式的說明和對比

#### (1) console.log()和alert相比

```
console.log()的用處主要是方便你調式javascript用的, 你能夠看到你在頁面中輸出的內容。
相比alert他的優勢是:他能看到結構化的東西,若是是alert,彈出一個對象就是[object object],可是console能看到對象的內容。console不會打斷你頁面的操做,若是用alert彈出來內容,那麼頁面就死了,可是console輸出內容後你頁面還能夠正常操做。
```

#### (2) document.write 和 innerHTML

```
一、document.write是直接寫入到頁面的內容流,若是在寫以前沒有調用document.open, 瀏覽器會自動調用open。每次寫完關閉以後從新調用該函數,會致使頁面被重寫。
二、innerHTML則是DOM頁面元素的一個屬性,表明該元素的html內容。你能夠精確到某一個具體的元素來進行更改。若是想修改document的內容,則須要修改document.documentElement.innerElement。
三、innerHTML不少狀況下都優於document.write,其緣由在於其容許更精確的控制要刷新頁面的那一個部分。
```

#### (3) alert和prompt的區別

```
alert("我很帥"); 直接使用不須要變量
var a = prompt(「請輸入一個數字」) 須要用一個變量來接收用戶的輸入,且這個值必定是一個字符串
```

## 4、javascript的語法

### **js 基本的代碼規範:**

+ javascript對換行、縮進、空格不敏感。
+ 每條語句的末尾都要加上分號,除了if、for、function語句結尾處不加分號,若是不加分號,壓縮以後將不能運行。
+ 全部的符號都是英文的。
+ js中的字符串能夠使用單引號,也能夠使用雙引號,通常使用雙引號;
+ 區分大小寫
+ 變量是弱類型的,定義變量時要用var運算符聲明變量,能夠將它初始化爲任意值。所以,能夠隨時改變變量所存數據的類型(儘可能避免這樣作)。
+ javascript的註釋
    + 單行 // 單行註釋能夠嵌套單行、多行註釋
```
// 單行註釋
var name;
```

    + 多行 /* 內容 */ 多行註釋能夠嵌套單行註釋,可是 **不能嵌套多行註釋**

```
/*多行註釋*/
var name;
```
+ 括號表示代碼塊,代碼塊表示一系列應該按順序執行的語句,這些語句被封裝在左括號({)和右括號(})之間。

## 5、javascript的字面量

「直接量」即常量,就是一些不可改變的值,也稱爲「字面量」,看見什麼就是什麼。
字面量的種類

+ 數字(number)字面量,能夠是整數或者是小數,或者是科學計數(e)。

```    
3.14
1001
123e5  #12300000
123e-5 #0.00123```

+ 字符串(String)字面量 能夠使用單引號或雙引號

```
"John Doe"
'John Doe'
```

+ 表達式字面量 用於計算

```
5 + 6
5 * 10
```

+ 數組(Array)字面量 定義一個數組

```
[40, 100, 1, 5, 25, 10]
```

+ 對象(Object)字面量 定義一個對象

```
{firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"}
```

+ 函數(Function)字面量 定義一個函數

```
function myFunction(a, b) { return a * b;}
```

## 6、變量

變量表示一些能夠變化的數據,當一個數據的值常常變化或是不肯定時,就應該用變量來表示。
變量的做用:用來操做數據的(能夠讀取,能夠存儲)

### (一)聲明變量

+ 變量使用前必須用var運算符進行聲明,且不須要聲明變量的類型。

```
var test = "hi";
var test1 = 1;
```

+ 能夠用一個var聲明多個變量,變量之間用逗號分隔。

```
var test1 = 1, test2 = "string";
```

+ 能夠用同一個 var 語句聲明的變量沒必要具備相同的類型。

```       
var test = "hi", age = 25;
```

+ var聲明的變量並不必定要初始化一個值。

```
var test; // 這樣也是有效的
```

+ 變量能夠存放不一樣類型的值。這是弱類型變量的優點,如能夠把變量初始化爲字符串類型的值,以後把它設置爲數字值。

```
var test = "hi";
alert(test);
test = 55;
alert(test);
```

+ 變量聲明不是必須的。

```
var sTest = "hello ";
sTest2 = sTest + "world";
alert(sTest2);
```

首先,sTest 被聲明爲字符串類型的值 "hello"。接下來的一行,用變量 sTest2 把 sTest 與字符串 "world" 連在一塊兒。變量 sTest2並無用var運算符定義,這裏只是插入了它,就像已經聲明過它同樣。
ECMAScript的解釋程序遇到未聲明過的標識符時,用該變量名建立一個**全局變量**,並將其初始化爲指定的值。這是該語言的便利之處,不過若是不能緊密跟蹤變量,這樣作也很危險。最好的習慣是像使用其餘程序設計語言同樣,老是聲明全部變量。

### (二)變量的命名規範

變量名須要遵照兩條簡單的規則:

+ 第一個字符必須是字母、下劃線(_)或美圓符號($),不能以數字開頭。
+ 餘下的字符能夠是下劃線、美圓符號或任何字母或數字字符;
+ 變量名通常都是小寫;

下面的變量都是合法的:
```
var test;
var $test;
var $1;
var _$te$t2;
```

+ 保留字不能用做變量名
```
abstract、boolean、byte、char、class、const、debugger、double、enum、export、extends、final、float、goto
implements、import、int、interface、long、native、package、private、protected、public、short、static、super、synchronized、throws、transient、volatile
```

+ 幾種常見的命名方式:

   一、Camel 標記法:首字母是小寫的,接下來的字母都以大寫字符開頭。例如:

```           
var myTestValue = 0, mySecondValue = "hi";
```

   二、Pascal 標記法 首字母是大寫的,接下來的字母都以大寫字符開頭。例如:

```
var MyTestValue = 0, MySecondValue = "hi";
```

   三、匈牙利類型標記法:

   在以Pascal標記法命名的變量前附加一個小寫字母(或小寫字母序列),說明該變量的類型。例如,i 表示整數,s 表示字符串,以下所示「

```

var iMyTestValue = 0, sMySecondValue = "hi";
```

### (三)變量值交換

#### 一、第一種方法:利用臨時變量進行交換

```
<script type="text/javascript">
  var num1 = 10;
  var num2 = 20;
  var temp = num1;
  num1 = num2;
  num2 = temp;
  console.log(num1, num2); // 20 10
</script>
```

#### 二、第二種方法: 通常用於數字交換

```
<script type="text/javascript">
  var num1 = 10;
  var num2 = 20;
  num1 = num1 + num2;
  num2 = num1 - num2;
  num1 = num1 - num2;
  console.log(num1, num2); // 20 10
</script>
```

#### 三、第三種方法: 位運算交換
```
<script type="text/javascript">
    var num1 = 10;
    var num2 = 20;
    num1 = num1 ^ num2;
    num2 = num1 ^ num2;
    num1 = num1 ^ num2;
    console.log(num1, num2); // 20 10
</script>
```

### (四)變量值的分類

在 ECMAScript 中,變量能夠存在兩種類型的值,即原始值和引用值。又能夠稱爲基本數據類型(簡單類型和值類型)和複雜類型,    
原始數據類型有:number string null undefined boolean object
原始值(基本數據類型):number string null undefined boolean
引用值(複雜數據類型):object


**原始值(基本數據類型)**
存儲在棧(stack)中的簡單數據段,也就是說,它們的值直接存儲在變量訪問的位置。

**引用值(複雜數據類型)**
存儲在堆(heap)中的對象,也就是說,存儲在變量處的值是一個指針(point),指向存儲對象的內存處。

爲變量賦值時,ECMAScript 的解釋程序必須判斷該值是原始類型,仍是引用類型。要實現這一點,解釋程序則需嘗試判斷該值是否爲 ECMAScript 的原始類型之一,即 Undefined、Null、Boolean、Number 和 String 型。因爲這些原始類型佔據的空間是固定的,因此可將他們存儲在較小的內存區域 - 棧中。這樣存儲便於迅速查尋變量的值。

在許多語言中,字符串都被看做引用類型,而非原始類型,由於字符串的長度是可變的。ECMAScript 打破了這一傳統。

若是一個值是引用類型的,那麼它的存儲空間將從堆中分配。因爲引用值的大小會改變,因此不能把它放在棧中,不然會下降變量查尋的速度。相反,放在變量的棧空間中的值是該對象存儲在堆中的地址。地址的大小是固定的,因此把它存儲在棧中對變量性能無任何負面影響。以下圖所示:

![棧堆](media/6.png)


#### 原始類型(基本數據類型)

ECMAScript 有 5 種原始類型(primitive type),即 Undefined、Null、Boolean、Number 和 String。

#### typeof運算符查看變量值的類型

 typeof 運算符有一個參數,即要檢查的變量或值。例如:
```       
    var sTemp = "test string";
    alert (typeof sTemp);    //輸出 "string"
```
---
```
<script type="text/javascript">
    var a = 1;
    var b = '我是誰';
    var c = 1.3242424;
    var d = 3e7;
    var e;
    var f = "";
    console.log(typeof a, typeof b, typeof c, typeof d);
    console.log(typeof e);
    console.log(typeof f);
    console.log(typeof bb);
</script>
```
輸出結果:

![輸出結果](media/1.png)

**對變量或值調用 typeof 運算符將返回下列值之一:**

+ undefined - 若是變量是 Undefined 類型的
+ boolean - 若是變量是 Boolean 類型的
+ number - 若是變量是 Number 類型的
+ string - 若是變量是 String 類型的
+ object - 若是變量是一種引用類型或 Null 類型的
+ function-函數

**typeof 運算符對於 null 值會返回 "Object"。這其實是 JavaScript 最初實現中的一個錯誤,而後被 ECMAScript 沿用了。如今,null 被認爲是對象的佔位符,從而解釋了這一矛盾,但從技術上來講,它仍然是原始值。**

#### 各個原始類型(基本數據類型)詳細介紹

##### 一、Undefined 類型

    Undefined 類型只有一個值,即 undefined。當聲明的變量未初始化時,該變量的默認值是 undefined。
```
    var oTemp;
```

**值 undefined 並不一樣於未定義的值。可是,typeof 運算符並不真正區分這兩種值。**

```
    console.log(typeof e); //e 被定義了,可是沒有給值進行初始化。也是輸出undefined
    console.log(typeof bb); //bb沒有被定義過 也是輸出undefined
```

若是對bb使用除typeof以外的其餘運算符的話,會引發錯誤,由於其餘運算符只能用於已聲明的變量上。
    
**當函數無明確返回值時,返回的也是值 "undefined"**

```
    function testFunc() {
    }
    alert(testFunc() == undefined);  //輸出 "true"
```

**調用函數時,應該提供的參數沒有提供,該參數等於 undefined**

```javascript
function f(x) {
  return x;
}
f() // undefined
```



**對象沒有賦值的屬性**

```javascript
// 對象沒有賦值的屬性
var  o = new Object();
o.p // undefined
```



##### 二、Null 類型

它只有一個專用值 null,即它的字面量。值 undefined 其實是從值 null 派生來的,所以 ECMAScript 把它們定義爲相等的。
```
    alert(null == undefined);  //輸出 "true"
```
儘管這兩個值相等,但它們的含義不一樣。undefined 是聲明瞭變量但未對其初始化時賦予該變量的值,null則用於表示還沒有存在的對象。若是函數或方法要返回的是對象,那麼找不到該對象時,返回的一般是 null。想讓一個變量的值是Null時,必須手動指定 `var a = Null;`

##### 三、Boolean 類型

它有兩個值 true 和 false (即兩個 Boolean 字面量)。即便 false 不等於 0,0 也能夠在必要時被轉換成 false,這樣在 Boolean 語句中使用二者都是安全的

> 任何的非0數值都是true,包括正負無窮,只有0和NaN是false
> 任何的非空字符串都是true,只有空字符串是false
> 任何的對象都是true,除了Null和 undefined是false,空數組[],和空對象{}是true

##### 四、Number 類型

ECMA-262 中定義的最特殊的類型是 Number 類型。這種類型既能夠表示 32 位的整數,還能夠表示 64位的浮點數。直接輸入的(而不是從另外一個變量訪問的)任何數字都被看作 Number 類型的字面量。

* javascript 可正常計算的範圍:小數點前16位,後16位。

+ 八進制數和十六進制數

js 能夠表示不一樣進制的數字,得看瀏覽器的支持

整數也能夠被表示爲八進制(以8爲底)或十六進制(以16爲底)的字面量。八進制字面量的首數字必須是 0,其後的數字能夠是任何八進制數字(0-7),
```        
    var iNum = 070;  //070 等於十進制的 56
```
要建立十六進制的字面量,首位數字必須爲 0,後面接字母 x,而後是任意的十六進制數字(0 到 9 和 A 到 F)。這些字母能夠是大寫的,也能夠是小寫的。
```
    var iNum = 0x1f;  //0x1f 等於十進制的 31
    var iNum = 0xAB;  //0xAB 等於十進制的 171
```
儘管全部整數均可以表示爲八進制或十六進制的字面量,但全部數學運算返回的都是十進制結果。

+ 浮點數

要定義浮點值,必須包括小數點和小數點後的一位數字(例如,用 1.0 而不是 1)。這被看做浮點數字面量。
```
var fNum = 5.0;
```
對於浮點字面量的有趣之處在於,用它進行計算前,真正存儲的是字符串

+ 科學計數法

對於很是大或很是小的數,能夠用科學計數法表示浮點數,能夠把一個數表示爲數字(包括十進制數字)加 e(或 E),後面加乘以 10 的倍數。
```
var fNum = 5.618e7
```
該符號表示的是數 56180000。把科學計數法轉化成計算式就能夠獲得該值:5.618 x 107。

+ 特殊的 Number 值

前兩個是 Number.MAX_VALUE 和 Number.MIN_VALUE,它們定義了 Number 值集合的外邊界。全部ECMAScript數都必須在這兩個值之間。不過計算生成的數值結果能夠不落在這兩個值之間。
最後一個特殊值是 NaN,表示非數(NotaNumber)。NaN是個奇怪的特殊值。通常說來,這                                                                         種狀況發生在類型(String、Boolean 等)轉換失敗時。例如,要把單詞 blue 轉換成數值就會失敗,由於沒有與之等價的數值。與無窮大同樣,NaN也不能用於算術計算, 是一個非法的數字,當對數值進行計算,沒有結果返回,則返回NaN,NaN 的另外一個奇特之處在於,它與自身不相等,這意味着NaN也不等於NaN。

* NaN 屬性是表明非數字值的特殊值。

含義:表示非數字, 主要用在將字符串解析成數字出錯的場合。

```javascript
5 - 'x' // NaN
```

一些數學函數的運算結果也會出現NAN

```javascript
Math.acos(2) // NaN
Math.log(-1) // NaN
Math.sqrt(-1) // NaN
```

0除0也會是NaN 1/0是Infinity

運算規則:

NaN不等於任何值,包括它自己`NaN === NaN // false`

Nan在布爾運算時被看成是false `Boolean(NaN) // false`

NaN與任何數(包括它本身)的運算,獲得的都是NaN

```javascript
NaN + 32 // NaN
NaN - 32 // NaN
NaN * 32 // NaN
NaN / 32 // NaN
```



###### **小結:**

(1)不管是小數仍是整數都是數字類型

(2)不要用小數去驗證小數

```
var x=0.1;
var y=0.2;
var sum=x+y;
console.log(sum==0.3); // false
```

(3)不要用NaN判斷是否是Nan,而是用isNan(值或者是變量句)

```
判斷結果不是一個數字能夠使用isNaN(變量名)
var sum=num+10;//NaN
console.log(sum);
console.log(isNaN(sum));//不是數字爲true,是數字結果爲false
```

(4)想表示十進制就是正常的數字

(5)想表示八進制以0開頭

(6)想表示十六進制以0x開頭

(7)像010這樣的字符串,有些瀏覽器會當成是8進制,有些則會當成是10進制,爲了保證準確性,在進行轉換時,parseInt()時,用第二個參數明確具體的進制數。

##### 五、String 類型

String 類型的獨特之處在於,它是惟一沒有固定大小的原始類型。能夠用字符串存儲 0 或更多的 Unicode 字符,
字符串字面量是由雙引號(")或單引號(')聲明的。而Java則是用雙引號聲明字符串,用單引號聲明字符。可是因爲 ECMAScript 沒有字符類型,因此可以使用這兩種表示法中的任何一種。
```
var sColor1 = "red";
var sColor2 = 'red';
```

**只要有一個是字符串,其餘的是數字,那麼結果也是拼接,不是相加**

```
console.log("我" + "愛" + "你");   //連字符,把三個獨立的漢字,鏈接在一塊兒了
console.log("我+愛+你");           //原樣輸出
console.log(1+2+3);             //輸出6
```

**字符串 - 或 * 數值 = 數值 若是有一個是字符串,另外一個不是字符串,使用 - 或 * 號,此時會發生計算**

```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
    <script type="text/javascript">
        var a = "54";
        var b = 99;
        // 瀏覽器會自動把字符串類型的數字轉換爲數字類型,這叫隱式轉換。
        var c = b - a;
        console.log(typeof c, c);
    </script>
</body>
</html>
```

輸出結果:

![輸出結果](media/2.png)

若是把a改成字母 var a = 'e'; 則輸出結果爲:

![輸出結果](media/3.png)

若是把-換成*乘號,var c = b * a; 則輸出結果爲:

![輸出結果](media/4.png)

#### 類型轉換

##### 一、 轉換成字符串

+ toString()方法

```
<script type="text/javascript">
// 數字轉字符串
  var num1 = 123;
  var str1 = num1.toString();
  console.log(str1, typeof str1) //123 string
  // Boolean 轉字符串
  var bool = true;
  var str2 = bool.toString();
  console.log(str2, typeof str2); // true string
</script>
```

**須要注意的地方:**

> null 和 undefined 沒有toString()的方法,強行調用會報錯
> toString 不會改變原變量的值,它只會將轉化的結果返回

+ String() 函數

有時候有些值沒有toString()的方法,好比null和undefined

> 若是Number 和 Boolean 用String函數進行字符串的轉換,其實是調用了toString的方法
> 對於null和undefined來講,沒有toString的方法,會在內部產生一個新的字符串

```
<script type="text/javascript">
  // 數字轉字符串
  var num1 = 123;
  var str1 = String(num1);
  console.log(str1, typeof str1); // 123 string
  // Boolean 轉字符串
  var bool = true;
  var str2 = String(bool);
  console.log(str2, typeof str2); // true string
  // null轉字符串
  var nu = null;
  var str3 = String(nu);
  console.log(str3, typeof str3); // null string
  var unde = undefined;
  var str4 = String(unde);
  console.log(str4, typeof str4) // undefined string
</script>
```

+ 任何數據和+鏈接在一塊兒都會轉爲字符串,其內部的原理和String同樣

```
<script>
  var num1 = 123;
  var str1 = num1 + '';
  console.log(str1, typeof str1); // 123 string
  var bool = true;
  var str2 = bool + '';
  console.log(str2, typeof str2); // true string
  var nul = null;
  var str3 = nul + '';
  console.log(str3, typeof str3); // null string
  var unde = undefined;
  var str4 = unde + '';
  console.log(str4, typeof str4); // undefined string
</script>
```

##### 二、轉換成數字

 parseInt()  parseFloat() 和 Number()。

+ 注意的地方
    + parseInt()把值轉換成整數,parseFloat()把值轉換成浮點數。只有對String類型調用這些方法,它們才能正確運行;對其餘類型都是先轉化成字符串(string()方法)後再進行轉換。他的返回值只有兩種,一種是十進制的整數,一種是NaN。

    + Number()函數中不管混合字符串中是否存在有效的整數,都會返回NaN,利用parseInt()和parseFloat()能夠提取字符串中的有效整數。

    + parseInt()和parseFloat()的區別是,前者能夠提取有效的整數,後者能夠提取有效的小數。

    + 對非String使用parseInt()或者parseFloat(),會將其轉換成String而後再操做

```
var str11 = true;
var res13 = parseInt(str11); // 這裏至關於parseInt("true");
console.log(res13); // NaN
var res14 = Number(str11);
console.log(res14); // 1
```

+ Number()函數

一、字符串轉數字

**若是是純數字字符串,則直接將其轉換爲數字**

```
<script>
  var str1 = "123";
  var num1 = Number(str1);
  console.log(num1, typeof num1); // 123 "number"
</script>
```

**若是字符串中含有非數字的內容,則轉換爲NaN**

```
<script>
  var str1 = "abc123";
  var num1 = Number(str1);
  console.log(num1, typeof num1); // NaN "number"
</script>
```

**若是字符串是一個空串,或是一個所有是空格的字符串,則轉換爲0 **

```
<script>
  var str1 = ""; // 空串
  var str2 = "   "; // 所有是空格
  var str3 = "123  " // 最後含有兩個空格
  var str4 = "  123" // 開頭含有兩個空格
  var num1 = Number(str1);
  var num2 = Number(str2);
  var num3 = Number(str3);
  var num4 = Number(str4);
  console.log(num1, typeof num1); // 0 "number"
  console.log(num2, typeof num2); // 0 "number"
  console.log(num3, typeof num3); // 123 "number"
  console.log(num4, typeof num4); // 123 "number"
</script>
```

二、undefined 轉數字 NaN

```
<script>
  // undefined轉數字
  var unde = undefined;
  var num1 = Number(unde);
  console.log(num1, typeof num1); // NaN "number"
</script>
```

三、null轉數字 0
```
<script>
  // null轉數字
  var nu = null;
  var num1 = Number(nu);
  console.log(num1, typeof num1) // 0 "number"
</script>
```

四、布爾轉數字 true轉成1 false轉成0

```
<script>
  // 布爾值轉數字
  var bool = true;
  var num1 = Number(bool);
  console.log(num1, typeof num1) // 1 "number"
  var bool1 = false;
  var num2 = Number(bool1);
  console.log(num2, typeof num2); // 0 "number"
</script>
```

+ parseInt() 把值轉換成整數

    1. 帶有自動淨化的功能;只保留字符串最開頭的數字,後面的中文自動消失

        parseInt()方法首先查看位置0處的字符,判斷它是不是個有效數字;若是不是,該方法將返回 NaN,再也不繼續執行其餘操做。但若是該字符是有效數字,該方法將查看位置 1 處的字符,進行一樣的測試。這一過程將持續到發現非有效數字的字符爲止,此時 parseInt() 將把該字符以前的字符串轉換成數字。


    2. 自動帶有截斷小數的功能:取整,不四捨五入
    
        字符串中包含的數字字面量會被正確轉換爲數字,好比 "0xA" 會被正確轉換爲數字 10。不過,字符串 "22.5" 將被轉換成 22,由於對於整數來講,小數點是無效字符。
    
    3. parseInt()方法還有基模式,能夠把二進制、八進制、十六進制或其餘任何進制的字符串轉換成整數。

```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
    <script type="text/javascript">
        var a = '123adfsfw'; // 數字開頭的
        var b = 'afsfsf234'; // 字母開頭的
        var c = '1sf23iwr'; // 開頭1個數字,混全的
        var d = '1334北京!!';
        var f = '1.23'; // 小於1.5的
        var f1 = '1.98'; //大於1.5的
        var aa = 'AF';
        var bb = '010';
        console.log(parseInt(a))
        console.log(parseInt(b))
        console.log(parseInt(c))
        console.log(parseInt(d))
        console.log(parseInt(f))
        console.log(parseInt(f1))
        console.log(parseInt(aa, 16))
        console.log(parseInt(bb, 8))
    </script>
</body>
</html>
```


輸出結果:

![輸出結果](media/5.png)

+ parseFloat() 把值轉換成浮點數
  
    + 會解析第一個,遇到第二個或者非數字結束;
    + 若是第一位不是有效數字,什麼也提取不到;
    + 不支持第二個參數,只能解析10進制數;
    + 若是解析內容裏只有整數,解析成整數;

```
var fNum1 = parseFloat("12345red"); //返回 12345
var fNum2 = parseFloat("0xA");  //返回 NaN
var fNum3 = parseFloat("11.2"); //返回 11.2
var fNum4 = parseFloat("11.22.33"); //返回 11.22
var fNum5 = parseFloat("0102"); //返回 102
var fNum1 = parseFloat("red");  //返回 NaN
```

## 7、運算符

+ **做用:**

運算符是告訴程序執行特定算術或邏輯操做的符號, 例如告訴程序, 某兩個數相加, 相減等

+ 分類

    + 按照功能分:算術、位、關係、邏輯
    + 按照操做個數分:
        + 單目運算 只有一個操做數:如i++
        + 雙目運算 有兩個操做數:如a+b
        + 三目運算 也稱爲問號表達式 如:a > b ? 1:0

+ 結合性
JavaScript中各類運算符的結合性分爲兩種: 左結合性(自左至右) 和 右結合性(自右至左)
    + 自左至右,即先左後右
        例如表達式: x - y + z;
        則y 應先與「-」號結合,執行 x-y 運算,而後再執行+z 的運算。
        這種自左至右的結合 方向就稱爲「左結合性」。
    + 自右至左,即先右後左
        例如:如x = y = z = 10
        因爲「=」的 右結合性,應先執行z = 10; 再執行y = z 再執行x = y運算。

### (一)加法運算符 +

+ 非Number類型的值,除字符串外,都會先轉爲Number類型的值後再進行計算

```
var sun = true + 2;
console.log(sun, typeof sun); // 3 "number"
var sun1 = true + false;
console.log(sun1, typeof sun1); // 1 "number"
var sun3 = 3 + null; // null 轉爲0
console.log(sun3, typeof sun3); // 3 「number"
```

+ 任何值和NaN進行運算時,結果都是NaN

```
var sun2 = NaN + 3;
console.log(sun2, typeof sun2); // NaN "number"
var sun4 = undefined + 3;
console.log(sun4, typeof sun4); // NaN "number"
```

+ 任何值和字符串進行加法運算,都會先轉爲字符串,而後和字符串進行拼接

```
var sun5 = 3 + "3";
console.log(sun5, typeof sun5); // 33 string
var sun6 = null + "3";
console.log(sun6, typeof sun6); // null3 string
var sun7 = undefined + "3";
console.log(sun7, typeof sun7); // undefined3 string
var sun8 = true + '3';
console.log(sun8, typeof sun8); // true3 string
```

### (二)減法運算符 -

+ 全部的非Number類型(包括字符串)的數據類型,都會將非Number數據類型先轉爲Number後再進行計算

```
var difference = 10 - 2;
console.log(difference, typeof difference); // 8 "number"
var difference1 = 10 - '2';
console.log(difference1, typeof difference1); // 8 "number"
var difference2 = 10 - true;
console.log(difference2, typeof difference2); // 9 "number"
var difference3 = 10 - null;
console.log(difference3, typeof difference3); // 10 "number"
```

+ 任何數據類型和NaN進行減法運算時,結果都是NaN

```
var difference4 = 10 - undefined;
console.log(difference4, typeof difference4); // NaN "number"
var difference5 = 10 - NaN;
console.log(difference5, typeof difference5); // NaN "number"
```

### (三) 乘法運算 *

規律和減法同樣

### (四)除法運算符 /

規律和減法同樣

### (五)取餘運算符 %

> m % n 求餘 至關於 m / n 取餘數

+ m 等於0 返回 0

```
var remainder = 0 % '4';
console.log(remainder, typeof remainder); // 0 "number"
```

+ n 等於0 返回 NaN

```
// 當n爲0時
var remainder1 = '4' % 0;
console.log(remainder1, typeof remainder1); // NaN "number"
```

+ m > n 正常取餘

```
// 當m>n時
var remainder2 = 5 % 2;
console.log(remainder2, typeof remainder2); // 1 "number"
```

+ m < n 結果是m

```
// 當m<n時
var remainder3 = 2 % 5;
console.log(remainder3, typeof remainder3); // 2 "number"
```

+ 其餘的規則和減法同樣

### (六)一元運算符

只有一個操做數的運算符 + -
+ +號不會對數字產生任何的影響,相似與數字中的正號
+ 對非Number類型的值,會調用Number()函數先進行轉換,而後再運算

```
// + 對數字不會產生影響,對與非Number類型的數值,會先調用Number()函數進行轉換
  var num1 = + "6";
  console.log(num1, typeof num1); // 6 "number"
  var num2 = + null;
  console.log(num2, typeof num2); // 0 "number"
  var num3 = + undefined;
  console.log(num3, typeof num3); // NaN "number"
  var num4 = + true;
  console.log(num4, typeof num4); // 1 "number"
```

+ -號至關於數字中的負數,對數字進行取反操做

```
var num5 = - - '6'; // 負負得正
console.log(num5, typeof num5); // 6 "number"
var num6 = 1 - -"3" + 3;
console.log(num6, typeof num6); // 7 "number"
var num7 = - "123abc"; // 轉換的時候調用的Number()函數,不是調用的parseInt()函數。
console.log(num7, typeof num7); // NaN "number"
```

### (七)賦值運算符

賦值運算符能夠分爲簡單賦值運算符和複合賦值運算符

+ 簡單賦值運算符
    + 格式:變量名 = 數據
    + =的左邊只能是變量
    + 多個賦值運算符能夠組成賦值表達式,具備右結合性

```
// 從右往左進行賦值
// 先將10賦值給c,而後變量c中儲存的值再賦值給b,變量b中儲存的值再賦值給a,最後a b c 儲存的值都是10
a = b = c = 10;
```

+ 複合賦值運算符

```
+= 加後賦值 如: a += 1 至關於 a = a + 1
-= 減後賦值 如:a -= 1 至關於 a = a -1
*= 乘後賦值 如:a *= 1 至關於 a = a * 1
/= 除後賦值 如:a /= 1 至關於 a = a / 1
%= 取模後賦值 如:a %= 1 至關於 a = a % 1
```

+ 複合賦值表達示運算

    + 格式:a *= 1 + 2
    + 因爲賦值運算符是右結合性,因此會先計算=右邊的,而後再進行計算 至關於 a = a * (1 + 2) 

```
var a = 10
a *= 100 + 30;
console.log(a) // 1300 a = 10 * (100+30)
```

### (八) 自增自減運算符

### 一、介紹

javascript提供了 ++ -- 這兩種自增和自減的運算符來簡化 i = i + 1, i = i - 1 這樣的操做

### 二、自增、自減 求值的過程

+ 不管運算符在前面仍是後面(前綴仍是後綴)變量自身都會發生改變
+ 後綴表達式 i ++ , i -- 先用i的值作爲整個表達式的值,再進行加1或減1的操做,即:先用後變

```
// a ++ a-- 先用後變
var a = 10, b;
b = a ++; // 先用i的值作爲賦值運算右邊的值,把a的值賦值給b,而後a再自身加1
console.log(a); // 11
console.log(b); // 10
var num = 10;
sun = num++ + 10;
console.log(sun); // 20 先完成num + 10 後,再自身加1
console.log(num); // 11
```

+ 前綴表達式 ++ i, -- i 先自身加1或減1,而後再將i的值作爲表達式的值,即:先變後 用

```
// ++a --a 先變後用
var a1 = 10 , b;
b1 = ++ a1; // a1自身先加上1,而後把值賦值給b1
console.log(a1); // 11
console.log(b1); // 11
var num1 = 10;
sun1 = ++num1 + 10;
console.log(sun1); // 21 先自身加1 後,再進行 + 10 的運算
console.log(num1); // 11
```

### (九)關係運算符

關係運算符的返回值,只有兩個,要麼是真(true)要麼是假(false)

+ javascript 支持的關係運算符

![關係](media/關係.png)

+ 對於非數值類型進行比較時,會轉換爲數值再進行比較

```
var a = 1;
console.log(a == true); // true
console.log( a === true); // false
console.log(a > '0'); // ture
```

+ 若是兩側都是字符串,不會轉換爲數字進行比較,而是分別比較字符串的Unicode編碼的大小
    + 比較編碼時是從左到右一位一位進行比較
    + 若是兩位相同,則會比較下一位,能夠用來作英文的排序
    + 比較中文沒有意義

```
console.log('a' < 'b'); // true
console.log('abc' < 'abd'); // true
console.log('你' > "我"); // false
```

+ null、 undefined、 NaN比較

```
console.log(null == 0); // false
console.log(undefined == 0); // false
// 永遠不要判斷兩個NaN是否相等
console.log(NaN == NaN); // false

/*
 * 能夠經過isNaN()函數來判斷一個值是不是NaN
 *    若是該值是NaN(不是一個數字)則返回true,不然返回false
 */
var num = NaN;
console.log(isNaN(num)); // true
console.log(isNaN(1)); // false
console.log(isNaN(null)); // false
console.log(isNaN(undefined)); // true
console.log(isNaN('abc')); // true

// undefined 衍生自 null, 因此返回true
console.log(null == undefined); // true;
console.log(null === undefined); // false;


// == 判斷值是否相等
// == 會進行數據類型轉換
console.log("123" == 123); // true
// === 判斷值和類型時候同時相等
// === 不會進行數據類型轉換
console.log("123" === 123); // false
```

+ 注意的地方

比較兩個字符串類型的數字,結果可能有誤差,因此須要提早轉型;

```
console.log("1111123" < "124" ); // true
console.log("1111123" < 124 ); // false
```

### (十)邏輯運算符

#### 一、&& (與運算)

+ 運行結果 條件A && 條件B

先去判斷條件A成不成立,若是A成立了纔去判斷B是否成立,若是A不成立則不會去判斷B

兩個條件爲真才爲真,有一個爲假就爲假

+ 短路測試

條件 && 表達式 條件爲真時,後面的表達式執行
```
console.log(7 > 3 && console.log('執行了')) // 執行了
```

+ 注意的地方
    + 對於非Boolean類型的數值,邏輯與會自動將其轉換爲Boolean類型來判斷;
    + 若是條件A成立,無論條件B成立與不成立都會返回條件B;
    + 若是條件A不成立,則返回條件A自己;
```
// 若是條件A不成立,則返回a的自己
var result = null && 7 > 3;
console.log(result); // null
// 若是條件A成立,無論B成不成立,都將返回B
var result1 = 123 && 'abc';
console.log(result1) // abc
var result2 = 123 && null;
console.log(result2); // null
```

#### 二、 || (或運算)

+ 運行結果 條件A || 條件B

有一個爲真就爲真,兩個爲假才爲假

若是A成立了,則不會去判斷條件B,只有在A不成立的時候纔會去判斷條件B

+ 短路測試

條件 && 表達式 條件爲假時,後面的表達式執行
```
console.log(7 < 3 && console.log('執行了')) // 執行了
```

+ 注意的地方
    + 對於非Boolean類型的值,邏輯或會將其自動轉爲布爾類型的值來判斷;
    + 若是條件A不成立,則無論條件B成不成立都會返回條件B自己的數值;
    + 若是條件A成立,則返回條件A自己的數值;

#### 三、 !(非運算)

+ 運行結果 !條件A

對條件A進行取反 好比:條件A成立true,取反後爲false

+ 注意的地方
    + 對一個值進行兩次取反,它不會發生變化;
    + 對非布爾值進行操做,則先將其轉換爲Boolean,而後再進行取反,因此將一個數值轉換爲Boolean,除了Boolean()函數外,還能夠使用 !!數值, 實現的原理和Boolean(數值)是同樣的;

### (十一)逗號運算符

逗號表達式就是把多個表達式鏈接起來,組成一個表達式。

+ 結果 

從左往右計算,一直到最後一個,整個表達式的值也是最後一個表達式的值。

```
var a, b;
b = (a=3, --a, a*5);
console.log(b) // 10
```

+ 使用注意事項

    + 程序中使用逗號表達式,一般是求表達式內各個表達式的值,並不必定要求,整個逗號表達式的值;
    + 並非全部出現逗號的地方都組成逗號表達式,例如在變量說明中,函數參數表中的逗號只是分隔做用;

```
var a, b, c;  //這裏的逗號只是分隔符
    function sendMessage(num, content) { //這裏的逗號只是分隔符
           console.log(num, content);
    }
```

### (十二)三目運算符

+ 格式:

條件表達式 ?語句1:語句2;

+ 求值規則

條件表達式爲真時,執行語句1;爲假時執行語句2.

```
// 若是條件表達式爲真,則執行語句1,爲假則執行語句2
true?alert("語句1"):alert("語句2"); // 語句1
false?alert('語句1'):alert('語句2') // 語句2
```

一個案例:

```
<script>
// 接收用戶輸入的三個數,找出最大的那個
var num1, num2, num3, maxNum;
num1 = Number(prompt("請輸入數字1"));
num2 = Number(prompt("請輸入數字2"));
num3 = Number(prompt('請輸入數字3'));
maxNum = num1 > num2 ? num1:num2;
maxNum = maxNum > num3 ? maxNum:num3;
console.log(maxNum);
</script>
```

+ 注意的地方

    + 條件運算符?:是一對運算符,不能分開單獨使用
    + 若是條件表達式的求值結果不是一個Boolean,則會轉換爲Boolean值後再運算

### (十三)運算符的優先級

+ 運算符的優先級共分爲15級,1最高,15最低;
+ 計算規則
    + 先計算優先級高的;
    + 若是優先級同樣,則誰在左邊先算誰
    + 能夠使用()來改變優先級
+ 優先級圖示

![優先級](media/優先級.png)

## 8、流程控制

### (一)if 語句

一個分支,要麼執行,要麼不執行

+ 語法

```
if (條件){
    代碼塊;
}
```

+ 執行過程

若是條件是true,則執行代碼塊,若是是false,不會執行代碼塊

### (二)if else 語句

兩個分支,只能執行一個分支,像這種狀況也能夠使用三元表達式

+ 語法

```
if(表達式){
    代碼塊1;
}else{
    代碼塊2;
}
```

+ 執行過程

若是表達式的結果是true,執行代碼塊1,若是結果是false,則執行代碼塊2

### (三)if else if else if .. else 語句

多個分支,最終也執行一個

+ 語法

```
if(表達式1){
    代碼塊1;
}else if(表達式2){
    代碼塊2;
    .....
}else{
    代碼塊3;
}
else if 能夠寫多個,具體看須要
else 能夠不用寫,具體看需求
```

+ 執行過程

先判斷表達式1的結果,若是是true,就執行代碼塊1,後面的不會執行,若是結果是false,則會判斷表達式2的結果,若是是true,就執行代碼塊2,後面的不執行,若是是false,則會繼續判斷下一個表達式,依此類推,最終,若是else if的表達式結果都是false,則執行最後的else代碼塊的語句。

### (四) switch case 語句

多個分支,最終也執行一個(最終執行幾個由break決定)

+ 語法

```
switch(表達式){
    case 值1:代碼1;
    break;
    case 值2:代碼2;
    break;
    case 值3:代碼3;
    break;
    case 值4:代碼4;
    break;
    .....
    default:代碼5;
    break;
}
default 後的break能夠省略
default 也能夠省略
case 值和表達式的值進行比較的時候是嚴格模式,至關是===的比較;
break,若是不寫,會從case匹配到的值開始,一直執行代碼塊,直到遇到break跳出
```

+ 執行過程

獲取表達式的值,和值1進行比較,若是相同,則執行代碼1,遇到break跳出,後面的代碼不執行;若是和值1不相同,則和值2進行比較,依此類推,若是表達式的值和case的值都不同,就執行default代碼5的,跳出。

break的使用

```
<script>
  // 每月有多少天
  var month = Number(prompt("月份"));
  if (!isNaN(month)) {
    switch (month) {
      case 1:
      case 3:
      case 5:
      case 7:
      case 8:
      case 10:
      case 12:
        console.log("有31天")
        break;
      case 4:
      case 6:
      case 9:
      case 11:
        console.log("有30天")
        break;
      case 2:
        console.log("有28天")
        break;
    }
  }else{
    console.log("輸入有誤")
  }
</script>
```

## 9、循環

### (一)while 循環

+ 語法

```
while(循環條件){
    循環體;
    計數器++;
}
```

+ 執行過程

先判斷循環條件是true仍是false,若是條件是true,則執行循環體和計數器,再次判斷循環條件,若是條件成立,就執行循環體,不然就退出循環。

### (二)do while 循環

+ 語法

```
do {
    循環體;
} while(條件);
```

+ 執行過程

先執行一次循環體,而後判斷條件是true仍是false,若是是false,則跳出循環,若是是true,則繼續執行循環體,至到條件不知足,跳出循環體,

+ while 和 do while的區別

    + while 是先判斷,後循環,有可能一次循環都不執行;
    + do-while 是先循環,後判斷,至少執行一次循環;

### (三)for 循環

+ 語法

```
for(表達式1;表達式2;表達式3){
    循環體;
}
```

+ 執行過程
先執行一次表達式1,而後判斷表達式2的條件成不成立。
    + 若是成立,則執行一次循環體,而後執行表達式3,再判斷表達式2成不成立,依此類推,至到表達式2不成立。跳出循環;
    + 若是不成立,則跳出循環;

```
 // 斐波那契數列
var num1=1, num2=1, sun=0;
for (var i=3; i<=12; i++) {
  sun = num1 + num2;
  num1 = num2;
  num2 = sun;
}
console.log(sun);
```

### (四) break 語句

若是在循環中,遇到了break,則當即跳出當前所在的循環(注意是當前的循環,若是還有外層循環,是不會跳出的)

```
<script>
  // break 跳出
  for(var i=0; i<5; i++){
    while (true) {
      console.log("哈哈哈");
      break; // 只跳出當前這層循環
    }
  }
</script>
```

```
// break 找100-200之內被7整除的第2個數
for (var i=100, j=0; i<=200; i++) {
if (i%7==0){
  if(j==1){
    console.log(i);
    break;
  }
  j++;
}
}
```

### (五)continue 跳出本次循環

在循環中遇到continue關鍵字,直接跳出本次循環,進入一下次循環。

```
// 求100-200之間全部的奇數的和 continue
for (var i=100, sun=0; i<=200; i++) {
  if (i%2==0) {
    continue;
  }
  sun += i;
}
console.log(sun);
```

```
// 求整數100-200的累加值,要求跳過全部個位數爲3的數
// 個數數爲3,要取出來,就是10取餘後,餘數是3的
for (var sun=0, i=100; i<=200; i++) {
  if (i%10==3) {
    /* 說明個位數是3,不要 */
    continue;
  }
  sun += i;
}
console.log(sun);
```

## 10、數組

+ 數組:變量只能存儲一個值,所謂的數組就是將多個元素(一般是同一類型)按必定順序排列放到一個集合中,那麼這個集合咱們就稱爲數組。
+ 數組的做用:能夠一次性存儲多個數據;
+ 數組的全部方法來源於:`Array.prototype`
```javascript
 // 本身寫數組的push方法
Array.prototype.push = function () {
  for (var i=0; i<arguments.length; i++) {
    this[this.length] = arguments[i];
  }
  return this.length;
};
var arr = [1, 2]
```



+ 數組的定義

  一、經過構造函數建立數組;
```
語法:
var 數組名=new Array(長度);
var array=new Array();//沒有數據,空數組
數組的名字若是直接輸出,那麼直接就能夠把數組中的數據顯示出來,若是沒有數據,就看不到數據。
var array=new Array(5); // 若是數組中沒有數據,可是有長度,數組中的每一個值就是undefined
var arr = new Array(10.2) // 會報錯,第一位傳小數會報錯
```

 二、經過字面量的方式建立數組;

```
var 數組名=[]; //空數組
```

三、數組的讀和寫

arr[num] 不能夠溢出讀,結果是undefind,不會報錯

arr[num] = xxx  能夠溢出寫,會把數組的長度撐長到num,前面的數據是undefind。

+ 數組元素:數組中存儲的每一個數據,均可以叫數組的元素,好比:存儲了3個數據,數組中3個元素
+ 數組的長度:就是數組的元素的個數,好比有3個元素,就說這個數組的長度是3;
+ 數組索引(下標):用來存儲或者訪問數組中的數據的;數組名[下標]
+ 注意點:
    + 不管是構造函數的方式仍是字面量的方式定義的數組,若是有長度,那麼默認的是undefined;
    + 構造函數的方式建立數組的時候,若是在Array(一個數字)————>數組的長度(數組元素的個數);
    + 若是在Array(多個值),這個數組中就有數據了,數組的長度就是這些數據的個數;
    + 數組的索引和數組長度的關係:就是長度減1,就是最大的索引;

```
// for 循環遍歷數組
var array = new Array(1, 2, 'mjc', undefined, true, null, new Object);
for (var i=0; i<array.length; i++) {
  console.log(array[i]);
}
```

```
// 求數組裏的最大值
var array = new Array(1, 6, 9000, 120, 900, 1000, 0);
for (var max=array[0], i=0; i<array.length; i++) {
  if (max < array[i]) {
    max = array[i];
  }
}
console.log(max);
```

```
// 數組的倒序
var array = new Array(1, 2, 3, 4, 5, 6);
for (var i=array.length-1; i>=0; i--) {
  console.log(array[i]);
}
```

```
 // 把數組中的每一個元素用|拼接到一塊兒產生一個字符串輸出
var array = new Array(1, 2, 3, 4, 5, 6);
for (var i=0, str=''; i<array.length-1; i++) { /* 這裏的length-1,爲了避免輸出最後一個 */
  str += array[i] +'|';
}
console.log(str+array[array.length-1]); /* 輸出的最後再把數組的最後一個加上 */
// 1|2|3|4|5|6
```

```
// 去掉數組中重複的0, 把其餘的元素放在一個新的數組中
var array = new Array(1, 0, 4, 9, 10, 0, 23);
var newArray=[];
for (var i=0; i<array.length; i++) {
  if (array[i] != 0) {
    newArray[newArray.length] = array[i]; // 把新數組的長度做爲下標
  }
}
console.log(newArray); // [1, 4, 9, 10, 23]
```

```
// 翻轉數組 位置調換
// 思路:
// 一、交換的次數是長度的一半,4個元素,交換2次,5個元素也交換2次
// 二、利用第三方變量臨時存儲交換的值
/* 三、循環交換時:第一次:索引位置是0的和索引位置是length-1-0的進行交換;第二次:索引位置是1的和索引位置是length-1-1的進行交換;
第三次:索引位置是2的和索引位置是length-1-2的進行交換。。。依此類推 */

var array = new Array(1, 2, 3, 4, 5, 6, 7);
for (var i=0; i<array.length/2; i++) {
  var temp = array[i];
  array[i] = array[array.length-1-i];
  array[array.length-1-i] = temp;
}
console.log(array);
```

冒泡排序:

![冒泡排序](media/冒泡排序.png)

```
// 冒泡排序
/* 思路:
一、拿一個數字和其餘的元素進行對比,每個元素都要跟其餘的元素對比一次;
二、比較的輪數是長度-1;
三、每一輪比較的次數:length-1-i;
四、用第三方交換變量; */
// 從小到大排序
var array = new Array(1, 3, 5, 9, 2, 6, 4);
for (var i=0; i<array.length-1; i++) {
  for (var j=0;j<array.length-1-i; j++) {
    var temp;
    if (array[j] < array[j+1]) {
      temp = array[j];
      array[j] = array[j+1];
      array[j+1] = temp;
    }
  }
}
console.log(array); // [9, 6, 5, 4, 3, 2, 1]
```

### 僞數組

arguments對象是全部(非箭頭)函數中均可用的局部變量。你能夠使用arguments對象在函數中引用函數的參數。arguments對象不是一個 Array 。它相似於Array,但除了length屬性和索引元素以外沒有任何Array屬性。例如,它沒有 pop 方法。

arguments.length 能夠獲取函數在調用時,傳入了幾個參數,還能夠使用arguments對象能夠獲取傳入的每一個參數的值(數組形式)函數名.length:能夠獲取形參的個數;

類數組的構成

```javascript
// 類數組的構成
var obj = {
  0:'a',
  1:'b',
  2:'c',
  length:3,
  push:Array.prototype.push,
  splice:Array.prototype.splice // 給一個對象加上splice,就長的像數組同樣。
}
obj.push('d')
console.log(obj) // {0: "a", 1: "b", 2: "c", 3: "d", length: 4, push: ƒ} 會發現增長了一個3:'d',而且長度增長了
```

上面的就叫一個類數組,必須有幾個組成部分

一、屬性要爲索引(數字)必須有length屬性,最好加上push。

二、好處,能夠像數組同樣用,也能夠像對象同樣用,DOM生成的類數組的東西,全是類數組。

```javascript
var obj = {
  0:'a',
  1:'b',
  2:'c',
  name:'ww',
  age:123,
  length:3,
  push:Array.prototype.push,
  splice:Array.prototype.splice
}
console.log(obj); // Object(3) ["a", "b", "c", name: "ww", age: 123, push: ƒ, splice: ƒ]
console.log(obj.name); // ww
```



## 11、函數

函數:把一坨重複的代碼封裝,在須要的時候直接調用便可

函數的做用:代碼的重用。

```
語法:
一、函數的定義:
function 函數名字(){
  函數體-->一坨重複的代碼
}
二、函數的調用:函數名();
三、函數的參數:在函數定義的時候,函數名子後面的小括號裏的變量就是參數,目的是函數在調用的時候,用戶傳進來的值操做;此時函數定義的時候後面的小括號裏的變量叫參數;在函數調用的時候,按照提示的方式,給變量賦值-->就叫傳值,把這個值就傳到了變量(參數)中;
四、形參:函數在定義的時候,小括號裏的變量叫形參;
五、實參:函數在調用的時候,小括號裏傳入的值叫實參,實參能夠是變量也能夠是值;
函數的返回值:在函數內部有return關鍵字,而且在關鍵字後面有內容,這個內容被返回了,當函數調用以後,須要這個返回值,那麼就定義變量接收,便可;
六、命名函數:函數若是有名子,就是命名函數,是一種弱類型的聲明方式,在預解析完,執行的時候,會被var聲明的覆蓋。
alert(a) 若是是在預解析的時候,函數名會被提高
var a = 1;
    function a() {
        alert(1)
    }
    alert(a) 會彈出1
==========================================================================
七、匿名函數:函數若是沒有名子,就是匿名函數;
八、函數的另外一種定義方式:函數表達式,把一個匿名函數或者把一個函數給一個變量;強類型的聲明,先聲明,後調用
var f1 = function () {
  console.log("我是一個函數");
};
console.log(f1.name); // f1
var f1 = function abc () { // 注意這裏的abc充當了一個表達式就不能充當一個函數體了
  console.log("我是一個函數");
}
abc(); // 報錯
console.log(f1.name) // abc
若是是函數表達式,那麼此時前面的變量中存儲的就是一個函數,而這個變量就至關因而一個函數,就能夠直接加小括號調用了。
九、函數的自調用,沒有名字,調用--聲明的同時,加小括號直接用, 一次性的,通常用於初始化數據
(function(){console.log("自調用");})(); 聲明函數不能自調用,可是在聲明函數前加上-/+/!/(括號)就變成了函數表達式了,可以自調用了,可是函數名就不起做用了;
十、回調函數:函數做爲參數使用,若是一個函數做爲參數,那麼咱們說這個參數(函數)能夠叫作回調函數,只要是看到了一個函數做爲參數使用了,那麼就是回調函數;
十一、塊級做用域:一對大括號就能夠看做是一塊,在這塊區域中定義的變量,只能在這個區域中使用,可是在js中在這個塊級做用域中定義的變量,外面也能使用。說明,js中沒有塊級做用域;
十二、全局變量:聲明的變量,是使用var聲明的,那麼這個變量就是全局變量,全局變量能夠在頁面的任何位置使用,若是頁面不關閉,那麼就不會釋放,就會佔空間,消耗內存;一切聲明的全局變量,都是window的屬性。如 var a = 123; console.log(window.a) // 123
1三、局部變量:在函數內部定義的變量,是局部變量,外面不能使用,目前除了函數內部定義的變量是局部變量,其餘地方定義的變量是全局變量。
1四、全局做用域:全局變量的使用範圍;
1五、局部做用域:局部變量的使用範圍;
1六、在一個函數中使用一個變量,先在該函數中搜索這個變量,找到了則使用,找不到則繼續向外找這個變量,一直找到全局使用域,找不到則是undefined;
1七、隱式全局變量(暗式全局變量):聲明的變量沒有var,就叫隱式全局變量;函數內的隱式全局變量,在函數外也能夠訪問,可是隱式全局變量不會預解析進行變量的提高。
1八、js的執行過過程:一、語法分析,先過一遍看有沒有語法錯誤;二、預編譯;三、解釋執行代碼;
預編譯也叫變量提高,無論函數在那定義的,都會把函數總體(整個函數,包括聲明,可是不是函數表達式 )提高到邏輯的最前面,變量聲明提高,只提高聲明,不會賦值。

注意點:
一、函數要先定義,才能使用;
二、函數的名字和變量同樣,要遵循命名法;
三、函數聲明重名,後面的會把前面的覆蓋,無論在那個位置;函數表達式
四、形參的個數和實參的個數能夠不一到(這一點和python不同,python裏必需要求一致,不然會報錯);
五、函數沒有返回值(沒有return)或者是沒有明確的返回值(return後面沒有內容)可是在調用的時候接收了,那麼結果就是undefined(變量聲明瞭,沒有賦值也是undefined);
六、return就是結束函數,後面的代碼不會被執行;
七、函數名不加括號,打印出來是函數塊的代碼(python打印出來的是函數的內存地址);
八、函數之間能夠相互調用;
九、函數表達式後面,賦值結束後,必需要加分號;
十、函數是有數據類型的,是function類型的;
十一、函數能夠做爲參數(回調函數),也能夠做爲返回值;
十二、全局變量是不能被delete刪除的,隱式全局變量是能夠被刪除的,也就是說使用var是不會被刪除的,沒有var是能夠刪除的;
1三、預解析中,變量聲名的提高,只會在當前的做用域中提高,提高到當前的做用域的最上面,函數中的變量只會提早到局部做用域的最前面,不會成爲全局的;
1四、預解析會分段(多對的script標籤中函數重名,預解析的時候不會衝突)
```

### arguments.callee

指向的是函數的引用,也就是函數自己的代碼,在那個函數裏就指代那個函數自己

```javascript
function test() {
  console.log(arguments.callee); // ƒ test() {console.log(arguments.callee);}
}
test()
============================
var num = (function (n) {
  if (n == 1) {
    return 1
  }
  return n * arguments.callee(n-1) // return n * 函數(n -1)
}(5))
console.log(num); // 120
```

### `function.caller`

函數本身的屬性,在那個環境裏調用,就是誰

```javascript
function f1() {
  f2()
}
function f2() {
  console.log(f2.caller); // 在f1裏被調用了,那麼就是f1自己,ƒ f1() {f2()}
}
f1()
```



![做用域](media/做用域.jpg)

```
// 三個數中最大的值
  function maxNum(x, y, z) {
    return x>y?(x>z?x:z):(y>z?y:z);
  }
  console.log(maxNum(3, 5, 9));
```

```
// 判斷一個數是否是素數
function primeNumber(x) {
  for (var i=2; i<x; i++) {
    if (x%i == 0) {
      return false;
    }
    return true;
  }
}
console.log(primeNumber(5)?"是質數":"不是質數");
```

```
// 求一組數字中最大的值
function maxNum(array) {
  var max = array[0]; // 注意這個變量應該是定義在循環外邊
  for (var i=0; i<array.length; i++) {
    if (max < array[i]) {
      max = array[i];
    }
  }
  return max;
}
console.log(maxNum([1, 3, 4, 56, 998, 233, 833]));
```

```
// 輸入,年、月、日、獲取這個日期是這一年的多少天
// 定義判斷閏年的函數
function isLeapYear(year) {
  // 閏年:能被4整除,可是不能被100整除,或者能被400整除
  return year%4==0&&year%100!=0||year%400==0;
}
// 定義計算天數的函數
function getDays(year, month, day) {
  var days = day;
  if (month==1) { // 若是用戶輸入的是1月份,不必再向後算天數,直接返回天數
    return day;
  }
  // 定義一個數組,存儲每月份的天數
  var months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  // 小於的是月份-1,而不是數組長度-1
  for (var i=0; i<month-1; i++) {
    days += months[i];
  }
  // 須要判斷這個年份是否是閏年
  if (isLeapYear(year) && month>2) {
    days ++;
  }
  return days;
}
console.log(getDays(2000, 3, 2))
```

```
/* arguments 的應用 計算N個數字的和
定義一個函數,若是不肯定用戶是否傳入了參數,或者說不知道用戶傳了幾個參數,沒辦法計算,可是若是在函數中知道了參數的個數,也知道了每一個參數的值,能夠 */
function f1() {
  var sun = 0;
  for (var i=0; i<arguments.length; i++) {
    sun += arguments[i];
  }
  return sun;
}
console.log(f1(20, 30, 10, 50));
```

```
// 聲名函數 重名 後面的會覆蓋,無論在那個位置調用
function f1() {
  console.log("小明好帥")
}
f1(); // 小豬好帥哦
function f1() {
  console.log("小豬好帥哦")
}
f1(); // 小豬好帥哦

// 函數表達式 重名後,不會覆蓋,調用時會根據位置的不一樣產生不一樣的結果。
var f2 = function () {
  console.log("星期天真好")
}; // 函數表達式這個分號不能少
f2(); // 星期天真好
f2 = function () {
  console.log("星期一真痛苦")
}
f2(); // 星期一真痛苦

// 函數的自調用,由於加小括號就是函數的調用,函數名不加括號輸出就是函數的代碼,自調用就是匿名函數代碼直接加小括號,且匿名函數之間不影響;
(function () {
  console.log("macbook真香");
})(); // macbook真香
(function () {
  console.log("Thinkpad也還行"
  );
})(); // macbook真香
```

預解析代碼:

```
    // 預編譯(變量的提高)
    /*
    * 預編譯發生在函數執行的前一刻,預編譯的四部曲
    * 一、建立Ao對象(至關於做用域或是執行期上下文)
    * AO = {
    *
    * }
    * 二、找形參和變量聲明,將變量和形參名做爲ao屬性名,值爲undefined, 只找有var的
    * AO = {
    *   a:undefined,
    *   b:undefined
    * }
    * 三、將實參值和形參值統一
    * AO = {
    *   a:1,
    *   b:undefined
    * }
    * 四、在函數體裏面找函數聲明,將函數名做爲AO屬性,值是函數體,注意是函數聲明,不是函數表達式
    * AO = {
    *   a:function a() {},
    *   b:undefined // b叫函數表達式,不叫函數聲明
    *
    * }
    * 預編譯結束開始執行函數
    * */
    function fn (a) {
        console.log(a); // function a() {}
        var a = 123;  // 預編譯已經執行過var a; 這一步只執行 a = 123;
        console.log(a); // 123
        function a() {} // 預編譯時已經執行過了再也不執行
        console.log(a); // 123
        var b = function () {}; // 預編譯的時候已經執行過var b; 只執行b=function () {}
        console.log(b); // function () {}
    }
    fn(1);
    /*
    * 全局預編譯
    * 一、建立GO對象,
    * 二、找到變量聲明,只找var的,將變量名做爲GO的屬性,值爲undefined;
    * 三、找到函數聲明,將函數名做爲GO屬性,值是函數體,注意是函數聲明,不是函數表達式
    * */
```

```
// 預解析
// 通常變量的書寫順序是先提早聲明變量,輸出在後,可是預解析會把變量的聲名提早到最前面
// 正常書寫
var num = 11;
console.log(num); // 11
// 先輸出,後聲明
console.log(num1); // undefined;
var num1 = 12;
// 正常書寫函數
function f1() { 
  console.log("我是一個函數");
}
f1(); // 我是一個函數
// 先調用,後聲明
f2(); // 預解析
function f2() {
  console.log("預解析");
}
// 例3;
f3(); // undefined 調用函數的時候,會把函數的聲明提高到做用域的上面
var num3 = 20  // 這個變量會被提高到變量使用以前,至關於在f3()以前,var num3; 可是沒有賦值。
function f3() {
  console.log(num3);
}
// 例4
var a = 25;
function abc() {
  /* 至關因而

  alert(a); // undefined ,預解析只會在局部變量裏提高 var a=10 的聲名,不會到全局的a
  /* 至關因而
  a= 20 */
  var a = 10;
}
abc();
console.log(a) // 25 全局變量

// 例5
console.log(a); // 函數的代碼 由於提高的是函數的聲明
function a() {
  console.log("aaaa");
}
var a = 1;
console.log(a); // 1
// 上面的代碼至關於:
function a() {
  console.log("aaaa");
}
console.log(a);
var a = 1;
console.log(a);

// 例6
function f4() {
  console.log(num4); // undefined
  var num4 = 20;
}
console.log(num4); // 會報錯,由於,預解析只會提高到當前做用域的最上面。不會提高到全局做用域的

// 例7:注意坑
f5();
console.log(c); // 9
console.log(b); // 9
console.log(a); // 報錯
function f5() {
  var a=b=c=9;
  console.log(a); // 9
  console.log(b); // 9
  console.log(c); // 9
}
// 緣由:至關因而下面的代碼
function f5() {
  var a;
  a = 9;
  // b和c是沒有var的隱式全局變量
  b = 9;
  c = 9;
  console.log(a); // 9
  console.log(b); // 9
  console.log(c); // 9
}
f5();
console.log(c); // 9
console.log(b); // 9
console.log(a); // 報錯
// 例8
f6(); // 報錯
var f6 = function () {
  console.log(a);
  var a = 10;
};
// 緣由:由於這個函數是函數表達式,是經過賦值的形式,在預解析的時候,提高聲名,只會在f6();前面聲明var f6;並無函數的代碼,因此報錯;
```

### 遞歸

找規律(公式),找出口(已知的條件)

階乘的公式:n*(n-1)

斐波那契數列:(n-1)+(n-2);

```
// 遞歸
    function f(n) {
        if (n == 1|| n==0){
            return 1;
        }
        return n * f(n-1);
    }

// 斐波那契數列
    function f(n) {
        if (n == 1||n == 2)  {
            return 1;
        }
        return f(n-1) + f(n-2);
    }
```

## 12、面向對象



+ 編程思想:把一些生活中作事的經驗融入到程序中;
+ 面向過程:凡事都要親力親爲,每件事的具體過程都要知道,注重的是過程;
+ 面向對象:根據需求找對象,全部的事都用對象來作,注重的是結果;
+ 面對對象的三大特性:封裝、多態、繼承;
+ js不是面對對象的語言,是一門基於對象的語言,可是能夠模擬面向對象的思想;
+ 什麼是對象:看的見,摸的到,具體特指的某個東西,好比:汽車就是否是一個對象,是一個類別,而掛甘A10011的就是對象。有屬性和方法,具體特指的某一個事物;

### 建立對象的三種方式


  一、調用系統的構造函數建立對象

```javascript
  建立對象:
  var obj = new Object();
  添加屬性:對象.名子 = 值;
  obj.name = "小明";
  obj.age = 18;
  添加方法:對象.名子 = 函數;
  obj.eat = function () {
    console.log("我喜歡吃大米");
  };
  調用屬性:對象.名子;
  console.log(obj.name);
  調用方法:對象.名子();
  obj.eat();
  刪除屬性: delete 對象.屬性名
	雖然全局變量var num = 123 是window的屬性,可是一但經歷了var操做,所得出的屬性,這種屬性叫作不可配置的屬性,不可配置的屬性,delete是刪不掉的。可是隱式全局變量沒有經歷var操做,就能夠刪掉
```

  二、工廠模式建立對象

```
// 工廠模式建立,解決了建立多個類似對象的問題,相比於自定義的構造函數,可是不能解決對象識別的問題
function createObject(name, age) {
  var obj = new Object();

  obj.name = name;
  obj.age = age;
  obj.fangFa = function () {
    console.log("工廠模式的方法");
  };
return obj;
}
var person = createObject("小明", 18);
person.fangFa();
```

  三、自定義構造函數建立對象(結合第一種和需求經過工廠模式建立對象)

```javascript
// 二、自定義構造函數建立(工廠模式建立對象)
// 一次性能夠建立多個對象,把建立對象的代碼封裝在一個函數中
// 對象能夠分辨出是屬於什麼類型
// 函數和構造函數的區別:名字的首字母是否是大寫;
// 自定義構造函數
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.eat = function () {
    console.log(this.name + "今年" + this.age + "歲" + "想吃大米");
  };
}
var pers1 = new Person("小明", 18); // 自定義構造函數建立對象 當這行代碼執行的時候發生了4件事
//第一件事:在內存中開闢空間,存儲建立的新對象;
//第二件事:把this設置爲當前的對象,而且在這個對象中添加__proto__:Person.prototype(原型)的屬性
//第三件事:設置對象的屬性和方法的值
//第四件事:把this這個對象返回
pers1.eat();
console.log(pers1 instanceof Person);
自定義構造函數相比工廠模式:
一、沒有顯式的建立對象;
二、直接將屬性和方法賦給了this對象;
三、沒有return;
// instanceof
// 如何獲取該變量(對象)是否是屬於什麼類型的?
// 語法:變量 instanceof 類型的名字 ----> 布爾類型
```

  四、字面量的方式建立對象;

```
// 三、字面量建立對象
// 注意裏面的屬性方法與值之間用冒號,相互之間用逗號隔開,最後一個不加
// 缺陷:一次性的對象,不對傳值
var pers2 = {
  name:"小明",
  age:18,
  eat:function () {
    console.log(this.name + this.age + "愛吃辣條");
  }
};
pers2.eat();
```

### 訪問對象屬性方法的另外一種寫法

obj.prop與obj["prop"]

當執行obj.prop的時候,內部會隱式的轉化成obj["prop"]的方式來執行,obj[]的這種形式,方括號裏的必須是字符串

```javascript
// 訪問對象屬性的另外一種方法["名子"] 注意雙引號,是以字符串的形式
function Dog (name, age) {
  this.name = name;
  this.age = age;
  this.play = function () {
    console.log(this.name + "愉快的玩要");
  };
}
var dog = new Dog("阿黃", 3);
dog["play"](); // 調用方法
console.log(dog["name"]); // 調用屬性
console.log(dog["age"]);
```

屬性名是字符串拼接的狀況

```javascript
// 屬性的字符串拼接
var den = {
  wife1: {name:'xiaoliu'},
  wife2: {name:'xiaozhang'},
  wife3: {name:'xiaowang'},
  sayWife: function (num) {
    return this['wife'+num]
  }
}
console.log(den.sayWife(1)); // {name: "xiaoliu"}
===================================================
  var obj = {
    name:'www',
    age:12,
    sex: 'wrwr'
  }
for (var key in obj){
  console.log(obj.key) // 打印3次undefined 爲何呢?由於執行obj.key至關因而==>obj["key"],這個字符串的key屬性是對象沒有的,因此是undefined
  console.log(obj[key]) // 這樣纔是對的
}
```



### 知識點

+ 對象是一組無序屬性的集合,屬性的值能夠是任意的數據類型

```
function Person(name, age, bool) {
    this.name = name; // 字符串
    this.age = age; // 數字
    this.dog = {name:"阿花", age:18}; // 對象
    this.sex = bool; // 布爾值
    this.play = function () { // 函數
      console.log("喜歡玩遊戲")
    };
  }
  var xiaoMing = new Person("小明", 18, true);
  console.log(xiaoMing.sex?"男":"女"); // 男
  console.log(xiaoMing.dog.name); // 阿花
  
 ============================================
 
```

+ json格式的數據:通常都是成對的,是鍵值對,json也是一個對象,數據都是成對的,通常json格式的數據不管是鍵仍是值都是用雙引號括起來的。

  JSON.parse():string —> json

  JSON.stringify():json —>string

```
var json = {
  "name":"小明",
  "age":18,
  "sex":"男"
}
// 遍歷對象,不單是json,全部的對象都適用
for (var key in json) {
  // console.log(json.key) // 這種是錯誤的,key 是個變量,不是值,在屬性裏沒有,會是undefined,點語法,若是沒有屬性值,會是undefind
  console.log(key + "====" + json[key]);
}
```

+ 判斷一個對象裏有沒有指定屬性

```
// 判斷一個對象裏有沒有指定的屬性
var obj = {
    sex:"男",
    age:18
};
if (obj["sex"]) {
    console.log("有");
}else {
    console.log("沒有");
}
// 有
```

```
// 判斷一個對象裏沒有指定的屬性
var obj = {
    sex:"男",
    age:18
};
function check(key, obj) {
    return obj[key]?true:false;
}
console.log(check("sex", obj)); // true
```

+ 在對象中一個方法調用另外一個方法

```
// 在對象中一個方法調用另外一個方法
    obj = {
        sayHi:function () {
            console.log("sayhi方法");
            this.eat(); // 此時的this就是obj
        },
        eat:function () {
            console.log("eat方法");
        }
    };
```

### 對象的枚舉

#### `for in `

會延伸到原型鏈上的屬性,可是不會打印Object上的東西。

hasOwnProperty(屬性名) ,判斷一個屬性是本身的仍是原型鏈上的,是本身的爲true

```javascript
var obj = {
            name:'www',
            age:12,
            sex: 'wrwr',
            __proto__: {
                lastName:'鄧'
            }
        }
        for (var key in obj){
            // console.log(obj.key) // 打印3次undefined 爲何呢?由於執行obj.key至關因而==>obj["key"],這個字符串的key屬性是對象沒有的,因此是undefined
            if (obj.hasOwnProperty(key)) { // 判斷obj自身有沒有這循環出來的這些屬性,有了纔打印,for in 會延展到原型鏈上,若是不加判斷則會打印出鄧
                console.log(obj[key]) // 這樣纔是對的
            }

        }
```

#### `in`

判斷整個原型鏈上有沒有這個屬性,有就是true,

`"lastName" in obj`則爲true

#### `instanceof`

`A instanceof B` A對象是否是B構造函數構造出來的,其實是看A的原型鏈上有沒有B的原型

```javascript
person instanceof Person // true
person instanceof Object // true
[] instanceof Array // true
[] instanceof Object // true
```

#### 判斷數據的類型

```javascript
// 第一種判斷數組和對象的方法
if ([].constructor === Array){
  console.log('是一個數組');
}
var obj = {};
if (obj.constructor === Object) {
  console.log('是一個對象');
}
// 第二種區分數組和對象的方法
console.log([] instanceof Array ? '是數組':'是對象');
console.log(obj instanceof Array ? '是數組':'是對象');
// toString, 由於函數重寫了toString方法
// Object.prototype.toString = function () {
//     // 識別this
//     // 返回相應的結果
// }
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call(123)); // [object Number]
console.log(Object.prototype.toString.call({})); // [object Object]

通常用的時候用toString,由於在頁面中有iframe子頁面的時候,好比子域裏的數組到父域[] instanceof Array 會是false
```

### 對象的深淺拷貝

#### 淺拷貝

總結起來,淺拷貝就是隻能拷貝原始值,只是拷貝了引用值的指向,因此引用值一個改變也會影響另外一個的改變。

```javascript
obj = {
  name:'abc',
  age:123,
  sex:"female",
  card:['visa', 'unionpay']
};
function clone(origin, target) {
  var target = target || {};
  for (var key in origin) {
    target[key] = origin[key];
  }
  return target
}
var obj1 = {};
clone(obj, obj1);
console.log(obj1);
obj1.card.push('mm') // 修改引用值
console.log(obj); // 另外一個對象中的引用值也會跟着改變
obj1.name = 'bb'; // 修改原始值
console.log(obj) // 另外一個對象中的原始值不會發生改變。
```

#### 深拷貝

```javascript
var obj = {
  name: "abc",
  age: 123,
  card: ["visa", "master"],
  wife: {
    name: "bcd",
    son: {
      name: "aaa"
    }
  }
};
// 1.判斷是否是原始值
// 2.判斷引用值是數組仍是對象
// 3. 創建相應的數組或對象
// 4.遞歸
function deepClone (origin, target) {
  var target = target || {},
      toStr = Object.prototype.toString,
      arrStr = '[object Array]';
  for (var key in origin) {
    if (origin.hasOwnProperty(key)) { // 只拷貝自身的,而不是原型鏈上的
      if (origin[key] !== "null" && typeof(origin[key]) == "object") {
        // 開始判斷是數組仍是對象
        target[key] = toStr.call(origin[key]) == arrStr ? []:{};
        deepClone(origin[key], target[key])
      }else { // 是原始值就直接拷貝
        target[key] = origin[key];
      }
    }
  }
  return target;
}
var obj1 = {};
deepClone(obj, obj1)
```





## 十3、內置對象

對象分爲三種:內置對象、自定義對象、瀏覽器對象

內置對象:系統提供的

自定義對象:本身寫的對象

瀏覽器對象:瀏覽器的

實例對象,經過構造函數建立出來的,實例化的對象;

靜態對象,不須要建立,直接就是一個對象,方法(靜態方法),直接經過這個對象名子調用。

實例方法必須經過實例化後的對象調用的;對象.方法();

靜態方法必須經過大寫的構造函數這樣的調用的方式調用的;構造函數.方法()

### (一)Math

Math 是一個內置對象,具備數學常數和函數的屬性和方法,不是一個構造函數,全部的屬性和方法都是靜態的。

#### Math 對象屬性

| 屬性                                                         | 描述                                              |
| :----------------------------------------------------------- | :------------------------------------------------ |
| [E](http://www.w3school.com.cn/jsref/jsref_e.asp)            | 返回算術常量 e,即天然對數的底數(約等於2.718)。 |
| [LN2](http://www.w3school.com.cn/jsref/jsref_ln2.asp)        | 返回 2 的天然對數(約等於0.693)。                |
| [LN10](http://www.w3school.com.cn/jsref/jsref_ln10.asp)      | 返回 10 的天然對數(約等於2.302)。               |
| [LOG2E](http://www.w3school.com.cn/jsref/jsref_log2e.asp)    | 返回以 2 爲底的 e 的對數(約等於 1.414)。        |
| [LOG10E](http://www.w3school.com.cn/jsref/jsref_log10e.asp)  | 返回以 10 爲底的 e 的對數(約等於0.434)。        |
| [PI](http://www.w3school.com.cn/jsref/jsref_pi.asp)          | 返回圓周率(約等於3.14159)。                     |
| [SQRT1_2](http://www.w3school.com.cn/jsref/jsref_sqrt1_2.asp) | 返回返回 2 的平方根的倒數(約等於 0.707)。       |
| [SQRT2](http://www.w3school.com.cn/jsref/jsref_sqrt2.asp)    | 返回 2 的平方根(約等於 1.414)。                 |

#### Math 對象方法

| 方法                                                         | 描述                                                         |
| :----------------------------------------------------------- | :----------------------------------------------------------- |
| [abs(x)](http://www.w3school.com.cn/jsref/jsref_abs.asp)     | 返回數的絕對值。                                             |
| [acos(x)](http://www.w3school.com.cn/jsref/jsref_acos.asp)   | 返回數的反餘弦值。                                           |
| [asin(x)](http://www.w3school.com.cn/jsref/jsref_asin.asp)   | 返回數的反正弦值。                                           |
| [atan(x)](http://www.w3school.com.cn/jsref/jsref_atan.asp)   | 以介於 -PI/2 與 PI/2 弧度之間的數值來返回 x 的反正切值。     |
| [atan2(y,x)](http://www.w3school.com.cn/jsref/jsref_atan2.asp) | 返回從 x 軸到點 (x,y) 的角度(介於 -PI/2 與 PI/2 弧度之間)。 |
| [ceil(x)](http://www.w3school.com.cn/jsref/jsref_ceil.asp)   | 對數進行上舍入。                                             |
| [cos(x)](http://www.w3school.com.cn/jsref/jsref_cos.asp)     | 返回數的餘弦。                                               |
| [exp(x)](http://www.w3school.com.cn/jsref/jsref_exp.asp)     | 返回 e 的指數。                                              |
| [floor(x)](http://www.w3school.com.cn/jsref/jsref_floor.asp) | 對數進行下舍入。                                             |
| [log(x)](http://www.w3school.com.cn/jsref/jsref_log.asp)     | 返回數的天然對數(底爲e)。                                  |
| [max(x,y)](http://www.w3school.com.cn/jsref/jsref_max.asp)   | 返回 x 和 y 中的最高值。                                     |
| [min(x,y)](http://www.w3school.com.cn/jsref/jsref_min.asp)   | 返回 x 和 y 中的最低值。                                     |
| [pow(x,y)](http://www.w3school.com.cn/jsref/jsref_pow.asp)   | 返回 x 的 y 次冪。                                           |
| [random()](http://www.w3school.com.cn/jsref/jsref_random.asp) | 返回 0 ~ 1 之間的隨機數。                                    |
| [round(x)](http://www.w3school.com.cn/jsref/jsref_round.asp) | 把數四捨五入爲最接近的整數。                                 |
| [sin(x)](http://www.w3school.com.cn/jsref/jsref_sin.asp)     | 返回數的正弦。                                               |
| [sqrt(x)](http://www.w3school.com.cn/jsref/jsref_sqrt.asp)   | 返回數的平方根。                                             |
| [tan(x)](http://www.w3school.com.cn/jsref/jsref_tan.asp)     | 返回角的正切。                                               |
| [toSource()](http://www.w3school.com.cn/jsref/jsref_tosource_math.asp) | 返回該對象的源代碼。                                         |
| [valueOf()](http://www.w3school.com.cn/jsref/jsref_valueof_math.asp) | 返回 Math 對象的原始值。                                     |

### (二)Date

```
// 建立一個Date的實例化對象(不傳參)
var date = new Date();
console.log(date);
// 獲取時間戳
console.log(date.getTime())
// 傳入參數
var date1 = new Date("2000-5-4")
console.log(date1);
// 獲取年份
console.log(date.getFullYear());
// 獲取月份
console.log(date.getMonth() + 1);//是從0開始的,真實的須要加1
// 獲取日期
console.log(date.getDate());
// 獲取時
console.log(date.getHours());
// 獲取分
console.log(date.getMinutes());
// 獲取秒
console.log(date.getSeconds());
// 獲取星期
console.log(date.getDay()); // 週日是0,依此類推
// 英文的日期的字符串
console.log(date.toDateString());
// 數字的日期的字符串
console.log(date.toLocaleDateString());
// 英文的時間的字符串
console.log(date.toTimeString());
// 中文的時間的字符串
console.log(date.toLocaleTimeString());
```

```
// 格式化日期輸出「2018年11月15日 11:23:23」
/** 檢查月、日、時、分、秒是否是大於0
* @param num 日期的數字
* @returns {string} 返回的是清洗後的數字
*/
function checkDate(num) {
    return num>10?num:"0"+num;
}
/** 返回指定格式的日期字符串
* @param date 日期對象
* @returns {string} 返回的是字符串
*/
function formatDate(date) {
    // var date = new Date(); // 能夠直接向函數傳一個對象的參數
    //年
    var y = date.getFullYear();
    //月
    var m = checkDate(date.getMonth() + 1); // 月份是從0開始的,因此要加1
    //日
    var d = checkDate(date.getDate());
    //時
    var h = checkDate(date.getHours());
    //分
    var M = checkDate(date.getMinutes());
    //秒
    var s = checkDate(date.getSeconds());
    var str = y+"年"+ m +"月"+d+"日" + h +":"+M+":"+ s;
    return str;
}
console.log(formatDate(new Date())); // 能夠直接向函數傳一個對象的參數
```

```
// 毫秒值轉成日期對象
var date = new Date();
console.log(date.valueOf()) // 獲得毫秒數 1546436676284
var dt = new Date(date.valueOf());
console.log(dt);
```

### (三)String

String是一個對象,字符串能夠當作是字符組成的數組,可是JS中沒有字符類型,字符是一個一個的,在別的語言中是用單引號括起來的,在JS中字符串能夠使用單引號或者雙引號,由於字符串能夠當作是數組,因此能用for循環進行遍歷。

字符串的特性:不可變性。單獨寫是基本的數據類型(棧)經過new構造函數的方式建立的是引用類型(堆 棧)javascript會將基本的數據類型的字符串轉化爲字符串對象,來使用字符串對象的方法。

字符串的從新賦值,看起來是字符串發生改變了,其實是指向改變了,並非值改變了,原來的值還在內存中。

```
// 建立一個字符串的對象,兩種方法:一是字面量,第二種系統構造函數建立對象
var str = "小明好帥abc";
var str1 = new String('今天是個好天氣');
// 字符串對象的屬性
var len = str.length;
console.log(len); // 7
// **** 一、字符方法
// charAt() 返回指定位置的字符
console.log(str.charAt(2)); // 好
// charCodeAT() 返回指定位置的unicode編碼
console.log(str.charCodeAt(4));
// **** 二、字符串的操做方法
// concat 和字符串的拼接+ 同樣,比+更經常使用
console.log(str.concat(str1, "哈哈")); // 小明好帥abc今天是個好天氣哈哈
// slice 從strat位置截取字符串的片段,直到end end 截取不到,一個參數一直截取到最後,不支持反截取
console.log(str.slice(2)); // 好帥abc
console.log(str.slice(2, 4)); // 好帥
console.log(str.slice(2, -2)); // 好帥a
console.log(str.slice(4, 2)); // 空 截取不到
// substring() 功能和slice同樣,不同的是不支持負數索引值,可是支持反截取
console.log(str.substring(2, -2)); // 小明 不支持負數索引,會從0位置截取
console.log(str.substring(2, 4)); // 好帥
console.log(str.substring(4, 2)); // 好帥
// substr() 從開始的位置截取長度爲幾個的字符串 第一個參數是開始的位置,第二個參數爲截取的長度,只寫一個參數,從開始一直到結束
console.log(str.substr(3, 1)); // 帥
// **** 三、位置方法
// indexOf() 返回指定內容在字符串中的位置,找不到則返回-1,第二個參數是從第幾個索引開始找
console.log(str.indexOf("帥")); // 3
console.log(str.indexOf("帥", 5)); // -1
// lasttIndexOf() 從右往左找返回指定內容在字符串中的位置,找不到返回-1,第二個參數無心義
console.log(str.lastIndexOf("帥")); // 3
console.log(str.lastIndexOf("帥", 5)); // 3
// **** 四、去除空白
// trim() 只能是去除字符串兩端的空格,不能去除中間的
console.log("   abess   ".trim());
// **** 五、大小寫轉換方法
// 小寫轉大寫
console.log(str.toUpperCase()); // 小明好帥ABC
console.log(str.toLocaleUpperCase()); // 小明好帥ABC
// 大寫轉小寫
console.log("SFSFS".toLocaleLowerCase()); // sfsfs
console.log("SAADAD".toLowerCase()); // saadad
// **** 六、與正則相關的
// split() 把一個字符串分隔成字符串數組 第一個參數,正則表達式或者是分隔符,第二個參數分隔後數組的長度
console.log("wsf|sfsw|sfwrr|wwrw|www".split('|')); // ["wsf", "sfsw", "sfwrr", "wwrw", "www"]
// replace 替換 第一個參數是被替換的內容或是regexp 正則對象, 第二個參數是新的內容
console.log(str.replace("帥", "醜")); // 小明好醜abc
console.log("123,321,456".replace(',', '')); // 123321,456 只會替換第一個不是全局的
console.log("123,321,456".replace(/,/g, '')); // 123321456
// search() 查找指定內容或正則表達式的索引,找不到返回-1,
console.log(str.search("帥")); // 3
```

案例:

```
// 截取指定的字符串
var str = "我喜歡村裏的小芳";
var key = "小芳";
var index = str.indexOf(key);
str = str.slice(index, index+key.length);
console.log(str);
```

```
// 找到字符串中全部o的位置
var str = "wrwrowrowrsfsfowrsfsfwosfsfosfwosfwwowrwo";
var key = "o";
var index = 0;
while ((index = str.indexOf(key, index))!= -1) { /* 先算等號右邊的,若是index不等於-1,
    就循環查找,本次查找到的索引值做爲下一次查找的開始位置 */
    console.log(index);
    index += key.length; // 不加上查找字符串的長度,會成爲死循環
};

// 將上述代碼封裝成函數
function finedStr(str, key) {
    var index = 0;
    while ((index = str.indexOf(key, index)) != -1) {
        console.log(index);
        index += key.length;
    }
}
var str1 = "wsfpsfwpsfwpsfwpsfsp"
console.log(finedStr(str1, "p"));
```

```
// 找出字符串的每一個字母出現了多少次
var str = "ooouwrosiQWiadWooiuQWWueyrREwq";
// 第一步先將字符串所有變爲大寫或小寫
str = str.toLowerCase();
// 建立一個空對象,目的爲了存儲每一個字母的次數
var obj = {};
// 循環遍歷字符串,獲取每一個字母
for (var i=0; i<str.length; i++) {
    // 獲得每一個字母,把字母做爲對象的鍵
    var key = str[i];
    // 判斷對象裏沒有這個鍵
    if (obj[key]){
        obj[key] ++; // 有的話就加1
    }else {
        obj[key] = 1; // 沒有的話就把這個字母做爲鍵值爲1,存到對象中
    }
}
// 循環對象,獲得每一個字母的次數
for (var key in obj) {
    console.log(key+"出現了"+ obj[key] +"次");
}


// 將上面的代碼封裝成函數
function finedCount(str) {
    var obj = {};
    // 先轉換爲小寫
    str = str.toLowerCase();
    // 循環遍歷字符串取到每一個字母
    for (var i=0; i<str.length; i++) {
        key = str[i]; // 獲得每一個字母
        obj[key]?obj[key]++:obj[key]=1;
    }
    return obj;
}
function ouptCount(obj) {
    for (var key in obj) {
        console.log(key+"出現了"+obj[key]+"次");
    }
}
var str="sfwwrpqpruqeiwpruw";
var obj = finedCount(str);
ouptCount(obj);
```

### (四)Array

+ 判斷變量是否是數組類型兩種方式

一、instanceof

二、使用數組的靜態方法Array.isArray()方法

```
/* 判斷變量是否是一個數組
一、instanceof */
var obj = [];
console.log(obj instanceof Array); // true
// 二、使用數組的靜態方法Array.isArray()
console.log(Array.isArray(obj)); // true
```

+ 經常使用的一些方法
+ 改變原數組的:push, pop, shift, unshift, sort, reverse, splice
+ 不改變原數組:concat, (join —可逆> split),toString, slice

```javascript
// 數組的方法
var arr1 = [1, 2, 3, 45, 6];
// 一、Array.from()將一個可迭代對象,轉換爲數組, 不改變原有的,返回一個新的數組
console.log(Array.from(arr1)); // [1, 2, 3, 45, 6]
console.log(Array.from("abcedf")); // ["a", "b", "c", "e", "d", "f"]
// 二、concat() 合併多個數組,不修改原來的,返回一個新的數組,不會去重
console.log(arr1.concat([7, 8, 9])); // [1, 2, 3, 45, 6, 7, 8, 9]
console.log(arr1.concat([1, 2, 3, 7])); //  [1, 2, 3, 45, 6, 1, 2, 3, 7]
// 二、every(callback 回調函數) 測試數組中的全部的元素是否經過了指定函數的測試
// 函數做爲參數使用,總體返回boolean值是and的關係,函數中有三個參數,第一個是元素的值,第二個
// 參數是元素的索引值,第三個參數是調用方法的數組(通常沒用) 不用能夠不寫
var flage = arr1.every(function (ele, index) {
    return ele > 2;
});
console.log(flage); // false
// 三、filter(函數) 參數是一個回調函數,經過回調函數,過濾數組中的每一個元素,把符合條件的元素,組成一個新的數組,返回
// 函數有三個參數,第一個是元素的值,第二個是元素的索引,第三個是調用方法的數組,不用不以不寫
var newArry = arr1.filter(function (ele) {
    return ele > 5;
});
console.log(newArry); // [45, 6]
// 四、forEach() 遍歷數組,至關於for 循環,數組的每個元素都執行一次回調函數
// 函數有三個參數,第一個是元素的值,第二個是元素的索引,第三個是調用方法的數組,不用不以不寫
var arr1 = [1, 2, 3, 45, 6];
arr1.forEach(function (ele, index) {
    console.log(ele + "====" + index);

});
/*
1 ====0
2 ====1
3 ====2
45 ====3
6 ====4
*/
// 五、map(函數) 數據中的每一個元素都要執行一次回調函數,把新的值組成一個新的數組,並返回
// 函數有三個參數,第一個是元素的值,第二個是元素的索引,第三個是調用方法的數組,不用不以不寫
var arr1 = [1, 2, 3, 45, 6];
var newArr = arr1.map(function (ele, index) {
    return ele += 3;
});
console.log(newArr); // [4, 5, 6, 48, 9]
// 六、push() 追加元素 原地修改 返回新數組長度,不去重
var arr2 = [1, 2, 3];
console.log(arr2.push(3)); // 4
console.log(arr2); //  [1, 2, 3, 3]
// 七、unshift() 向數組的第一個元素前面插入一個新的元素 原地修改,返回新數組長度,不去重
var arr2 = [1, 2, 3];
console.log(arr2.unshift(3)); // 4
console.log(arr2); //  [3, 1, 2, 3]
// 八、pop() 刪除最後一個元素或者指定的元素, 原地修改,返回被刪除的元素,
var arr2 = [1, 2, 3, 'aa'];
console.log(arr2.pop("aa")); // aa
console.log(arr2); // [1, 2, 3]
console.log(arr2.pop()); // 3
console.log(arr2); // [1, 2]
// 九、shift() 刪除數組中的第一個元素,不能刪除指定的元素,原地修改,返回被刪除的元素
var arr2 = [1, 2, 3, 'aa'];
console.log(arr2.shift("aa")); // 1 刪除指定的元素,失敗
console.log(arr2); // [2, 3, "aa"]
console.log(arr2.shift()); // 2
console.log(arr2); // [3, "aa"]
// 十、reverse 翻轉數組,原地修改,返回排序後的數據
var arr2 = [1, 2, 3, 'aa'];
console.log(arr2.reverse()); // ["aa", 3, 2, 1]
console.log(arr2); // ["aa", 3, 2, 1]
// 十一、sort(排序函數) 數組排序 原地修改,返回排序後的數據
// 不寫函數不穩定,回調函數的第一個參數至關於arr[j], 第二個參數至關於arr[j+1]
// 規則: 一、必須寫兩個參數 二、看返回值:(1)當返回值爲負數時,那麼前面的數放在前面;(2)爲正數,那麼後面的數
// 在前;(3)爲0,不動。
var arr2 = [3, 4, 2, 8, 9, 10, -1];
console.log(arr2.sort(function (a, b) {
    if (a > b) {
        return 1;
    } else if (a == b) {
        return 0;
    } else {
        return -1;
    }
    // 簡化版的
    // return a-b
})); // 不寫回調函數結果是[-1, 10, 2, 3, 4, 8, 9] ,寫了回調函數 [-1, 2, 3, 4, 8, 9, 10]
console.log(arr2); // 不寫回調函數結果是[-1, 10, 2, 3, 4, 8, 9] 寫了回調函數 [-1, 2, 3, 4, 8, 9, 10]
// 十二、indexOf() 返回指定元素的索引,第二參數,查找的起始位置,找不到返回-1
var arr = [1, 2, 2, 2, 3, 4];
console.log(arr.indexOf(2)); // 1
console.log(arr.indexOf(2, 3)); // 3
console.log(arr.indexOf(500)); // -1
// 1三、lastIndexOf 從右往左,返回指定元素的索引,找不到返回-1
var arr = [1, 2, 2, 2, 3, 4];
console.log(arr.lastIndexOf(2)); // 3
console.log(arr.lastIndexOf(2, 2)); // 2
console.log(arr.lastIndexOf(500)); // -1
// 1四、join 將數組按指定的元素組成一個新的字符串,返回
var arr = [1, 2, 3, 4, 5];
console.log(arr.join(":")); // 1:2:3:4:5
// 1五、selice() 淺拷貝從參數(開始索引到結束索引之間的元素,不包括結束索引),組成一個新的數據 返回,原數組不變,不傳參數就是拷貝整個數組
var arr = [1, 2, 3, 4, 5];
console.log(arr.slice(1, 3)); // [2, 3]
console.log(arr.slice(3)); // [4, 5]
console.log(arr); // [1, 2, 3, 4, 5]
// 1六、splice(開始的位置,要刪除的個數, 替換的元素值) 通常用於刪除數組中的元素,或者是替換元素,或者是插入元素
// 替換返回的是[]空列表,刪除返回的是刪除的元素組成的列表
var arr = [1, 2, 3, 4, 5];
console.log(arr.splice(3, 0, 'deue')); // [] 在任意位置插入元素
console.log(arr); // [1, 2, 3, "deue", 4, 5]
var arr = [1, 2, 3, 4, 5];
console.log(arr.splice(2, 2)); // [3, 4]
console.log(arr); // [1, 2, 5]
```

技巧:

```
// 清空一個數組
var arr = [1, 2, 3, 4, 5];
arr.length = 0;
console.log(arr); // []
```

### (五)包裝類

基本包裝類型

+ 普通變量不能直接調用屬性或者方法;
+ 對象能夠直接調用屬性和方法;

**基本包裝類型:自己是基本類型,可是在執行代碼的過程當中,若是這種類型的變量調用了屬性或者是方法,那麼這種類型就再也不是基本類型了,而是基本包裝類型,這個變量也再也不是普通的變量了,而是基本包裝類型對象 **

string number boolean 是基本類型,也是基本包裝類型

```javascript
var str = "hello";
str = str.replace("ll", "HH"); // 基本數據類型調用了方法
console.log(str); // heHHo 這個時候,str就再是基本數據類型了,而是基本包裝類型對象

var num = 10; // 原來是基本數據類型
console.log(num.toString()); // 10 調用了方法,那麼如今就是基本包裝類型了

規律:
若是是一個對象&&true,那麼結果是true;
若是 是一個true&&對象,那麼結果是對象;

var flag = new Boolean(false);
var result = flag && true;
console.log(result); // true

var flag = new Boolean(false);
var result = true && flag;
console.log(result); // Boolean

var num = 10;
var num2 = Number("10") // 類型轉換,仍是基本數據類型,沒有new
var num3 = new Number("10"); // 基本包裝類型

var str = "hello";
str.li = "ee";
console.log(str.li); // undefined; 由於str在調用屬性的時候,至關因而調用了new String("hello") 包裝成了引用類型,而後添加了屬性,當執行log的時候,又至關是再次調用了new String("hello")的方法,而這個新的對象裏是沒有li的屬性的。
```



# Web API

## 1、API相關的概念

** 什麼是API **

API是一些預先定義的函數,目的是提供應用程序與開發人員基於某軟件或硬件得以訪問一組例程的能力,而又無需訪問源碼,或理解內部工做機制的細節。

+ 任何開發語言都有本身的api
+ API的特徵輸入和輸出
+ API的使用方法(console.log())

** 什麼是WEB API **

瀏覽器提供一套操做瀏覽器功能和頁面的API(BOM和DOM)

## 2、DOM

DOM 就是把頁面當作是一個文檔,學習DOM就是學習操做文檔裏的元素。DOM又稱爲文檔樹模型

DOM樹:把html頁面或者是xml文件當作是一個文檔,文檔就是一個對象,這個文檔中全部的標籤都是元素,元素也能夠當作是對象,標籤(元素、對象)有不少,還有嵌套關係組成的這種層次結構,能夠模擬成樹形結構圖,簡稱:樹狀圖,就是dom樹

DOM對象:經過DOM方式獲取的元素獲得的對象

文檔 一個網頁能夠稱爲文檔

節點(node):頁面中全部的內容都是節點(包括標籤、屬性、文本(文字、換行、空格、回車)、註釋等)

元素(elementt):頁面中全部的標籤都是元素,元素能夠當作是對象。

根元素:html標籤

頁面中的頂級對象:document 

屬性 標籤的屬性


HTML文件是用來展現信息,展現數據的
XML:側重於存儲數據

HTML 文件當作是一個文檔(document),把這個文檔也能夠當作是一個對象,文檔中全部的標籤均可以當作是一個對象

### DOM結構樹(繼承關係)

![dom結構樹](/Users/mengjuncheng/Documents/notes/前端/javascript筆記/media/dom結構樹.png)

DOM結構樹上相關聯的有這個繼承的關係,例如在`HTMLElement.abc=123`,那麼在它的分支下的任何一個擁有繼承關係的分支上,都會有這個屬性。好比在頁面中選中一個元素,那麼這個元素身上也有abc=123這個屬性。

`document.__proto__` ==> `HTMLDocument`  `HTMLDocument.__proto__`  ==>`Document` `Document.__proto__` ==> `Node`  `Node.__proto__`==> `EventTarget` `EventTarget.__proto__` ==>`Object`

## 3、DOM 常見的操做

+ 獲取元素
+ 動態建立元素
+ 對元素進行操做(設置其屬性或調用其方法)
+ 事件(什麼時機作相應的操做)

一、`getElementByid`方法定義在`Document.prototype`上,即`Element`節點上不能使用。

二、`getElementsByName`方法定義在`HTMLDocument.prototype`上,即非`html`中的`document`不能使用(`xml documentElement`)

三、`getElementsByTagName`方法定義在`Document.prototype`和`Element.prototype`上,換句話說就是獲取到的元素能夠繼續調用`getElementsByTagName`這個方法。

四、`HTMLDocument.prototype`定義了一些經常使用的屬性,`body.head`分別指代`HTML`文檔中的`<body><head>`標籤

五、`Document.prototype`上定義了`documentElement`屬性,指代文檔的根元素,在`HTML`文檔中,他老是指代 `<html>`元素。

六、`getELementsByClassName`、`querySelectorAll`、`querySelector`在`Docuement.prototype`,`Element.prototype`類中均有定義。



###  獲取頁面元素的方法 

除了id,其餘的選擇器取出來的都是一組的,基本上所有是類數組

一、根據id屬性獲取元素 返回的是一個元素對象 getElementById("id")

二、根據標籤名獲取元素 返回的是元素對象組成的僞數組 getElementsByTagName("標籤的名子")

下面的幾個,有的瀏覽器不支持

三、根據表單的name屬性獲取元素,返回的是元素對象組成的一個僞數組
getElementsByName("name屬性") 

```
<body>
<input type="button" value="更改value值" id="btn">
<input type="text" name="name1" value="我很好"> <br/>
<input type="text" name="name2" value="我很好"> <br/>
<input type="text" name="name1" value="我很好"> <br/>
<input type="text" name="name3" value="我很好"> <br/>
<input type="text" name="name3" value="我很好"> <br/>
<script >
    // 根據表單的name屬性獲取元素 把name是1的獲取出來
    document.getElementById("btn").onclick = function () {
        // document.getElementsByName("name屬性值")是根據表單的name屬性獲取元素,返回的也是一個僞數組
        var nameList = document.getElementsByName("name1");
        for (var i=0; nameList.length; i++) {
            nameList[i].value = "你好呀";
        }
    };
</script>
</body>
```

四、根據類樣式的名子來獲取元素,返回的是元素對象組成的僞數組 getElementsByClassName("類名子")

```
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div {
            width: 100px;
            height: 100px;
            background-color: #f40;
        }
        span {
            display: block;
            width: 100px;
            height: 100px;
            background-color: yellow;
        }
    </style>
</head>
<body>
<div class="cls">這是第一個div</div>
<div class="cls">這是第二個div</div>
<span class="cls">span</span>
<input type="button" value="變顏色" id="btn">
<script src="./common.js"></script>
<script >
    // 根據類樣式獲取元素 注意ie8及如下都不支持
    my$("btn").onclick = function () {
        // document.getElementsByClassName("類樣式名子") 根據類樣式獲取元素,返回的也是一個僞數組
        var classList = document.getElementsByClassName("cls");
        for (var i=0; i<classList.length; i++) {
            classList[i].style.backgroundColor="pink";
        }
    };

</script>
</body>
```

五、根據css選擇器獲取元素,返回來的是一個元素對象 querySelector("選擇器名字"),並不經常使用,選擇出來的東西不是時事的

六、根據css選擇器獲取元素,返回的是元素對象組成的僞數組 querySelectorAll("選擇器的名字")

## 4、事件 

事件的三要素

+ 事件源:被觸發事件的元素

+ 事件類型:事件的觸發方法(如鼠標通過、鼠標點擊)

  * 鼠標事件

  click(點擊)、mousedown(鼠標按下),mouseup(鼠標擡起),一個鼠標的click點擊事件分開來看就是是先down,再up,造成一個click事件。

  mousemove:鼠標移動事件

  contextmenu:鼠標右鍵產生菜單事件。

  mouseover進入,mouseout離開,mouseenter、mouseleave

  - mouseover和mouseout在父元素和其子元素均可以觸發,當鼠標穿過一個元素時,觸發次數得依子元素數量而言。
  - mouseenter和mouseleave只在父元素觸發,當鼠標穿過一個元素時,只會觸發一次。
  - mouseover和mouseout比mouseenter和mouseleave先觸發

  所以通常mouseover和mouseout一塊兒使用,mouseenter和mouseleave一塊兒使用,

  必須是事件mousedown和mouseup事件來判斷,用事件參數對象button的屬性值來區分鼠標的左右鍵:0/1/2,左/中鍵/右鍵,click事件只能監聽左鍵。

  * 鍵盤事件

    * 和鼠標的click事件不同,keydown+ keyup  != keypress,

    * keydown>keypress>keyup

    * keydown和keypress的區別

      * keydown的事件參數參數對象的charCode屬性值爲0,而keypress的charCode是每一個字母的ASCII碼,而兩個的which都有值,對應的是每一個鍵的值,可是大小寫也是同樣的,因此字符用keypress,而操做類的用keydown.

      * keydown能夠響應任意鍵盤按鍵,keypress只可響應字符類鍵盤按鍵
      * keypress返回ASCII碼,能夠轉換成相應字符。

  * 文本操做事件

    * input(輸入一次觸發一次),change(鼠標聚焦,與失去聚點,兩次input的value值發生改變時才觸發)
    * focus得到焦點觸發, blur失去焦點後觸發, 

  * 窗休操做類(window上的事件)

    * scroll 頁面滾動條發生滾動觸發
    * load 整個文檔解析完畢後才觸發,效率低。

+ 事件的外理程序:事件觸發後要執行的代碼(函數形式)

點擊操做: 就是一個事件。

事件:就是一件事,好比 按鍵被點擊,彈出對話框,點擊就是事件的名子

觸發:被點了,就是觸發了

響應:彈框了就是響應

事件源:按鍵就是事件源

事件綁定的特性 一但綁定 這個元素 就一直有這個事件了,即便事件中修改了這個元素的id,事件也會繼續有這個事件。

事件源對象:event.target 火狐只有這個,event.srcElement ie只有這個,這兩個chrome都有

`var target = event.target || event.srcElement;`

事件參數對象:window.event和e都是事件參數對象,一個是Ie的標準,一個是火狐的標準,事件參數e在ie8的瀏覽器中是不存在,此時用window.event來代替。`var event = e ||window.event;`

事件委託:經過事件的冒泡把子元素的事件傳傳遞給父元素,父元素再經過事件源對象操做每一個子元素

優勢:一、性能不須要循環全部的元素一個個綁定事件

​	    二、靈活,當有新的子元素時不須要從新綁定事件。

```javascript
<ul>
	<li>1</li>
	<li>2</li> 
	<li>3</li>
	<li>4</li>
	<li>5</li>
	<li>6</li>
</ul>
<script>
	var ul = document.getElementsBytagName('ul')[0];
ul.onclick = function (e) {
  var event = e || window.event;
  var target = event.target || event.srcElement;
  console.log(target.innerText);
}
</script>
```

(一)點擊事件 onclick

```
<!--第一種方法彈框--沒有把html和js分離-->
<input type="button" value="按鍵1" onclick="alert('彈出1')">
<!--第二種方法彈框--只是把js代碼封裝在函數內,仍是沒有真正意義上的分離-->
<!--標籤內屬性的值是由引號包裹的,表明點擊元素時,執行引號裏的代碼,會把引號裏的代碼拿出來跑,若是函數不加括號,函數就不會執行,因此這裏的函數要加括號-->
<input type="button" value="按鍵2" onclick="f1()">
<!--第三種方法-->
<input type="button" value="按鍵3" id="btn">
<!--最終版-->
<input type="button" value="按鍵4" id="btn2">
<script >
    // 第二種方法js
    function f1() {
        alert("彈出2");
    }
</script>
<script >
    // 第三種方法js
    function f2() {
        alert("彈出3");
    }
   /* html標籤中的id屬性中存儲的值是惟一的,id屬性就像人的身份證號同樣,不能重複,頁面中惟一的標識,從文檔中找到id值爲btn的這個標籤(元素)
   * document.getElementById("id屬性的值") 返回的是一個元素對象,若是出如今了html代碼的前面,會找不到而報錯。
   * */
   // 根據id屬性的值從整個文檔中獲取這個元素(標籤)
    var btnObj = document.getElementById("btn");
    // 爲當前找到的這個按鈕元素(對象)註冊點擊事件 ,添加事件處理函數
    /*這裏的函數不能加括號,加上括號是執行的意思,頁面加載到這個地方會直接執行了函數,添加事件的回調函數應該就是給相應的事件屬性賦值,而很明顯須要把一個函數賦值給這個事件屬性,而不是函數的調用結果。因此在js中的綁定是直接賦值。*/
    btnObj.onclick = f2; // 這個方法有個缺陷,就是若是從別的文件中引入的js文件中正好有個f2文件出現了重名的狀況,後面的會把前面的覆蓋了
</script>
<script >
    // 最終版js
    // 根據id屬性的值從整個文檔中獲取這個元素(標籤)
    var btn1Obj = document.getElementById("btn2");
    // 爲當前的這個按鈕(元素)註冊點擊事件,添加事件處理函數
    btn1Obj.onclick = function () { // 這是匿名函數就不會出現名子衝突的狀況了
      // 響應作的事
        alert("最終版的彈框");
    }
</script>
```

(二)鼠標進入和移出事件 onmouseover進入 onmouseout 移出

案例一:鼠標進入離開列表高亮顯示

```
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        ul {
            list-style: none;
        }
    </style>
</head>
<body>
<ul id="uu">
<li>五菱神車</li>
<li>五菱神車</li>
<li>五菱神車</li>
<li>五菱神車</li>
<li>五菱神車</li>
<li>五菱神車</li>
<li>五菱神車</li>
<li>五菱神車</li>
</ul>
<script src="./common.js"></script>
<script >
    // 鼠標進入li高亮顯示,離開後恢復原樣
    // 鼠標進入和鼠標離開是兩個事件
    // 先經過id 獲取到ul元素,再經過標籤把li選中,放到一個僞數組內
    var liList = my$("uu").getElementsByTagName("li");
    // 循環這個列表
    for (var i=0; i<liList.length; i++) {
        // 註冊鼠標進入事件
        liList[i].onmouseover = function () {
            this.style.backgroundColor = "red";
        };
        // 註冊鼠標離開事件
        liList[i].onmouseout = function () {
            this.style.backgroundColor = "";
        };
    }
</script>
</body>
```

案例二:鼠標進入和移出顯示二維碼

事件響應代碼中添加和移除類名的方式,顯示或隱藏,注意多個類名的時候,要把以前的也要從新寫上

```
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        .nodeSmall {
            width: 50px;
            height: 50px;
            background: url(../images/bgs.png) no-repeat -159px -51px;
            position: fixed;
            right: 10px;
            top: 40%;
        }
        .erweima {
            position: absolute;
            top: 0;
            left: -150px;
        }
        .nodeSmall a {
            display: block;
            width: 50px;
            height: 50px;
        }
        .hide {
            display: none;
        }

        .show {
            display: block;
        }
    </style>


</head>
<body>
<div class="nodeSmall" id="node_small">
    <a href="#"></a><!--錨定-->
    <div class="erweima hide" id="er">
        <img src="../images/456.png" alt=""/>
    </div>
</div>
<script src="./common.js"></script>
<script >
    // 鼠標進入時a標籤時,讓id是er的類樣式改成show,移出爲hide
    // 先根據id 獲取元素div,而後根據標籤名獲取a
    var aObj = my$("node_small").getElementsByTagName("a")[0];
    // 爲元素a註冊鼠標進入事件 添加事件處理函數
    aObj.onmouseover = function () {
        my$("er").className = "erweima show";
    };
    // 爲元素a註冊鼠標移出事件 添加事件處理函數
    aObj.onmouseout = function () {
        my$("er").className = "erweima hide";
    };
</script>

</body>
```

案例三:鼠標通過高亮顯示邊框 

注意,因爲border會增長盒子的大小,鼠標通過時會顯示跳,影響下面的佈局,因此先在css裏設置好邊框大小,顏色和背景同樣,鼠標通過時只改邊框顏色就能夠了

```
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
       div {
           width: 900px;
           margin: 20px auto;
           text-align: center;
       }
        ul>li {
            list-style: none;
            width: 150px;
            height: 150px;
            background-color: #ccc;
            float: left;
            margin-left: 10px;
            border: 2px solid #ccc;
        }
    </style>
</head>
<body>
<div>
    <ul>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
    </ul>
</div>
<script >
    // 根據標籤名獲取全部li元素僞數組
    var tagList = document.getElementsByTagName("li")
    // 循環數組,拿到每一個li元素,爲每一個元素註冊鼠標通過事件
    for (var i=0; i<tagList.length; i++) {
        // 鼠標進入事件
        tagList[i].onmouseover = function () {
            this.style.borderColor = "#f40";
        };
        // 鼠標離開事件
        tagList[i].onmouseout = function () {
            this.style.borderColor = "#ccc";
        };
    }
</script>
</body>
```

(三)焦點事件 

進入焦點:onfocus 失去焦點:onblur

案例一:模擬搜索框焦點事件

```
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        input {
            width: 200px;
            height: 30px;
            color: #ccc;
            outline: none;
        }
    </style>
</head>
<body>
<input type="text" value="請輸入內容">
<script >
    // 根據標籤名獲取到input元素
    var inpuObj = document.getElementsByTagName("input")[0];
    // 註冊獲取焦點事件 onfocus
    inpuObj.onfocus = function () {
        // 判斷輸入框是不是默認值
        if (this.value == "請輸入內容") {
            this.value="";
            this.style.color = "black"
        }
    }
    // 註冊失去焦點事件 onblur
    inpuObj.onblur = function () {
        // 判斷用戶有沒有輸入,這裏也能夠寫this.value == "",可是效率沒有數字的高
        if (this.value.length == 0) {
            this.value = "請輸入內容";
            this.style.color = "#ccc";
        }
    };
</script>
</body>
```

案例二:驗證密碼長度

```
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        input {
            width: 200px;
            height: 20px;
            outline: none;
            /*border: 1px solid ;*/
        }
    </style>
</head>
<body>
<input type="text" value="">
<script >
    // 根據標籤名獲取到元素input, 註冊失去焦點事件,添加事件處理函數
    document.getElementsByTagName("input")[0].onblur = function () {
        // 判斷密碼長度大於等於6小於等於10
        if (this.value.length >= 6 && this.value.length <= 10) {
            this.style.border = "2px solid green"
        } else {
            this.style.border = "2px solid red";
        }
    };

</script>
</body>
```

## 5、操做屬性

能對屬性進行賦值,也能夠經過屬性拿對對應的值

### (一)非表單元素的屬性

href、 title 、id、 src、 className 

案例一:點擊按鈕顯示圖片

```
<body>
    <input type="button" value="顯示圖片" id="btn">
    <img src="" alt="" id="img">
<script >
    // 點擊按鈕顯示圖片:點擊按鈕的時候,設置img的src屬性來顯示圖片
    // 一、獲取按鈕的id
    var btnObj = document.getElementById("btn");
    // 二、爲按鈕註冊點擊事件,添加事件處理函數
    btnObj.onclick = function () {
        // 三、獲取圖片的id獲取圖片元素(標籤)
        var imgObj = document.getElementById("img");
        // 爲圖片標籤設置src屬性
        imgObj.src = "1.jpg";
        // 爲圖片標籤添加width屬性
        imgObj.width = '300'; // 不加px,由於這是img標籤裏的屬性,只有在css裏時纔要加px
    }

</script>
</body>
```

案例二:點擊修改a標籤的地址和熱點文字

```
<body>
    <input type="button" value="顯示圖片" id="btn">
    <img src="" alt="" id="img">
<script >
    // 點擊按鈕顯示圖片:點擊按鈕的時候,設置img的src屬性來顯示圖片
    // 一、獲取按鈕的id
    var btnObj = document.getElementById("btn");
    // 二、爲按鈕註冊點擊事件,添加事件處理函數
    btnObj.onclick = function () {
        // 三、獲取圖片的id獲取圖片元素(標籤)
        var imgObj = document.getElementById("img");
        // 爲圖片標籤設置src屬性
        imgObj.src = "1.jpg";
        // 爲圖片標籤添加width屬性
        imgObj.width = '300'; // 不加px,由於這是img標籤裏的屬性,只有在css裏時纔要加px
    }

</script>
</body>
```

案例三 點擊修改P標籤的顯示內容

```
<body>
    <input type="button" value="設置p標籤的內容" id="btn"/>
    <p id="p1">這是一個p標籤</p>
<script >
    // 案例:點擊按鈕修改p標籤的顯示內容
    // 先根據id獲取按鈕,爲按鈕註冊點擊事件,添加事件處理函數,在事件處理函數裏改寫p標籤的內容
    // 凡是成對的標籤,中間文本內容,設置的時候,都使用innerText這個屬性的方式
    var btnObj = document.getElementById("btn");
    btnObj.onclick = function () {
        // 獲取id爲p1標籤並設置其innerText屬性
        document.getElementById("p1").innerText = "哈哈哈";
    }
</script>
</body>
```

案例四 點擊修改多個P標籤的文字

```
<body>
<input type="button" id="btn" value="更換多個P標籤">
<p>王者歸來</p>
<p>王者歸來</p>
<p>王者歸來</p>
<p>王者歸來</p>
<p>王者歸來</p>
<p>王者歸來</p>

<!--若是有兩個div,裏面有P標籤,只想改d1裏的,另外一個不動,須要在標籤選擇的時候,進行區別:
加上document表明的是從整個文檔裏找,下面這句代碼的意思是,先找到d1,而後再找d1下面的p標籤
document.getElementById("d1").getElementsByTagName("p")-->
<div id="d1">
<p>哈哈,變帥了</p>
<p>哈哈,變帥了</p>
<p>哈哈,變帥了</p>
<p>哈哈,變帥了</p>
<p>哈哈,變帥了</p>
</div>
<div id="d2">
<p>啦啦,變醜了</p>
<p>啦啦,變醜了</p>
<p>啦啦,變醜了</p>
<p>啦啦,變醜了</p>
<p>啦啦,變醜了</p>
</div>
<script>
    // 案例:點擊按鍵修改多個標籤的文字內容
    // 一、根據id獲取按鈕,註冊點擊事件,添加事件處理函數
    document.getElementById("btn").onclick = function () {
        // document.getElementsByTanName("標籤的名子"),無論找到的元素是幾個,返回的都是一個僞數組
        // var pObjs = document.getElementsByTagName("p"); 找整個文檔的p標籤
        var pObjs = document.getElementById('d1').getElementsByTagName("p"); // 只找id爲d1下面的p標籤
        // 循環這個僞數組
        for (var i=0; i<pObjs.length; i++) {
            pObjs[i].innerText = "王者榮耀";
        }
    };
</script>
</body>
```

案例5 點擊修改圖片的alt title

```
<body>

<img src="1.jpg" alt="" title="">
<input type="button" value="變一下">
<script >
    // 由於根據標籤名獲取到的元素是一個僞數組,因此,要想進行屬性的設置,要麼用下標獲取單個的元素,要麼循環獲取每一個元素
    document.getElementsByTagName("input")[0].onclick = function () {
        var imgObj = document.getElementsByTagName("img")[0];
        imgObj.alt = "圖片丟失後顯示的";
        imgObj.title = "鼠標懸停時顯示的";
    }
</script>
</body>
```

案例6:點擊修改全部文本框的值

```
<body>
    <input type="button" value="變一下" id="btn"> <br/>
    <input type="text" value=""> <br/>
    <input type="text" value=""> <br/>
    <input type="text" value=""> <br/>
    <input type="text" value=""> <br/>
    <input type="text" value=""> <br/>
    <input type="text" value=""> <br/>
    <input type="text" value=""> <br/>
    <input type="text" value=""> <br/>
    <input type="text" value=""> <br/>
    <input type="text" value=""> <br/>
<script >
    // 根據id獲取到標籤,爲標籤註冊事件,添加事件處理函數
    document.getElementById("btn").onclick = function () {
        // 根據標籤名獲取元素,循環僞數組,排除type是button的那個,爲其餘的input標籤改value的值
        var inpObjs = document.getElementsByTagName("input");
        for (var i=0; i<inpObjs.length; i++) {
            if (inpObjs[i].type != "button") {
                inpObjs[i].value = "無聲無息";
            }
        }
    };
</script>
</body>
```

案例7 爲每一張圖片添加點擊事件

```
<body>
<img src="1.jpg" alt="">
<img src="1.jpg" alt="">
<img src="1.jpg" alt="">
<img src="1.jpg" alt="">
<img src="1.jpg" alt="">
<script >
    // 找到頁面中的全部img標籤,循環,在循環裏面給每個標籤註冊事件,添加事件處理函數
    var imgObjs = document.getElementsByTagName("img");
    for (var i=0; i<imgObjs.length; i++) {
        imgObjs[i].onclick = function () {
            alert("被點了");
        };
    }
</script>
</body>
```

案例8:點擊按鍵修改按鈕自己的value屬性

```
<body>
<input type="button" value="按鈕" id="btn"/>
<script >
    // 在某個元素的事件中,本身的事件中的this,就是當前的這個元素對象
    var btnObj = document.getElementById("btn");
    btnObj.onclick = function () {
        this.value = "我變了";
        this.type = "text";
        this.id = "btn2";
    };
</script>
</body>
```

案例9:點擊圖片修改自身的寬高

```
body>
<img src="1.jpg" alt="">
<script >
    // 點擊圖片修改自身的大小
    // 根據標籤名獲取到標籤僞數組,取第一個,給自身註冊一個事件,添加事件處理函數
    var imgObj = document.getElementsByTagName("img")[0];
    imgObj.onclick = function () {
        this.width = "100";
        this.height = "80";
    };
</script>

</body>
```

案例10 按鈕的排他功能

```
<body>
<input type="button" value="沒懷孕">
<input type="button" value="沒懷孕">
<input type="button" value="沒懷孕">
<input type="button" value="沒懷孕">
<input type="button" value="沒懷孕">
<input type="button" value="沒懷孕">
<script >
    // 按鈕的排他功能的思路,點擊選中的按鈕,並非先將本次選中的改變,再把以前選中的再變回去,而是在本次改變以前,先將全部的恢復成默認的,再將選中的
    // 發生改變
    // 根據標籤名獲取全部的input標籤
    var inpObjs = document.getElementsByTagName("input");
    // 循環inpObjs這個僞數組對象
    for (var i=0; i<inpObjs.length; i++) {
        // 爲每個元素註冊點擊事件,添加事件處理函數
        inpObjs[i].onclick = function () {

            // 先進行一次循環將全部的標籤恢復成默認的
            for (var j=0; j<inpObjs.length; j++) {
                inpObjs[j].value = "沒懷孕";
            }
            // 再把當前點擊的設成懷孕了
            this.value= "懷孕了"; // 由於已經給每一個元素都註冊了事件,這裏的this,表明,誰被點擊了就是誰
            // console.log(i); // 6
            // inpObjs[i].value = "懷孕了"; 這裏不這樣寫,由於,頁面一加載完畢,for循環給每一個元素註冊了點擊事件,也就循環完畢了,而點擊事件,
            // 要等到點擊後才能觸發,此時i這個變量,已經變成了數組的長度6,因此會報錯,找不到。
        };
    }
</script>
</body>
```

案例11 點擊超鏈接切換圖片

```
<body>
<a href="images/1.jpg" id="ak">
    <img src="images/1-small.jpg" alt="" id="im">
</a>
<script >
    // 點擊小圖的時候,把大圖的圖片地址給小圖
    document.getElementById("im").onclick = function () {
        this.src = document.getElementById("ak").href;
        return false;
    };
</script>
</body>
```

案例12 點擊按鈕切換圖片-經過封裝document.getElementById()的方式

```
// common.js
/**
 * 根據id值,返回對應的標籤元素。
 * @param id id 屬性的值,string類型
 * @returns {HTMLElement} 元素對象
 */
function my$ (id) {
    return document.getElementById(id);
}
```

```
<body>
<input type="button" value="顯示大圖" id="btn">
<img src="images/1-small.jpg" alt="" id="im">
<script >
    // 由於每次都要寫document.getElementById(id)有重複的代碼,因此要封裝成函數
    function my$ (id) {
        return document.getElementById(id);
    }
    // 把id傳給封裝後的函數,獲取到元素,註冊事件,添加事件處理函數
    my$("btn").onclick = function () {
        // 獲取到響應的元素,改變其src屬性
        my$("im").src = "images/1.jpg";
    };
</script>
</body>
```

### (二)表單元素屬性

+ value 用於大部分表單元素的內容獲取(option除外)
+ type 能夠獲取input標籤的類型(輸入框或複選框等)
+ disabled 禁用屬性
+ checked 複選框選中屬性
+ selected 下拉菜單選中屬性
+ name
+ readonly 只讀

案例1:點擊修改性別和興趣

```
<body>
<div id="d1">
    <input type="button" value="修改性別" id="btn">
    <input type="radio" value="1" name="sex">男
    <input type="radio" value="2" name="sex" id="ip1">女
    <input type="radio" value="3" name="sex">保密
</div>
<br/>
<div id="d2">
    <input type="button" value="修改興趣" id="btn2">
    <input type="checkbox" value="1" name="xinqu">吃飯
    <input type="checkbox" value="2" name="xinqu" id="ip2">睡覺
    <input type="checkbox" value="3" name="xinqu">打豆豆
    <input type="checkbox" value="4" name="xinqu" id="ip3">保藍球
    <input type="checkbox" value="5" name="xinqu">踢足球
</div>
<script >
    // 規律:在表單的標籤中,若是屬性和值只有一個,而且值是這個屬性自己(如checked),那麼寫js代碼,DOM操做的時候,這個屬性值,是布爾類型就能夠了。
    // 先封裝一個函數
    function my$ (id) {
        return document.getElementById(id);
    }
    // 獲取id爲btn的元素,註冊事件,添加事件處理函數
    my$("btn").onclick = function () {
        my$("ip1").checked = true;
    };
    my$("btn2").onclick = function () {
        my$("ip2").checked = true;
        my$("ip3").checked = true;
    };
</script>
</body>
```

案例2:點擊按鈕選擇菜單

```
<body>
<input type="button" id="btn" value="點菜">
<select name="" id="ss">
    <option value="1">油炸榴蓮</option>
    <option value="2">油炸杜鬆</option>
    <option value="3">爆炒臭豆腐</option>
    <option value="4" id="op1">清蒸助教</option>
    <option value="5">涼拌班主任</option>
    <option value="6">紅燒三絲</option>
</select>
<script src="common.js"></script>
<script >
    // 根據id獲取元素,註冊事件,添加事件處理函數
    my$("btn").onclick = function () {
        // 事件響應
        my$("op1").selected = true;
    };
</script>
</body>
```

案例3:點擊修改文本域

```
<body>
<!--readonly="readonly"只讀 disabled="disable" 禁用-->
<textarea name="" id="tt" cols="30" rows="10">
anchor()    建立 HTML 錨。

big()   用大號字體顯示字符串。
blink() 顯示閃動字符串。
bold()  使用粗體顯示字符串。
charAt()    返回在指定位置的字符。
charCodeAt()    返回在指定的位置的字符的 Unicode 編碼。
concat()    鏈接字符串。
fixed() 以打字機文本顯示字符串。
fontcolor() 使用指定的顏色來顯示字符串
</textarea>
<input type="button" id="btn" value="點我">
<script src="common.js"></script>
<script >
    // 根據id值獲取元素,註冊事件,添加事件處理函數
    my$("btn").onclick = function () {
        // 推薦用value,form表單的標籤
        // my$("tt").value = "哈哈";
        my$("tt").innerText = "吹牛逼";
    };
</script>
</body>
```

### (三)樣式操做

#### 一、使用style方式設置的樣式顯示在標籤行內

對象.style.屬性 = 值;設置標籤的

對象.style.classText = 值

獲取:getComputedStyle,由於對象.style.屬性只能拿到行間樣式,拿不到css類裏的屬性。

window.getComputedStyle(ele, null).屬性。計算樣式只讀,返回計算樣式的值都是絕對值,沒有相對單位,ie8及ie8如下不兼容。第二個參數是用來獲取僞元素的,把僞元素名子放到第二個參數上。

在ie8及ie8如下,使用ele.currentStyle[屬性]來獲取只讀屬性,返回的計算樣式的值不是通過轉換的絕對值,

案例1:點擊修改div的寬高背景顏色 

```
<body>
<div id="dv"></div>
<input type="button" id="btn" value="變了變了">
<script src="common.js"></script>
<script >
    /*凡是在css中屬性是多個單詞組成的好比:background-color 在js操做DOM的時候,把—幹掉,後面單詞的首字母大寫便可,可讀寫行間樣式,沒有兼容性的疸,碰到float這樣的保留字屬性,前面應加css,float->cssFloat,寫入的值必須是字符串的格式。
    好比backgroundColor*/
    // 獲取id獲取元素,註冊事件,添加事件處理函數
    my$("btn").onclick = function () {
        // 事件響應
        my$("dv").style.width = "300px";
        my$("dv").style.height = "200px";
        my$("dv").style.backgroundColor = "deeppink";
    }
</script>
</body>
```

案例2 點擊隱藏或顯示div

```
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div {
            width: 300px;
            height: 300px;
            background-color: #f40;
        }
        
    </style>
</head>
<body>
<input type="button" id="btn" value="隱藏">
<input type="button" id="btn2" value="顯示">
<div id="dv"></div>
<script src="common.js"></script>
<script >
    // 根據id獲取元素 註冊事件 添加事件處理函數
    my$("btn").onclick = function () {
        // 響應事件
        my$("dv").style.display = "none";
    };
    my$("btn2").onclick = function () {
        // 響應事件
        my$("dv").style.display = "block";
    };
</script>
</body>
```

案例3 一個按鈕解決div的隱藏與顯示

```
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div {
            width: 300px;
            height: 300px;
            background-color: #f40;
        }
        
    </style>
</head>
<body>
<input type="button" id="btn" value="隱藏">
<div id="dv"></div>
<script src="common.js"></script>
<script >
    // 經過設置元素的style屬性的display是none,仍是block來顯示或是隱藏,根據btn的value屬性值來判斷顯示的狀態
    // 根據id獲取元素 註冊事件 添加事件處理函數
    my$("btn").onclick = function () {
        // 根據value值來判斷
        if (this.value=="隱藏") {
            my$("dv").style.display = "none";
            this.value = "顯示";
        }else if (this.value == "顯示") {
            my$("dv").style.display = "block";
            this.value = "隱藏";
        }
    };
</script>
</body>
```

#### 二、類名操做 

修改標籤的className屬性至關於直接修改標籤的類名

對象.className = 值

案例1 經過類樣式,點擊設置div樣式

```
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .cls {
            width: 300px;
            height: 300px;
            background-color: #f40;
            border: 1px solid pink;
        }
    </style>
</head>
<body>
<div id="dv"></div>
<input type="button" id="btn" value="設置div">
<script src="common.js"></script>
<script >
    my$("btn").onclick = function () {
        // 在js代碼操做Dom時,設置元素的類樣式,不用clsss關鍵字,應該使用className
        // 下面這種方式很差,通常超過2個樣式,採用css樣式,給元素設置類樣式屬性值是以前設置過的css類名的方式
        // my$("dv").style="width:300px;height:300px;border:2px solid pink";
        my$("dv").className = "cls";
    };
</script>
</body>
```

案例2 經過類樣式顯示隱藏div

```
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div {
            width: 300px;
            height: 300px;
            background-color: #f40;
        }
        .cls {
            display: none;
        }
    </style>
</head>
<body>
<input type="button" id="btn" value="隱藏">
<div id="dv"></div>
<script src="common.js"></script>
<script >
    // 經過給一個標籤添加類樣式,來控制該元素的顯示與隱藏,
    my$("btn").onclick = function () {
        // 判斷元素的類裏面有沒有cls這個類樣式,若是沒有,就設置類樣式爲cls並設置btn的value屬性值爲顯示
        if (my$("dv").className != "cls") {
            my$("dv").className = "cls";
            this.value = "顯示";
        } else {
            // 不然,就設置這個元素的類樣式屬性爲空,而且把btn的value屬性設置爲隱藏
            my$("dv").className = "";
            this.value = "隱藏";
        }
    };
</script>
</body>
```

案例3 關燈效果

```
<body>
<input type="button" value="關燈" id="btn" />
<script src="common.js"></script>
<script >
    my$("btn").onclick = function () {
        /*直接給body標籤添加類樣式,改變背景色
        兩種方式,一是能夠用document.getElementById()獲取body,一種是直接document.body*/
        // document.body.className != "cls"?document.body.className="cls":document.body.className="";
        document.body.className=document.body.className != "cls"?"cls":"";
    };
</script>
</body>
```

### (四)阻止a連接瀏覽器默認跳轉和其餘的默認事件

+ return false;
+ 事件參數對象.preventDefault()方法;
+ href="javacript:void(0);"

```javascript
<body>
<!--阻止超鏈接的跳轉,就是要在事件響應中return false-->
<!--第一種寫法-->
<!--加onclick對瀏覽器默認的跳轉事件沒有影響, 阻止超鏈接的默認跳轉:return false-->
<a href="http://www.baidu.com" onclick="alert('哎呀我被點了');return false">百度一下</a>
<!--第二種寫法-->
<script >
    function f1() {
        alert("彈窗");
        return false;
    }
</script>
<!--onclick=f1()由於這個函數的執行結果是false,與第一種結果相對比,沒有return,因此仍是阻止不了-->
<!--<a href="http://www.baidu.com" onclick="f1()">百度一下</a>-->
<a href="http://www.baidu.com" onclick="return f1()">百度一下</a>
<!--第三種寫法-->
<a href="http://www.baidu.com" id="aa">百度一下</a>
<script >
    document.getElementById("aa").onclick = function () {
      alert("彈框2");
      return false;
    };
</script>
</body>
//還有一種寫法
function cancelHandler(evernt){
  if (event.preventDefault) {
    event.preventDefault();
  }else {
    event.returnValue = false;
  }
}
```

案例一:點擊小圖切換大圖

```
<body>
<a href="../images/1.jpg" id="aa"><img src="../images/1-small.jpg" alt=""></a>
<img src="" alt="" id="big">
<script src="./common.js"></script>
<script >
    // 點擊小圖顯示大圖
    // 由於小圖是在a鏈接裏面,因此直接點擊a超鏈接就能夠了
    // 根據Id獲取a鏈接元素對象,註冊事件,添加事件處理函數
    my$("aa").onclick = function () {
        my$("big").src = this.href;
        return false;
    };
</script>
</body>
```

案例二:美女相冊

```
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style type="text/css">
    body {
      font-family: "Helvetica", "Arial", serif;
      color: #333;
      background-color: #ccc;
      margin: 1em 10%;
    }

    h1 {
      color: #333;
      background-color: transparent;
    }

    a {
      color: #c60;
      background-color: transparent;
      font-weight: bold;
      text-decoration: none;
    }

    ul {
      padding: 0;
    }

    li {
      float: left;
      padding: 1em;
      list-style: none;
    }

    #imagegallery {

      list-style: none;
    }

    #imagegallery li {
      margin: 0px 20px 20px 0px;
      padding: 0px;
      display: inline;
    }

    #imagegallery li a img {
      border: 0;
    }
  </style>
</head>
<body>

<h2>
  美女畫廊
</h2>

<ul id="imagegallery">
  <li><a href="../images/1.jpg" title="美女A">
    <img src="../images/1-small.jpg" width="100" alt="美女1"/>
  </a></li>
  <li><a href="../images/2.jpg" title="美女B">
    <img src="../images/2-small.jpg" width="100" alt="美女2"/>
  </a></li>
  <li><a href="../images/3.jpg" title="美女C">
    <img src="../images/3-small.jpg" width="100" alt="美女3"/>
  </a></li>
  <li><a href="../images/4.jpg" title="美女D">
    <img src="../images/4-small.jpg" width="100" alt="美女4"/>
  </a></li>
</ul>


<div style="clear:both"></div>
<!--顯示大圖的-->
<img id="image" src="../images/placeholder.png" alt="" width="450"/>
<p id="des">選擇一個圖片</p>
<script src="./common.js"></script>
<script >
    // 點擊a標籤把a標籤href屬性賦值給id爲img的src,同時把a標籤的title屬性賦值給id爲des的文本屬性
    var aObjs = my$("imagegallery").getElementsByTagName("a"); // 先根據Id獲取到ul元素,再根據標籤名獲取到a元素組成的僞數組
    // 循環a元素組成的僞數組對象,爲每一個a元素註冊事件,添加事件處理函數
    for (var i=0; i<aObjs.length; i++) {
        // 爲每一個a添加事件
        aObjs[i].onclick = function () {
            // 把a 的href屬性賦值給id爲image的src
            my$("image").src = this.href;
            // 把a 的title屬性賦值給des的innerText
            my$("des").innerText = this.title;
            // 阻止瀏覽器的默認跳轉事件
            return false;
        };
    }
</script>
</body>
```

### (五) innerText和textContent兼容性

+ 設置標籤中的文本內容,應該使用textContent屬性,谷歌、火狐支持,ie8不支持
+ 設置標籤中的文本內容,應該使用innerText屬性,谷歌、ie8支持,高版本的火狐支持,低版本的不支持
+ 若是這個屬性在瀏覽器中不支持,那麼這個屬性的類型是undefined,判斷這個屬性的類型是否是undefined,就知道瀏覽器支不支持。

```
<body>
<input type="button" value="設置" id="btn">
<input type="button" value="獲取" id="btn1">
<div id="dv">螺螄粉就算了</div>
<script src="./common.js"></script>
<script >
    // 設置標籤中的文本內容,應該使用textContent屬性,谷歌、火狐支持,ie8不支持
    // 設置標籤中的文本內容,應該使用innerText屬性,谷歌、ie8支持,高版本的火狐支持,低版本的不支持
    // 若是這個屬性在瀏覽器中不支持,那麼這個屬性的類型是undefined,判斷這個屬性的類型是否是undefined,就知道瀏覽器支不支持。
    //  ** 寫解決兼容性的函數

    // 一、設置標籤中的文本內容
    function setInnerText (element, text) {
        if (typeof element.textContent=="undefined") {//說明不支持
            element.innerText = text;
        }else {
            element.textContent = text;
        }
    }
    // 二、獲取標籤中的文本內容
    function getInnerText (element) {
        if (typeof element.textContent == "undefined") {
            return element.innerText;
        } else {
            return element.textContent;
        }
    }
    // 測試設置
    my$("btn").onclick = function () {
        // 設置div中的文本內容
        setInnerText(my$("dv"), "老司機服務");
    };
    // 測試獲取
    my$("btn1").onclick = function () {
        // 獲取div中的內容
        var out = getInnerText(my$("dv"));
        console.log(out);
    };

</script>
</body>
```

### (六)innerText和innerHTML區別

+ innerText主要是設置文本的,設置標籤內容,是沒有標籤的效果的,同時會把標籤內的全部內容(包括包含的標籤)都替換爲新的內容 文本的形式
+ innerHTML 能夠設置文本內容,主要做用是在標籤中設置新的html標籤內容,是有標籤的效果的,同時把標籤內的全部內容(包括包含的標籤)都替換成
+ 新的內容 解析成html代碼的形式
+ innerText 獲取的時候,會把標籤內的全部的文本內容到取到。包括嵌套的標籤裏的內容,文本的形式
+ innerHTML 獲取的時候,會把標籤內的全部內容,原樣獲取到,html代碼的形式

```
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div {
            width: 300px;
            height: 300px;
            border: 2px solid red;
        }
    </style>
</head>
<body>
<input type="button" value="設置" id="btn">
<input type="button" value="獲取" id="btn1">
<div id="dv">酸辣粉叫我
<span>哈哈哈</span>
</div>
<script src="./common.js"></script>
<script >
    /*總結:一、innerText主要是設置文本的,設置標籤內容,是沒有標籤的效果的,同時會把標籤內的全部內容(包括包含的標籤)都替換爲新的內容 文本的形式
    * 二、innerHTML 能夠設置文本內容,主要做用是在標籤中設置新的html標籤內容,是有標籤的效果的,同時把標籤內的全部內容(包括包含的標籤)都替換成
    * 新的內容 解析成html代碼的形式
    * 三、innerText 獲取的時候,會把標籤內的全部的文本內容到取到。包括嵌套的標籤裏的內容,文本的形式
    * 四、innerHTML 獲取的時候,會把標籤內的全部內容,原樣獲取到,html代碼的形式
    */
    // 設置
    my$("btn").onclick = function () {
        // my$("dv").innerText = "哈哈" // 設置文本
        // my$("dv").innerText = "<p>沒看到</p>" // 設置html 代碼 ,沒有標籤的效果
        // my$("dv").innerHTML = "<p>沒看到</p>" // 設置html代碼,有標籤的效果。
    };
    // 獲取
    my$("btn1").onclick = function () {
        console.log(my$("dv").innerText); // 酸辣粉叫我 哈哈哈
        console.log(my$("dv").innerHTML); //酸辣粉叫我 <span>哈哈哈</span>
    };
</script>
</body>
```

### (七)自定義屬性

+ 自定義屬性:也叫隱式屬性,自己html標籤中沒有這個屬性,是本身添加的,用來存儲一些數據。setAttribute(屬性名,屬性值)
+ 在html標籤中添加的自定義屬性,是沒法經過對象.屬性獲取的,由於自定義屬性在標籤中,並不在DOM對象中,因此須要使用getAttribute("自定義屬性名子")來獲取的,也能夠拿到顯示屬性。
+ 在html標籤中設置自定義屬性,是沒法經過對象.屬性=值來設置的,由於這種方法自定義屬性在DOM對象上,不在標籤中
+ 刪除自定義屬性:removeAttribute("屬性的名子") 用於移除自定義屬性和標籤的屬性
+ 判斷有沒有這個屬性 hasAttribute(屬性名) 返回布爾值。

案例一:自定義屬性的獲取

```
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        li {
            list-style: none;
            cursor: pointer;
        }
    </style>
</head>
<body>
<ul id="uu">
<li score="10">小明的成績</li>
<li score="20">小花的成績</li>
<li score="30">小李的成績</li>
</ul>
<script src="./common.js"></script>
<script >
    /*
    * 自定義屬性:自己html標籤中沒有這個屬性,是本身添加的,用來存儲一些數據
    * 在html標籤中添加的自定義屬性,是沒法經過對象.屬性獲取的,由於自定義屬性在標籤中,並不在DOM對象中,因此須要使用getAttribute("自定義屬性
    * 名子")來獲取的
    * */
    var list = my$("uu").getElementsByTagName("li");
    for (var i=0; i<list.length; i++) {
        list[i].onclick = function () {
            // alert(this.score); // undefined
            alert(this.getAttribute("score"));
        };
    }
</script>
</body>
```

案例二:自定義屬性的設置與獲取

```
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        li {
            list-style: none;
            cursor: pointer;
        }
    </style>
</head>
<body>
<ul id="uu">
<li>小明的成績</li>
<li>小明的成績</li>
<li>小明的成績</li>
<li>小明的成績</li>
</ul>
<script src="./common.js"></script>
<script >
    // 根據id名獲取ul元素而且獲取下面的全部li標籤
    var list = my$("uu").getElementsByTagName("li");
    // 循環
    for (var i=0; i<list.length; i++) {
        // 先爲每一個li添加自定義的屬性
        // list[i].score = (i+1)*10; // 由於此方法的自定義屬性在DOM對象上,不在標籤中
        list[i].setAttribute("score", (i+1)*10);
        // 爲每一個li註冊點擊事件,顯示對應的自定義屬性
        list[i].onclick = function () {
            alert(this.getAttribute("score"));
        };
    }
</script>
</body>
```

案例三:刪除自定義屬性和標籤屬性

```
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            background-color: #ff4400;
        }
        .cls {
            background-color: yellow;
        }
    </style>
</head>
<body>
<input type="button" value="刪除自定義屬性" id="btn">
<input type="button" value="刪除標籤屬性" id="btn1">
<div id="dv" class="cls" score="30"></div>
<script src="./common.js"></script>
<script >
    /*
    * 點擊後移動自定義的屬性和標籤的屬性class 註冊區分標籤屬性class和DOM屬性className
    * removeAttribute("屬性的名子") 用於移除自定義屬性和標籤的屬性
    * */
    my$("btn").onclick = function () {
        my$("dv").removeAttribute("score");
    };
    my$("btn1").onclick = function () {
        // my$("dv").className = ""; // 這種方式值沒了,可是屬性還在
        my$("dv").removeAttribute("class"); // 刪除標籤的自帶屬性
    };
</script>
</body>
```

案例四:tab切換案例的實現  排他思想

排他的步驟:一、先刪除全部(恢復默認)二、再從新定義

```
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        ul {
            list-style-type: none;
        }

        .box {
            width: 400px;
            height: 300px;
            border: 1px solid #ccc;
            margin: 100px auto;
            overflow: hidden;
        }

        .hd {
            height: 45px;
        }

        .hd span {
            display: inline-block;
            width: 90px;
            background-color: pink;
            line-height: 45px;
            text-align: center;
            cursor: pointer;
        }

        .hd span.current {
            background-color: purple;
        }

        .bd li {
            height: 255px;
            background-color: purple;
            display: none;
        }

        .bd li.current {
            display: block;
        }
    </style>

</head>
<body>
<div class="box" id="box">
    <div class="hd">
        <span class="current">體育</span>
        <span>娛樂</span>
        <span>新聞</span>
        <span>綜合</span>
    </div>
    <div class="bd">
        <ul>
            <li class="current">我是體育模塊</li>
            <li>我是娛樂模塊</li>
            <li>我是新聞模塊</li>
            <li>我是綜合模塊</li>
        </ul>
    </div>
</div>
<script src="./common.js"></script>
<script>
    // 獲取最外面的盒子
    var boxObj = my$("box");
    // 獲取hd盒子
    var hdObj = boxObj.getElementsByClassName("hd")[0];
    // 獲取bd盒子
    var bdObj = boxObj.getElementsByClassName("bd")[0];
    // 獲取hd下的全部span
    var spanObjs = hdObj.getElementsByTagName("span");
    // 獲取bd下全部的li
    var liObjs = bdObj.getElementsByTagName("li");
    // 循環span元素組成的僞數組
    for (var i = 0; i < spanObjs.length; i++) {
        // 爲span添加自定義屬性index
        spanObjs[i].setAttribute("index", i);
        // 註冊點擊事件
        spanObjs[i].onclick = function () {
            // hd排他,先移動全部的,再添加本身的
            for (var j = 0; j < spanObjs.length; j++) {
                spanObjs[j].removeAttribute("class");
            }
            this.className = "current";
            // bd排他 先移動全部,再添加本身的
            for (var k = 0; k < liObjs.length; k++) {
                liObjs[k].removeAttribute("class");
            }
            liObjs[this.getAttribute("index")].className = "current";
        };
    }

</script>

</body>
</html>
```

## 6、節點

### (一)節點的介紹

頁面中的全部內容都是節點,包括標籤、文本(文字、空格、換行等)、註釋、屬性

### (三)節點的屬性

能夠使用標籤.點出來,能夠使用屬性節點.出來,文本節點.點出來

+ nodeType: 節點的類型 1 -- 標籤,2--屬性,3—文本,註釋-8 , document-9
+ nodeName:節點的名子:標籤節點--大寫的標籤名子,屬性節點--小寫的屬性名子,文本節點--#text
+ nodeValue: 節點的值:標籤節點--null, 屬性節點--屬性值,文本節點--文本內容
+ attributes:元素節點的屬性集合

```
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="dv">
    <span>這是div中的第一個span標籤</span>
    <p>這是div中的第二個元素,第一個P標籤</p>
    <ul id="uu">
        <li>這是ul中的第一個元素li</li>
        <li>這是ul中的第二個元素li</li>
        <li>這是ul中的第三個元素li</li>
    </ul>
</div>
<script src="./common.js"></script>
<script >
    var dvObj = my$("dv");
    var child = dvObj.childNodes;
    // 獲取裏面的每一個子節點
    for (var i=0; i<child.length; i++) {
        var node = child[i];
        /*
        * nodeType--節點的類型 1--標籤、2--屬性、3--文本;
        * nodeName--節點的名子 大寫--標籤名子、小寫--屬性名子、#text--文本
        * nodeValue--節點的值 null--標籤、屬性值--屬性、 文本內容--文本
        * */
        console.log(node.nodeType+"==="+node.nodeName+"==="+node.nodeValue);
    }
    /*
    * 3===#text===
    1===SPAN===null
    1===P===null
    1===UL===null
    3===#text===*/
    // 獲取的是屬性節點 getAttributeNode("屬性名子")
    var node = dvObj.getAttributeNode("id");
    console.log(node.nodeType+"==="+node.nodeName+"==="+node.nodeValue); // 2===id===dv
</script>
</body>
</html>
```

### (四)節點的層級

在頁面中只有標籤能作爲父節點(或者叫父元素)

父節點obj.parentNode=(父元素)obj.parentElement;

元素層級中,只有children兼容ie9如下的瀏覽器

```
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="dv">
    <span>這是div中的第一個span標籤</span>
    <p>這是div中的第二個元素,第一個P標籤</p>
    <ul id="uu">
        <li>這是ul中的第一個元素li</li>
        <li>這是ul中的第二個元素li</li>
        <li>這是ul中的第三個元素li</li>
    </ul>
</div>
<script src="./common.js"></script>
<script >
    var ulObj = my$("uu");
    // ul 標籤的父級節點
    console.log(ulObj.parentNode); //div
    // ul 標籤的父級元素
    console.log(ulObj.parentElement); //div
    // ul 標籤的父節點的父節點
    console.log(ulObj.parentNode.parentNode); //body
    // 再上一層
    console.log(ulObj.parentNode.parentNode.parentNode); // html
    // 再上一層
    console.log(ulObj.parentNode.parentNode.parentNode.parentNode); // #document
    // 再上一層
    console.log(ulObj.parentNode.parentNode.parentNode.parentNode.parentNode); // null
    // 獲取節點的類型、名子、值
    console.log(ulObj.nodeType); // 1 標籤的節點類型是1
    console.log(ulObj.nodeName); // UL 標籤的節點名子是大寫的標籤名
    console.log(ulObj.nodeValue); // null 標籤節點的值是null
    // 獲取子節點、節元素
    var dvObj = my$("dv");
    console.log(dvObj.childNodes); // NodeList(7) [text, span, text, p, text, ul#uu, text] 7個子節點 這是的text是換行
    console.log(dvObj.children); // HTMLCollection(3) [span, p, ul#uu, uu: ul#uu] 3個子元素

</script>
</body>
</html>
```

#### 節點層級的十二行代碼

```
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="dv">哈哈
    <span>這是div中的第一個span標籤</span>
    <p>這是div中的第二個元素,第一個P標籤</p>
    <ul id="uu">
        <li>這是ul中的第一個元素li</li>
        <li id="mid">這是ul中的第二個元素li</li>
        <li>這是ul中的第三個元素li</li>
    </ul>嘖嘖
</div>å
<script src="./common.js"></script>
<script >
    var dvObj = my$("dv");
    var liObj = my$("mid");
    // 父節點
    console.log(dvObj.parentNode);
    // 父元素
    console.log(dvObj.parentElement);
    // 子節點
    console.log(dvObj.childNodes);
    // 子元素
    console.log(dvObj.children);

    //============如下方法在谷歌和火狐裏是正常的,可是在ie8,子節點的結果變成了子元素的結果,子元素則是undefined
    // 第一個子節點
    console.log(dvObj.firstChild); // ie8中是第一個字元素
    // 第一個子元素
    console.log(dvObj.firstElementChild); // ie8中是undefined
    // 最後一個子節點
    console.log(dvObj.lastChild);
    // 最後一個子元素
    console.log(dvObj.lastElementChild);
    // 某元素的前一個兄弟節點
    console.log(liObj.previousSibling);
    // 某元素的前一個兄弟元素
    console.log(liObj.previousElementSibling);
    // 某元素的後一個兄弟節點
    console.log(liObj.nextSibling);
    // 某元素的後一個兄弟元素
    console.log(liObj.nextElementSibling);
    /*
    * 總結:凡是獲取節點的代碼在谷歌和火狐獲得的都是相關的節點
    * 凡是獲取元素的代碼在谷歌和火狐獲得的都是相關的元素
    * 從子節點和兄弟節點開始,凡是獲取節點的代碼在ie8中獲得的都是元素,獲取元素的相關代碼,在ie8中獲得的都是undefined,一句話,就是元素的代碼,ie不支持
    * */
</script>
</body>
</html>
```

案例一:利用節點 點擊更改p標籤的背景顏色

```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div {
            width: 300px;
            height: 450px;
            border:1px solid #f40;
        }
    </style>
</head>
<body>
<input type="button" value="變色" id="btn">
<div id="dv">
    <span>這是span</span>
    <p>這是p</p>
    <span>這是span</span>
    <p>這是p</p>
    <span>這是span</span>
    <p>這是p</p>
    <span>這是span</span>
    <p>這是p</p>
    <span>這是span</span>
    <p>這是p</p>
    <a href="">百度</a>
</div>
<script src="./common.js"></script>
<script >
    // 點擊按鍵,設置p變色--節點的方式作
    my$("btn").onclick = function () {
        // 獲取dv裏的子節點
        var dvChild = my$("dv").childNodes;
        // 循環數組
        for (var i=0; i<dvChild.length; i++) {
            // 判斷是否是p標籤
            // if (dvChild[i].nodeType==1&&dvChild[i].nodeName=="P") { // 正常取p標籤
            if (dvChild[i].nodeType==1&&dvChild[i].nodeName!="P") { // 取反獲得除P處的全部標籤元素
                dvChild[i].style.backgroundColor="red";
            }
        }
    };
</script>
</body>
</html>
```

案例二:隔行變色 節點的方式

```
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="button" value="變色" id="btn">
<ul id="uu">
<li>五菱宏光</li>
<li>五菱宏光</li>
<li>五菱宏光</li>
<li>五菱宏光</li>
<li>五菱宏光</li>
</ul>
<script src="./common.js"></script>
<script >
    // 隔行變色-經過節點的方式獲取liq
    my$("btn").onclick = function () {
        var liObjs = my$("uu").childNodes;
        var content = 0;
        for (var i=0; i<liObjs.length; i++) {
            // 判斷是否是li標籤
            if (liObjs[i].nodeType==1&&liObjs[i].nodeName=="LI") {
                liObjs[i].style.backgroundColor=i%2==0?"red":"yellow"; // 不能用i由於子節點的數和li的數不一致
                content ++;
                liObjs[i].style.backgroundColor=content%2==0?"red":"yellow";
            }
        }
    };
</script>
</body>
</html>
```

#### 節點的兼容代碼

```
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul id="uu">
<li>第一個</li>
<li>第二個</li>
<li>第三個</li>
<li>第四個</li>
<li>第五個</li>
</ul>
<script src="./common.js"></script>
<script >
    var ulObj = my$("uu")
    // 第一個節點和第一個元素的獲取代碼在Ie8中和火狐谷歌的不同
    // ulObj.firstChild 在谷歌和火狐中獲取的是第一個子節點而在Ie8中是第一個子元素
    // ulObj.firstElementChild 在谷歌和火狐中獲取的是第一個子元素,而在ie8中是undefined
    // 封裝第一個節點的兼容函數,獲取任意一個父級元素的第一個子元素
    function getFirstElementChild (element) { // 不是ie8
        if (typeof element.firstElementChild != "undefined") { // (element.firstElementChild)有值就是true,undefined就是false
            return element.firstElementChild;
        } else { // 是ie8,要拿到第一個子元素,就得是firstCHild
            // return element.firstChild; // 若是單是ie返回就好了,可是若是有瀏覽器不支持上邊的,firstChild就是第一個子節點,直接返回就不行了
            var node = element.firstChild; // 第一個節點
            while (node&&node.nodeType!=1) { // node 存在而且不是標籤才循環,由於子節點會算上標籤前面的換行,主要是排除第一是子節點,可是不是第一個子元素。再往下面找一下,看是否是子元素。
                node = element.nextSibling; // 將下一個兄弟節點賦值給node,再進行判斷
            }
            return node; // 若是node沒有找到或者是子元素了就返回
        }
    }
    // 封裝最後一個節點的兼容函數  獲取任意一個父級元素的最後一個子元素
    function getLaseElementChild (element) {
        if (typeof element.lastElementChild != "undefined") {
            return element.lastElementChild;
        } else {
            var node = element.lastChild; // 最後一個節點
            while (node&&node.nodeType!=1) {
                node = element.previousSibling;
            }
            return node;
        }
    }
    // 測試
    console.log(getFirstElementChild(ulObj).innerText)
    console.log(getLaseElementChild(ulObj).innerText);
</script>
</body>
</html>
```

案例三:切換背景圖片

背景圖片變量的拼接

```
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>哈哈,我又變帥了</title>
  <style>
    * {
      margin: 0px;
      padding: 0px;
    }

    body {
      background-image: url("images/1.jpg");
    }

    #mask {
      background-color: rgba(255, 255, 255, 0.3);
      height: 200px;
      text-align: center;
    }

    #mask img {
      width: 200px;
      margin-top: 35px;
      cursor: pointer;
    }

  </style>

</head>
<body id="bd">
<div id="mask">
  <img src="images/1.jpg" alt="">
  <img src="images/2.jpg" alt="">
  <img src="images/3.jpg" alt="">
</div>
<script src="./common.js"></script>
<script >
    // 獲取全部的img元素 循環註冊點擊事件 將body的背景圖地址設置爲對應的img的src , 注意的地方就是body背景圖片地址的拼接
    var imgs = my$("mask").children;
    for (var i=0; i<imgs.length; i++) {
        imgs[i].onclick = function () {
            my$("bd").style.backgroundImage = "url("+this.src+")";
        };
    }
</script>
</body>
</html>
```

案例四:全選和全不選邏輯

```
<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }

    .wrap {
      width: 300px;
      margin: 100px auto 0;
    }

    table {
      border-collapse: collapse;
      border-spacing: 0;
      border: 1px solid #c0c0c0;
      width: 300px;
    }

    th,
    td {
      border: 1px solid #d0d0d0;
      color: #404060;
      padding: 10px;
    }

    th {
      background-color: #09c;
      font: bold 16px "微軟雅黑";
      color: #fff;
    }

    td {
      font: 14px "微軟雅黑";
    }

    tbody tr {
      background-color: #f0f0f0;
    }

    tbody tr:hover {
      cursor: pointer;
      background-color: #fafafa;
    }
  </style>
</head>
<body>
<div class="wrap">
  <table>
    <thead>
    <tr>
      <th>
        <input type="checkbox" id="j_cbAll"/>
      </th>
      <th>菜名</th>
      <th>飯店</th>
    </tr>
    </thead>
    <tbody id="j_tb">
    <tr>
      <td>
        <input type="checkbox"/>
      </td>
      <td>紅燒肉</td>
      <td>田老師</td>
    </tr>
    <tr>
      <td>
        <input type="checkbox"/>
      </td>
      <td>西紅柿雞蛋</td>
      <td>田老師</td>
    </tr>
    <tr>
      <td>
        <input type="checkbox"/>
      </td>
      <td>油炸榴蓮</td>
      <td>田老師</td>
    </tr>
    <tr>
      <td>
        <input type="checkbox"/>
      </td>
      <td>清蒸助教</td>
      <td>田老師</td>
    </tr>

    </tbody>
  </table>
</div>
<script src="./common.js"></script>
<script >
    // 先獲取全先的這個複選框
    var ckAll = my$("j_cbAll");
    // 獲取tbody下的全部複選框
    var cks = my$("j_tb").getElementsByTagName("input");
    // 點擊全選框,獲取當前的狀態,而後設置tbody複選框的狀態
    ckAll.onclick = function () {
        // 循環tbody中的複選框,讓每一個的checked的狀態等於ckAll的狀態
        for (var i=0; i<cks.length; i++) {
            cks[i].checked = this.checked;
        }
    };
    // 爲tbody中的input添加點擊事件
    for (var i=0; i<cks.length; i++) {
        cks[i].onclick = function () {
            // 檢查其餘的input的選中狀態
            var flag = true;
            for (var j=0; j<cks.length; j++) {
                if (!cks[j].checked) { // 當有任何一個沒有選中的時候,就更改標記爲false
                    flag = false;
                    break;
                }
            }
            ckAll.checked = flag; // 讓ckAll的checked的狀態和標記同步
        };
    }
</script>
</body>
</html>
```

## 7、元素

爲了提升用戶的體驗,
元素建立的三種方式:

+ document.write("標籤的代碼及內容");
+ 對象.innerHTML="標籤及代碼";
+ document.createElement("標籤的名子");

### (一)document.write()

建立元素有缺陷,若是是在頁面**加載完畢後**,此時經過這種方式建立元素,那麼頁面上存在的全部的內容被幹掉了。

### (二)對象.innerHTML = "內容"

innerHTML 返回dom的內容,若是 = 就是賦予dom內容

outerHTML 會返回 dom自己+本身的內容,若是 = 就是連本身也給替換了

innerText 返回dom的文本內容  若是=須要注意,這個dom內若是有其餘的標籤和內容,就會一同覆蓋掉

```
<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }

    .wrap {
      width: 300px;
      margin: 100px auto 0;
    }

    table {
      border-collapse: collapse;
      border-spacing: 0;
      border: 1px solid #c0c0c0;
      width: 300px;
    }

    th,
    td {
      border: 1px solid #d0d0d0;
      color: #404060;
      padding: 10px;
    }

    th {
      background-color: #09c;
      font: bold 16px "微軟雅黑";
      color: #fff;
    }

    td {
      font: 14px "微軟雅黑";
    }

    tbody tr {
      background-color: #f0f0f0;
    }

    tbody tr:hover {
      cursor: pointer;
      background-color: #fafafa;
    }
  </style>
</head>
<body>
<div class="wrap">
  <table>
    <thead>
    <tr>
      <th>
        <input type="checkbox" id="j_cbAll"/>
      </th>
      <th>菜名</th>
      <th>飯店</th>
    </tr>
    </thead>
    <tbody id="j_tb">
    <tr>
      <td>
        <input type="checkbox"/>
      </td>
      <td>紅燒肉</td>
      <td>田老師</td>
    </tr>
    <tr>
      <td>
        <input type="checkbox"/>
      </td>
      <td>西紅柿雞蛋</td>
      <td>田老師</td>
    </tr>
    <tr>
      <td>
        <input type="checkbox"/>
      </td>
      <td>油炸榴蓮</td>
      <td>田老師</td>
    </tr>
    <tr>
      <td>
        <input type="checkbox"/>
      </td>
      <td>清蒸助教</td>
      <td>田老師</td>
    </tr>

    </tbody>
  </table>
</div>
<script src="./common.js"></script>
<script >
    // 先獲取全先的這個複選框
    var ckAll = my$("j_cbAll");
    // 獲取tbody下的全部複選框
    var cks = my$("j_tb").getElementsByTagName("input");
    // 點擊全選框,獲取當前的狀態,而後設置tbody複選框的狀態
    ckAll.onclick = function () {
        // 循環tbody中的複選框,讓每一個的checked的狀態等於ckAll的狀態
        for (var i=0; i<cks.length; i++) {
            cks[i].checked = this.checked;
        }
    };
    // 爲tbody中的input添加點擊事件
    for (var i=0; i<cks.length; i++) {
        cks[i].onclick = function () {
            // 檢查其餘的input的選中狀態
            var flag = true;
            for (var j=0; j<cks.length; j++) {
                if (!cks[j].checked) { // 當有任何一個沒有選中的時候,就更改標記爲false
                    flag = false;
                    break;
                }
            }
            ckAll.checked = flag; // 讓ckAll的checked的狀態和標記同步
        };
    }
</script>
</body>
</html>
```

### (三)建立元素

document.createElement('標籤名') 建立元素節點

document.createTextNode('文本') 建立文本節點

document.createComment('註釋內容') 建立註釋節點

一、先建立對象

document.createElement("標籤名子") 返回的是一個對象

二、追加到父元素

父元素.appendChild(對象) 追加到父元素的最後

父元素.insertBefore(對象,節點),在父元素內那個子元素前插入

案例一:點擊動態建立列表

```
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div {
            width: 300px;
            height: 500px;
            border: 1px solid #ff4400;
        }
    </style>
</head>
<body>
<input type="button" id="btn" value="添加列表">
<div id="dv"></div>
<script src="./common.js"></script>
<script >
    // 動態的建立li列表,把列表加入到div中
    var kunfu = ["天真", '愛你愛你', '回信息', '精華露', '遴選', '迷你地圖'];
    my$("btn").onclick = function () {
        // 建立ul把ul加入到div中
        var ulObj = document.createElement("ul");
        my$("dv").appendChild(ulObj);
        // 動態的建立li,加入到ul中
        for (var i=0; i<kunfu.length; i++) {
            // 建立Li對象
            var liObj = document.createElement("li");
            // 爲建立好的li對象添加屬性
            liObj.innerHTML = kunfu[i];
            // 追加到父元素ul
            ulObj.appendChild(liObj);
            // 爲建立好的li添加鼠標事件,在循環中添加事件,要使用命名函數
            liObj.onmouseover = mouseoverHandle; // 進入事件
            liObj.onmouseout = mouseoutHandle; // 移出事件
        }
        function mouseoverHandle () {
            this.style.backgroundColor = "red";
        }
        function mouseoutHandle () {
            this.style.backgroundColor = "";
        }

    };
</script>
</body>
</html>
```

案例二:動態建立表格

```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div {
            width: 300px;
            height: 500px;
            border: 1px solid red;
        }
    </style>
</head>
<body>
<input type="button" id="btn" value="添加表格">
<div id="dv"></div>
<script src="./common.js"></script>
<script>
    var tabList = [
        {name: "土豆", href: "http://www.baidu.com"},
        {name: "優酷", href: "http://www.baidu.com"},
        {name: "京東", href: "http://www.baidu.com"},
        {name: "天貓", href: "http://www.baidu.com"},
        {name: "愛奇藝", href: "http://www.baidu.com"},
        {name: "新浪", href: "http://www.baidu.com"}
    ];
    // 點擊建立表格
    my$("btn").onclick = function () {
        // 建立table對象
        var tableObj = document.createElement("table");
        tableObj.border = "1";
        tableObj.cellPadding = "0";
        tableObj.cellSpacing = "0";
        my$("dv").appendChild(tableObj);
        // 動態的建立tr對象
        for (var i = 0; i < tabList.length; i++) {
            var dtObj = tabList[i];
            var trObj = document.createElement("tr");
            tableObj.appendChild(trObj);
            // 建立第一列對象
            var td01 = document.createElement("td");
            td01.innerText = dtObj.name;
            trObj.appendChild(td01);
            // 建立第二列對象
            var td02 = document.createElement("td");
            td02.innerHTML = "<a href="+dtObj.href+">"+dtObj.name+"</a>"; // 拼接第二行的a標籤裏的內容
            trObj.appendChild(td02);
        }
    };
</script>
</body>
</html>
```

### (四)元素相關的操做方法

+ 追加子元素 父元素對象.appendChild("子元素");
+ 插入子元素 父元素對象.insertBefore(新元素,在那個元素以前插入);
+ 替換子元素 父元素對象.replaceChild(新元素,被替換的元素); 返回被替換的元素
+ 刪除子元素 父元素對象.removeChild(刪除的元素); 返回值就是刪除的元素
+ 刪除自身:子元素對象.remove(); 沒有返回值

```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div {
            width: 300px;
            height: 500px;
            border: 1px solid red;
        }
    </style>
</head>
<body>
<input type="button" id="btn" value="添加一個">
<input type="button" id="btn2" value="替換一個">
<input type="button" id="btn3" value="刪除一個">
<input type="button" id="btn4" value="刪除所有">
<div id="dv"></div>
<script src="./common.js"></script>
<script >
    var num = 0;
    my$("btn").onclick = function () {
        num ++;
        var bObj = document.createElement("input");
        bObj.type = "button";
        bObj.value = "按鈕" + num;
        // my$("dv").appendChild(bObj);
        // 把新元素插入到第一個子元素前面
        my$("dv").insertBefore(bObj, my$("dv").firstElementChild);
    };
    my$("btn2").onclick = function () {
        // 用第一個子元素替換最後一個子元素
        my$("dv").replaceChild(my$("dv").firstElementChild, my$("dv").lastElementChild);
    };
    // 刪除一個
    my$("btn3").onclick = function () {
        // 刪除最後一個子元素
        my$("dv").removeChild(my$("dv").lastElementChild);
    };
    // 刪除所有
    my$("btn4").onclick = function () {
        // 判斷父級有沒有第一個子元素,若是刪除完了,就爲false
        while (my$("dv").firstElementChild) {
            my$("dv").removeChild(my$("dv").firstElementChild);
        }
    };
</script>
</body>
</html>
```

### (五)爲同一個元素綁定多個相同的事件

因爲 ele.onXXXX=function(){}一個元素上只能綁定一個事件,後面的會把前面的覆蓋。這時this指向的是dom元素自己

#### 一、addEventListener()

程序this指向的是dom元素自己

```
<script >
    /*
    * 同一個元素有多個點擊事件,若是用對象.onxx只會執行一個,其餘的都被覆蓋了
    * 對象.addEventListener(參數1,參數2, 參數3) 火狐、谷歌支持,可是ie8不支持
    * 參數1:事件的類型 事件的名子,字符串,沒有on
    * 參數2:事件處理函數
    * 參數3:布爾類型 false 冒泡階段 true 捕獲階段
    * */
    // 爲同一個元素綁定多個相同的事件
    my$("btn").addEventListener("click", function () {
        console.log("小明很帥");
    }, false);
    my$("btn").addEventListener("click", function () {
        console.log("小明很帥");
    }, false);
    my$("btn").addEventListener("click", function () {
        console.log("小明很帥");
    }, false);
    my$("btn").addEventListener("click", function () {
        console.log("小明很帥");
    }, false);
</script>
```

#### 二、attachEvent()

程序指向是window

```
/*
    * 對象.attachEvent(參數1, 參數2) 只有ie8能夠用
    * 參數1:事件類型 事件的名子 有on
    * 參數2:事件處理函數
    * */
    my$("btn").attachEvent("onclick", function () {
        console.log("小明很帥");
    });
    my$("btn").attachEvent("onclick", function () {
        console.log("小明很帥");
    });
    my$("btn").attachEvent("onclick", function () {
        console.log("小明很帥");
    });
```

#### 三、兼容性代碼

```
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="button" value="測試" id="btn">
<script src="./common.js"></script>
<script >
    function addEventListener (element, type, fn) {
        // 若是對象裏有這個方法就爲真,注意不加括號,加了括號是判斷返回值是否是真
        if (element.addEventListener) {
            element.addEventListener(type, fn, false);
        } else if (element.attachEvent) {
            element.attachEvent("on"+type, fun); // attachEvent的type是帶on的,因此要加上on
        }else {
            element["on"+ type] = fn;
        }
    }
    // 測試
    addEventListener(my$("btn"), "click", function () {
        console.log("小明好帥");
    });
</script>
</body>
</html>
```

#### 四、綁定事件的區別

總結綁定事件的區別:

addEventListener();
attachEvent();

+ 相同點:

  一、均可覺得元素綁定多個事件;

+ 不一樣點

  一、方法名不同;

  二、參數的個數不同,addEventListener三個參數,attachEvent兩個參數;

  三、瀏覽器的兼容性不同,addEventListener 谷歌、火狐、ie11支持,ie8不支持;attachEvent 谷歌、火狐不支持,ie11不支持,ie8不支持;

  四、this不一樣,addEventListener中的this是當前綁定事件的對象,attachEvent中的this是window;

  五、addEventListener中的事件的類型(事件的名子)沒有On,attachEvent中的事件的類型(事件的名子)有on;

### (六)爲元素解綁事件

一、對象.onclick = function ----> 對象.onclick = null;

二、對象.addEventListener("事件名子不帶On", 命名函數,false)----> 對象.removeEventListener("事件名子不帶On", 命名函數,false)

三、對象.attachEvent("on事件名子",命名函數) ----> 對象.detachEvent("on事件名子",命名函數)

**注意點:**

一、用什麼方式綁定事件,就應該用對應的方式解綁事件,不能互換。 
    
  對象.on事件名子 = 事件處理函數  (綁定事件)
  對象.on事件名子 = null;

二、若是須要解綁,就要在綁定的時候使用命名函數,不能使用匿名函數;

**解綁的兼容性代碼 **

```
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<input type="button" id="btn1" value="綁定">
<input type="button" id="btn2" value="解綁">
<body>
<script src="./common.js"></script>
<script >
    // 綁定事件的兼容性代碼
    function addEventListener (element, name, fn) {
        if (element.addEventListener) {
            element.addEventListener(name,  fn,  false);
        } else if (element.attachEvent) {
            element.attachEvent("on"+name,  fn);
        } else {
            element["on"+name] = fn;
        }
    }
    // 解綁事件的兼容性代碼
    function removeEvent (element, name, fn) {
        if (element.removeEventListener) {
            element.removeEventListener(name, fn, false);
        }else if (element.detachEvent) {
            element.detachEvent("on"+name, fn);
        } else {
            element["on"+name] = null;
        }
    }
    // 測試
    function f1 () {
        console.log("小明好帥");
    }
    function f2 () {
        console.log("小花好漂亮");
    }
    addEventListener(my$("btn1"), "click", f1);
    addEventListener(my$("btn1"), "click", f2);
    // 注意,點擊btn2時,是刪除btn1的綁定事件
    my$("btn2").onclick = function () {
        removeEvent(my$("btn1"), "click", f1);
    };
</script>
</body>
</html>
```

## 8、事件冒泡

事件冒泡:多個元素嵌套,有層次關係,這些元素都註冊了相同的事件,若是裏面的元素的事件觸發了,外面元素的該事件也自動觸發了。 父級的事件子級都繼承,取消冒泡防止父級的事件貫穿到子級

阻止事件冒泡

一、window.event.cancelBubble = true; ie特有的,谷歌支持,火狐不支持

```javascript
<script >
    onload = function () {
        div1.onclick = function () { // 父元素
            alert('div1')
        }
        div2.onclick = function (e) { // 子元素
            console.log(e); // MouseEvent對象
            var e = e || event
            e.cancelBubble = true
            alert('div2')
        }
    }
</script>
```

二、事件參數.stopPropagation(); 谷歌和火狐支持,ie8+;

```javascript
<script >
    onload = function () {
        div1.onclick = function () { // 父元素
            alert('div1')
        }
        div2.onclick = function (e) { // 子元素
            console.log(e); // MouseEvent對象
            var ev = e || event
            ev.stopPropagation()
            alert('div2')
        }
    }
</script>
```



兼容代碼:


事件的三個階段:

一、事件捕獲階段:從外向內

二、事件目標階段:最開始選擇的目標

三、事件冒泡階段:從裏向外

四、觸發順序:先捕獲後冒泡

五、focus、blur、change、submit、reset、select等事件不冒泡

事件參數.eventPhase 查看事件階段

爲元素綁定事件:

addEventListener("沒有on的事件類型",事件處理函數,控制事件階段的),事件觸發的過程當中,可能會出現 事件冒泡的效果,爲了阻止事件冒泡:

window.event.cancelBubble=true;谷歌、ie8支持,火狐不支持;window.event就是一個對象,是ie的標準。

e.stopPropagation();阻止事件冒泡 ==>谷歌和火狐支持

window.event和e都是事件參數對象,一個是Ie的標準,一個是火狐的標準,事件參數e在ie8的瀏覽器中是不存在,此時用window.event來代替。`var event = e ||window.event;`

事件的階段有三個,經過e.eventPhase這個屬性能夠知道當前的事件是什麼階段的,若是 這個屬性的值是:1--捕獲階段 2--目標階段  3--冒泡階段

通常默認都是冒泡階段,不多用捕獲階段

```
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="button" id="btn" value="按鈕">
<script src="./common.js"></script>
<script >
    // 爲同一個元素綁定多個不一樣事件指向同一個事件處理函數
    my$("btn").onclick = f1;
    my$("btn").onmouseover = f1;
    my$("btn").onmouseout = f1;

    function f1 (event) {
        switch (event.type) {
            case "click":
                alert("彈個框");
                break;
            case "mouseover":
                this.style.backgroundColor="red";
                break;
            case "mouseout":
                this.style.backgroundColor="green";
                break;
        }
    }
</script>
</body>
</html>

=============取消冒泡兼容代碼===============
function stopBubble(event){
  if (event.stopPropagation){
    event.stopPropagation();
  }else {
    event.cancelBubble = true;
  }
}
```

## BOM 相關操做

### 1、BOM介紹

瀏覽器的頂級對象:window

頁面中的頂級對象:document

頁面中全部的內容都是屬於瀏覽器的,頁面中的內容也是window。由於頁面中全部的內容都是window的,window能夠省略。

### 2、BOM的對話框

window.alert("內容") 彈框 每一個瀏覽器的樣式不同,只是在測試的時候用

window.prompt("請輸入賬號") 讓用戶輸入 每一個瀏覽器的樣式不同,只是在測試的時候用

var ret = window.confirm("你肯定退出嗎") 點肯定的時候有返回值 true false 每一個瀏覽器的樣式不同,只是在測試的時候用

### 3、加載事件

只要頁面加載完畢,這個事件就會觸發----頁面全部的內容,標籤、屬性、文本、包括外部引入的js文件。

```
window.onload = function () {
  
}; // window 能夠省略,可是最好把js文件都放在最後 
```

頁面關閉後才觸發的事件 谷歌不支持

```
window.onunload = function () {

};
```

頁面關閉以前觸發的 谷歌不支持

```
window.onbeforeunload = function () {

}
```

### 4、window 中的對象

#### (一)location對象

```
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<input type="button" value="顯示效果" id="btn">
<body>
<script >
    /*
    * location對象 既是window的屬性,又是對象
    * */
    // 屬性
    // 返回地址欄裏#及後面的內容,超連接 錨點
    console.log(location.hash);
    // 返回主機名及端口號
    console.log(location.host);
    // 返回主機名
    console.log(location.hostname);
    // 返回文件的相對路徑
    console.log(location.pathname);
    // 返回端口號
    console.log(location.port);
    // 返回協議類型
    console.log(location.protocol);
    // ?及後面的內容 搜索的內容
    console.log(location.search);
    // 方法
    window.onload = function () {
        document.getElementById("btn").onclick = function () {
            // 設置跳轉的頁面的地址 能返回說明有歷史記錄
            location.href = "http://www.baidu.com"; // 屬性 比較重要
            location.assign("http://www.baidu.com"); // 方法
            // 從新加載 刷新
            location.reload();
            // 把地址欄的地址替換,進行跳轉  沒有後退,沒有歷史記錄
            location.replace("http://www.baidu.com")
        };
    };
</script>
</body>
</html>
```

#### (二)history對象

```
document.getElementById("btn2").onclick = function () {
        window.history.forward(); // 至關於瀏覽器的前進 得有歷史記錄
    };

document.getElementById("btn1").onclick = function () {
        window.history.back(); // 至關於瀏覽器上的後退 得有歷史記錄
    };
```

#### (三)navigator對象

```
 // navigator 對象
    // 經過platform 能夠判斷瀏覽器所在的系統平臺類型
    console.log(window.navigator.platform); // MacIntel
    // 判斷瀏覽器的類型
    console.log(window.navigator.userAgent);
```

### 5、定時器

#### (一)setInterval() 反覆

setInterval(參數1, 參數2)

參數1:函數

參數2:時間 毫秒 1000毫秒=1秒

返回值:就是定時器的ID;

執行過程:頁面加載完畢後,過了1秒,執行一次函數的代碼,又過了1秒,再執行函數,注意的是頁面加載完畢,過了間隔的秒後,才執行定時器。



中止定時器:window.clearInterval(參數) 參數:要清理定時器id的值,因此內部的this指向的是window

```
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="button" value="中止定時器" id="btn">

<script >
    // setInteval 每隔多少毫秒執行一次函數 參數1:函數 參數2:間隔時間,返回值是Inteval的id;
    var timeId = setInterval(function () {
        console.log(111);
    }, 1000);
    // clearInterval中止定時器,參數是定時器的Id;
    document.getElementById("btn").onclick = function () {
        clearInterval(timeId);
    };
</script>
</body>
</html>
```

案例一:最簡單的輪播圖

```
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
  <style>
    * {
      margin: 0;
      padding: 0
    }

    ul {
      list-style: none
    }

    img {
      vertical-align: top
    }

    .box {
      width: 730px;
      height: 454px;
      margin: 100px auto;
      padding: 5px;
      border: 1px solid #ccc;
    }

    .inner {
      width: 730px;
      height: 454px;
      background-color: pink;
      overflow: hidden;
      position: relative;
    }

    .inner ul {
      width: 1000%;
      position: absolute;
      top: 0;
      left: 0;
    }

    .inner li {
      float: left;
    }

    .square {
      position: absolute;
      right: 10px;
      bottom: 10px;
    }

    .square span {
      display: inline-block;
      width: 16px;
      height: 16px;
      background-color: #fff;
      text-align: center;
      line-height: 16px;
      cursor: pointer;
    }

    .square span.current {
      background-color: orangered;
      color: #fff;
    }

  </style>
</head>
<body>
<div class="box" id="box">
  <div class="inner"><!--相框-->
    <ul>
      <li><a href="#"><img src="images/1.jpg" alt=""/></a></li>
      <li><a href="#"><img src="images/2.jpg" alt=""/></a></li>
      <li><a href="#"><img src="images/3.jpg" alt=""/></a></li>
      <li><a href="#"><img src="images/4.jpg" alt=""/></a></li>
      <li><a href="#"><img src="images/5.jpg" alt=""/></a></li>
      <li><a href="#"><img src="images/6.jpg" alt=""/></a></li>
    </ul>
    <div class="square">
      <span class="current">1</span>
      <span>2</span>
      <span>3</span>
      <span>4</span>
      <span>5</span>
      <span>6</span>
    </div>
  </div>
</div>
<script >
    // 一、獲取最外面的div
    var boxObj = document.getElementById("box");
    // 二、獲取相框和相框的寬度
    var photoFrame = boxObj.firstElementChild;
    var photoWidth = photoFrame.offsetWidth;
    // 三、獲取ul
    var ulObj = photoFrame.firstElementChild;
    // 四、獲取全部的span
    var spanObjs = photoFrame.lastElementChild.children;
    // 五、循環全部的span標籤,註冊進入事件
    for (var i=0; i<spanObjs.length; i++) {
        // 添加自定義屬性,用來解決事件發生時,i已經循環完畢,沒法拿到索引值的問題
        spanObjs[i].setAttribute("index", i);
        // 爲每一個span註冊鼠標進入事件
        spanObjs[i].addEventListener("mouseover", f1, false);

    }
    // 鼠標進入事件的函數
    function f1 () {
        // 先幹掉全部span的class類
        for (var i=0; i<spanObjs.length; i++) {
            spanObjs[i].removeAttribute("class");
        }
        // 再爲當前的鼠標設置類
        this.className = "current";
        // 移動ul的位置 負的每張圖片的寬度*索引
        animation(ulObj, -this.getAttribute("index")*photoWidth);
        
    }
    function animation (element, goal) {
        // 爲了只產生一個定時器,先清理,再建立,還有一種辦法就是加鎖
        clearInterval(element.intervalId);
        // 爲了防止點一按鈕開闢一塊內存空間,直接把變量看成對象的屬性,由於對象相同的屬性只有一個
        // var intervalId = setInterval(function () {
        element.intervalId = setInterval(function () {
            // 獲取div的當前位置
            var current = element.offsetLeft; // offsetleft獲得的是數字類型沒有px;
            // div每次移動多少
            var step = 9;
            step = goal>current?step:-step; // 目標大於當前就是正數的step 不然爲負數的step
            // 每次移動後的距離
            current += step;
            // 設置div的目標位置
            if (Math.abs(goal-current)>Math.abs(step)) { //若是目標減去當前的絕對值大於移動位置的絕對值
                element.style.left = current + "px"; // 設置移動的距離爲增長或減小後的值
            } else {
                element.style.left = goal + "px"; // 不然讓最後那點距離等於目標值。如 當前位置396 目標400 之間的差4小於step9,定時器就停了
                // 而位置卻沒到,就直接讓等於目標值就好了。
                clearInterval(element.intervalId);

            }
        }, 20);
    }
</script>
</body>
</html>
```

案例二 完整的輪播圖

```
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
  <style type="text/css">
    * {
      padding: 0;
      margin: 0;
      list-style: none;
      border: 0;
    }

    .all {
      width: 500px;
      height: 200px;
      padding: 7px;
      border: 1px solid #ccc;
      margin: 100px auto;
      position: relative;
    }

    .screen {
      width: 500px;
      height: 200px;
      overflow: hidden;
      position: relative;
    }

    .screen li {
      width: 500px;
      height: 200px;
      overflow: hidden;
      float: left;
    }

    .screen ul {
      position: absolute;
      left: 0;
      top: 0px;
      width: 3000px;
    }

    .all ol {
      position: absolute;
      right: 10px;
      bottom: 10px;
      line-height: 20px;
      text-align: center;
    }

    .all ol li {
      float: left;
      width: 20px;
      height: 20px;
      background: #fff;
      border: 1px solid #ccc;
      margin-left: 10px;
      cursor: pointer;
    }

    .all ol li.current {
      background: #DB192A;
    }

    #arr {
      display: none;
    }

    #arr span {
      width: 40px;
      height: 40px;
      position: absolute;
      left: 5px;
      top: 50%;
      margin-top: -20px;
      background: #000;
      cursor: pointer;
      line-height: 40px;
      text-align: center;
      font-weight: bold;
      font-family: '黑體';
      font-size: 30px;
      color: #fff;
      opacity: 0.3;
      border: 1px solid #fff;
    }

    #arr #right {
      right: 5px;
      left: auto;
    }
  </style>
</head>
<body>
<div class="all" id='box'>
  <div class="screen"><!--相框-->
    <ul>
      <li><img src="images/1.jpg" width="500" height="200"/></li>
      <li><img src="images/2.jpg" width="500" height="200"/></li>
      <li><img src="images/3.jpg" width="500" height="200"/></li>
      <li><img src="images/4.jpg" width="500" height="200"/></li>
      <li><img src="images/5.jpg" width="500" height="200"/></li>
    </ul>
    <ol>
    </ol>
  </div>
  <div id="arr"><span id="left">&lt;</span><span id="right">&gt;</span></div>
</div>
<script >
    // 移動動畫函數
    function animation (element, goai) {
        // 每次點擊以前都先清除一下定時器
        clearInterval(element.intervalId);
        // 爲了防止點一次產生一個定時器,讓定時器作爲element的屬性,由於屬性只有一個
        element.intervalId = setInterval(function () {
            // 獲取當前的位置
            var current = element.offsetLeft; // 獲得是一個數字類型的,沒有px
            // 設置步長
            var step = 9;
            step = goai>current?step:-step; // 判斷向左移動仍是向右移動
            // 移動後的位置
            current += step;
            // 設置left值 判斷到沒到位置,只須要判斷,目標和當前位置的差是否是大於步長
            if (Math.abs(goai-current)>Math.abs(step)) {
                element.style.left = current + "px";
            } else {
                element.style.left = goai + "px"; // 由於步長的關係,還有一點距離,這個時候,讓他直接等於目標的值就能夠了
                clearInterval(element.intervalId); // 清除定時器
            }
        }, 10);
    }
    // 第一步獲取全部須要用的元素
    var boxObj = document.getElementById("box"); // box
    var phoneObj = boxObj.children[0]; // 相框
    var phoneWidth = phoneObj.offsetWidth; // 相框的寬度
    var ulObj = phoneObj.children[0]; // ul
    var liObjs = ulObj.children; // li
    var olObj = phoneObj.children[1]; // ol
    var arrObj = document.getElementById("arr"); // 按鈕
    var leftObj = document.getElementById("left"); //左按鈕
    var rightObj = document.getElementById("right"); // 右按鈕
    var index = 0; // 建立一個全局的變量,用於ol中的索引和左右兩邊的按鈕同步
    // 第二步建立小按鈕,根據li的個數 同時註冊鼠標進入事件
    for (var i=0; i<liObjs.length; i++) {
        // 根據循環的次數建立ol中的li的個數
        var olLiObj = document.createElement("li");
        // 在每一個li中添加自定義的屬性,存儲index值
        olLiObj.setAttribute("index", i);
        olObj.appendChild(olLiObj);
        // Ol中的數字
        olLiObj.innerHTML = i + 1; // 由於i是從0開始的
        // 註冊鼠標進入事件,兩件事,一是改變背景顏色,二是移動圖片
        olLiObj.onmouseover = function () {
            // 先幹掉ol中li全部的背景
            for (var j=0; j<olObj.children.length; j++) {
                olObj.children[j].removeAttribute("class");
            }
            // 設置當前鼠標進來的li的背景顏色
            this.className = "current";
            // 獲取鼠標進入後當前的li的索引值
            index = this.getAttribute("index");
            // 移動ul 負的索引值*相框的寬度,就是移動的位置
            animation(ulObj, -index*phoneWidth);

        };
        // 註冊鼠標進入事件
        olLiObj.onmouseout = function () {

        };
    }
    // 默認給第一個增長背景
    olObj.children[0].className = "current";
    // 克隆一個ul中的第一個li,加入到ul的最後
    var copyLi = liObjs[0].cloneNode(true); // 誰調用這個方法就克隆誰
    ulObj.appendChild(copyLi);
    var intervalId = setInterval(rightClick, 2000); // 自動播放
    // 鼠標進入box 顯示左右的按鈕
    boxObj.onmouseover = function () {
        clearInterval(intervalId);
        arrObj.style.display = "block";

    };
    // 鼠標離開box 隱藏左右的按鈕
    boxObj.onmouseout = function () {
        intervalId = setInterval(rightClick, 2000);
        arrObj.style.display = "none";
    };
    // 右邊按鈕的點擊
    /*
    * 當點擊到最後一張圖片的時候,也就是index=5的時候,直接讓left的值等於0,而且把index值也設爲0。
    * */
    function rightClick () {
        if (index==liObjs.length-1) {
            index = 0;
            ulObj.style.left = 0 + "px";
        }
        index ++;
        animation(ulObj, -index*phoneWidth);
        // 若是index ==5的時候,此時顯示第6張圖片,內容是第一張的,第一小按鈕有顏色
        if (index == liObjs.length-1) {
            // 第一個按鈕的顏色設置上
            olObj.children[0].className = "current";
            // 第五個按紐的顏色幹掉
            olObj.children[olObj.children.length-1].removeAttribute("class");
        } else {
            // 其餘地方就是排他功能
            // 刪除全部的
            for (var i=0; i<olObj.children.length; i++) {
                olObj.children[i].removeAttribute("class");
            }
            // 添加當前的
            olObj.children[index].className = "current";
        }
    }
    rightObj.onclick = rightClick;
    // 左邊按鈕的點擊
    leftObj.onclick = function () {
        // 當index是0的時候,直接跳到第六張圖,同時把index也改爲第六張圖的
        if (index == 0) {
            index = liObjs.length-1;
            ulObj.style.left = -index*phoneWidth + "px";
        }
        index --;
        animation(ulObj, -index*phoneWidth);
        // 設置小按鈕的顏色
        // 全部的先幹掉
        for (var i=0; i<olObj.children.length; i++) {
            olObj.children[i].removeAttribute("class");
        }
        // 添加當前的
        olObj.children[index].className = "current";
    };
</script>
</body>
</html>

```

變速動畫封裝

```
<script >
    /*
    * zIndex的值一步到位就行,opacity:獲取的時候,放大100倍,目標也放大100倍,賦值的時候縮小100倍,方便計算
    * */
    /**
     * 獲取任意對象屬性
     * @param element 對象
     * @param attr 屬性
     * @returns {string} 屬性的值
     */
    function getStyle(element, attr) {
        return window.getComputedStyle?window.getComputedStyle(element, null)[attr]:element.currentStyle[attr];
    }

    /**
     * 可以根據json對象裏的屬性值發生變速動畫的函數
     * @param element 對象
     * @param json 屬性值的json對象
     * @param fn 回調函數
     */
    function moreAnimation (element, json, fn) {
        clearInterval(element.intervalId);
        element.intervalId = setInterval(function () {
            var flage = true;
            for (var attr in json) {
                if (attr == "zIndex") { // 是否是zindex
                    element.style[attr] = json[attr];
                }else if (attr == "opacity") { // 是否是opacitty
                    // 獲取當前的透明度,擴大100倍
                    var current = getStyle(element, attr) *100; // 這裏不用加parseInt,由於字符串*數字是按數字計算的不是拼接
                    // 獲取目標透明度,擴大100倍
                    var target = json[attr] * 100;
                    // 步長
                    var step = (target-current)/10;
                    step = step>0?Math.ceil(step):Math.floor(step);
                    // 變化後的值
                    current += step;
                    // 設置 再縮小100倍
                    element.style[attr] = current / 100;
                    if (current != target) {
                        flage = false;
                    }
                } else { // 普通屬性
                    // 獲取當前的位置
                    var current = parseInt(getStyle(element, attr));
                    // 獲取目標的值
                    var target = parseInt(json[attr]);
                    // 步長
                    var step = (target-current)/10;
                    step = step>0?Math.ceil(step):Math.floor(step);
                    // 移動後的距離
                    current += step;
                    // 設置
                    element.style[attr] = current + "px";
                    if (current != target) {
                        flage = false;
                    }
                }
            }
            if (flage) {
                clearInterval(element.intervalId);
                if (fn) {
                    fn();
                }
            }
        }, 20)
    }

    // 測試
    var btnObj = document.getElementById("btn");
    var dvObj = document.getElementById("dv");
    btnObj.onclick = function () {
        moreAnimation(dvObj, {"width":400, "height":500, "left":500, "top":300, "zIndex":1000, "opacity":0.2}, function () {
            moreAnimation(dvObj, {"width":40, "height":50, "left":50, "top":30, "zIndex":1000, "opacity":0.8})
        })
    }
</script>
```

#### (二)setTimeout()一次性

setTimeout(函數,時間);時間仍是毫秒 返回值:仍是該定時器的ID

執行過程:一次性的定時器

中止定時器:window.clearTimeoutl(參數) 參數:要清理定時器id的值,因此內部的this指向的是window



### (三)直接經過document獲取屬性

```
  //獲取body
  console.log(document.body);//獲取的是元素--標籤
  //獲取title
  console.log(document.title);//標籤中的值
  document.title="嘎嘎去"; // 設置
  //獲取html
  console.log(document.documentElement);
```

## 9、一些屬性和方法

### (一)offset系列中的屬性

值都是數字類型,元素的樣式屬性是沒法直接經過:對象.style,屬性來獲取的(由於樣式在style標籤中設置的,只有在style屬性中設置的才能獲取)

+ offsetLeft:距離左邊位置的值,忽略自身是否是定位元素,若是父級是定位元素,那麼距離是到父級的距離,若是不是定位元素,則是到外邊框的距離。
+ offsetTop:距離上邊位置的值 規則同上
+ offsetWidth:元素自己的寬,無論內容 元素的尺寸
+ offfsetheight:元素的高,無論內容 元素的尺寸
+ `offsetParent`返回最近的有定位的父級,若是沒有,返回body,body.offsetParent返回null

#### 一、沒有脫離標準的文檔流

offsetLeft:父級元素margin+父級元素padding+父級元素的border+本身的margin

#### 二、脫離了標準文檔流

主要是本身的left和本身的margin

### (二)scroll系列:捲曲--滾出去

+ scrollWidth 元素中內容的實際寬度,若是沒有內容,就是元素的寬度

+ scrollHeight 元素中內容的實際的高,若是沒有內容,就是元素的高

+ scrollTop:向上捲曲出去的距離,有了滾動條以後,從可視區沒法看到部分的高度,也就是超出部分的高度

+ scrollLeft:向左捲曲出去的距離,有了滾動條以後,從可視區沒法看到部分的寬度,也就是超出部分的高度 

+ 兼容性的問題:(都是查看滾動條的滾動距離)

  1. window.pageXOffset或者window.pageYOffset IE8及IE8如下不兼容;

  2. document.body.scrollLeft/Top

     document.documentElement.scrollLeft/Top (ie8和ie8如下的瀏覽器兼容,可是具體那個好使是沒有定論的,有可能ie7上面的好使,也有可能下面的好使,有一個規律,在一個瀏覽器上只要上面的有值,那麼下面的必定爲零,反之下面的有值,上面的就沒值,相加以後就能夠兼容ie8和ie8如下的瀏覽器了)

```
獲取向上捲曲出去的距離的兼容代碼
var scrollTop = window.pageYoffset || document.documentElement.scrollTop ||document.body.scrollTop || 0;
也能夠這樣:
var scrollTop = window.pageYoffset || document.documentElement.scrollTop + document.body.scrollTop || 0;
獲取向左捲曲出去的距離的兼容代碼
var scrollLeft = window.pageXoffset || document.documentElement.scrollLeft ||document.body.scrollLeft || 0;
也能夠這樣:
var scrollLeft = window.pageXoffset || document.documentElement.scrollLeft + document.body.scrollLeft || 0;
```

### (三)client系列:可視區

+ clientWidth:可視區域的寬(沒有邊框)邊框內部的寬度
+ clientHeight:可視區域的高(沒有邊框)邊框內部的高度
+ clientLeft:左邊邊框的寬度
+ clientTop:頂部邊框的寬度
+ clientX:可視區域的橫座標
+ clientY:可視區域的縱座標

查看可視區窗口的尺寸(能夠看到的html代碼,能看到的部分,不包括瀏覽器的導航欄,控制檯等,頁面的縮放會影響到可視區窗口的尺寸)

1. `window.innerWith/innerHeight`w3c標準的。 ie8及ie8如下不兼容

2. ie8及ie8如下兼容

   `document.documentElement.clientWidth/clientHeight` 標準模式下(有`<!DOCTYPE html>`這行的就是標準模式,沒有就是怪異模式/混雜模式 向後兼容),任意瀏覽器都兼容

   `document.body.clientWidth/clientHeight` 適用於怪異模式下的瀏覽器

案例圖片跟着鼠標 兼容代碼的封裝過程

```
var imgObj = document.getElementById("im");
    // 火狐 谷歌
    document.onmousemove = function (e) {
        imgObj.style.left = e.clientX + "px";
        imgObj.style.top = e.clientY + "px";
    };
    // 事件參數對象e只有谷歌和火狐有,ie8沒有,ie8是window.event來代替e。可是在火狐裏不支持window.event,谷歌支持
    document.onmousemove = function () {
        imgObj.style.left = window.event.clientX + "px";
        imgObj.style.top = window.event.clientY + "px";
    };
    // 當有了滾動條以後,鼠標超過了可視區,如:y座標(pageX/pageY)=滾動出去的距離+clientY;圖標就不會跟鼠標了,而會找clientY/X;
    document.onmousemove = function (e) { // 谷歌支持,火狐支持 ie8不支持window.enevt.pageX和window.event.pageY這兩個屬性
        imgObj.style.left = e.pageX + "px";
        imgObj.style.top = e.pageY + "px";
    };
    // ie8 支持
    function getScroll () { // scroll兼容代碼
        return {
            left:window.pageXOffset||document.body.scrollLeft||document.documentElement.scrollLeft||0,
            top:window.pageYOffset||document.body.scrollTop||document.documentElement.scrollTop||0
        }
    }
    document.onmousemove = function () {
        imgObj.style.left = window.event.clientX + getScroll().left + "px";
        imgObj.style.top = window.event.clientY + getScroll().top + "px";
    };
===============================================================================

// 終極兼容版
    // 用到了對象的一個方法調用另外一個方法
    obj = {
        sayHi:function () {
            console.log("sayHi方法");
            this.eat(); // 調用eat方法
        },
        eat:function () {
            console.log("eat方法");
        }
    };
    /*
    * 兼容了那些:
    * 一、window.event和事件參數對象e的兼容
    * 二、 clientX和clientY單獨的使用的兼容代碼
    * 三、scrollleft和scrolltop的兼容代碼
    * 四、pageX,pageY和clientX+scrollLeft和clientY+scrollTop
    * 封裝在對象中
    * */
    var evt = {
        // window.event和e的兼容
        getEvent:function (evt) {
            return window.event || evt; // 至關於var a = 0 || 1; a是1;若是有window.event,就用window.event,沒有就用evt,
        },
        // 可視區域橫座標的兼容代碼
        getClientX:function (evt) {
            return this.getEvent(evt).clientX;
        },
        // 可視區域縱座標的兼容代碼
        getClientY:function (evt) {
            return this.getEvent(evt).clientY;
        },
        // scrollLeft和scrollTop的兼容代碼
        /*頁面向左捲曲出去的橫座標*/
        getScrollLeft:function () {
            return window.pageXOffset||document.body.scrollLeft||document.documentElement.scrollLeft||0;
        },
        /*頁面向上捲曲出去的縱座標*/
        getscrollTop:function () {
            return window.pageYOffset||document.body.scrollTop||document.documentElement.scrollTop||0;
        },
        // 相對於頁面的橫座標(pagex或者是clientX+scrollLeft)
        getPageX:function (evt) {
            return this.getEvent(evt).pageX?this.getEvent(evt).pageX:this.getScrollLeft()+this.getClientX(evt);
        },
        // 相對於頁面的縱座標(pagey或者是clientY+scrollTop
        getPageY:function (evt) {
            return this.getEvent(evt).pageY?this.getEvent(evt).pageY:this.getscrollTop()+this.getClientY(evt);
        }

    };
    // 測試
    var imObj = document.getElementById("im");
    document.onmousemove = function (e) {
        imObj.style.top = evt.getPageY(e) + "px";
        imObj.style.left = evt.getPageX(e) + "px";
    };
```

### (四)查看元素的幾何尺寸

`dom元素.getBoundingClientRect()`獲得一個對象包,裏面有所選擇元素的幾乎一切信息,和offset系列功能同樣,沒offset系列好用。

1. 兼容性很好;
2. 該方法返回一個對象,對象裏面有left, top, right, bottom等屬性。left和top表明該元素左上角的X和Y座標,right和bottom表明元素右下角的X和Y座標。
3. height和width屬性老版本IE並未實現。
4. 返回的結果不是實時的;

### (五)讓滾動條滾動

1. `window.scroll()`
2. `window.scrollTo()`
3. window.scrollBy()
4. 三個方法功能相似,用法都是將x,y座標傳入,即實現讓滾動輪滾動到當前位置。
5. 區別:scrollBy()會在以前的數據基礎之上作累加

## 10、閉包

### (一) [[scope]] 

每一個javascript的函數都是一個對象,對象中有些屬性能夠訪問,可是有些不能夠,這些屬性僅供javascript引擎存取,scope就是其中一個,scope就是咱們所說的做用域,其中存儲了運行期上下文的集合,就是ao和go

### (二) 做用域鏈

scope中存儲的運行期上下文對象的集合,這個集合呈鏈式連接,把這個鏈式鏈接叫作做用域鏈

### (三) 運行期上下文

當函數執行時,會建立一個稱爲執行期上下文的內部對象,(AO/GO),一個執行期上下文定義了一個函數的執行環境,函數執行時,對應的執行上下文都是獨一無二的,屢次調用函數,會建立多個執行上下文,當函數執行完畢,所產生的執行上下文被銷燬

查找變量:從做用域鏈的頂端依次向下查找

當一個函數a被定義的時候 [[scope]]存儲的第0位的是GO

當一個函數a被執行的時候 [[scope]]存儲的第0位就變成了AO,第一位就變成了GO。

![](media/scope1.png)

![](media/scope2.png)

### (四) 閉包

當內部函數被保存到外部時,將會生成閉包,閉包會致使原有做用域不被釋放,形成內存泄露

兩個函數嵌套,把裏面的函數保存到了外部全局,就行成了裝飾,它保存着父級函數的做用域AO

給一個標籤綁定一個事件,至關因而將事件外理函數保存在了js以外的標籤屬性上,那麼也就行成了閉包,若是正好這個事件外理函數在一個循環的函數中,那麼他就會保存着父級函數的AO,AO對象存儲着變量的值,這個值會隨着循環更新,停在循環最後一個值上,若是想要拿到循環時候的每一個值,就須要在事件函數的外面加一個當即執行函數,這樣事件函數就會存儲當即執行函數的AO對象,而這個AO裏的變量屬性是每次跟着循環獲得的值,這個值是不會變的

```
function createLi (n) {
    var divObj = document.createElement("div");
    var div = document.body.appendChild(divObj);
    var ulObj = document.createElement("ul");
    div.appendChild(ulObj);
    for (var i=0;i<n;i++)  {
        var liObj = document.createElement("li");
        ulObj.appendChild(liObj);
        liObj.style.backgroundColor=i%2==0?"red":"yellow";
        (function (j) {
            liObj.onclick = function () {
                alert(j);
            }
        }(i));
    }
}
```

只要是運行期的上下文被保存到了函數的外部,都行成了閉包

```javascript
var obj = {};
function a () {
  var aa = 123;
  function b () {
    console.log(aa)
  }
  obj.fun = b; // 這個b被保存到了函數外部,obj對象裏,就造成了閉包
}
```



### (五)閉包的做用

* 實現共有變量

  * 函數累加器

* 能夠做緩存(存儲結構)

* 實現封裝,屬性私有化

* 模塊化開發,防止污染全局變量

  ```javascript
  <script >
          var name = 'bcd';
          var init = (function () {
              var name = 'abc';
              function callName () {
                  console.log(name);
              }
              return function () {
                  callName();
              }
          }())
          console.log(name); // bcd
          init() // abc
      </script>
  ```

  

## 11、原型

定義:原型是function對象的一個屬性,它定義了構造函數製造出的對象的公共祖先,經過該構造函數產生的對象,能夠繼承該原型的屬性和方法,原型也是對象,沒有屬性和方法以前就是一個只有constructor屬性值是函數自己的一個對象。

+ 利用原型的特色和概念能夠提取公共屬性。

```javascript
<script >
        Car.prototype.height = 1400;
        Car.prototype.lang = 4900;
        Car.prototype.carName = "BMW";
        function Car (color, owner) {
            this.owner = owner;
            this.color = color;
            // this.height = 1400;  // 能夠把這些共有的屬性提取到原型對象上,沒必要要每次建立一個對象,就添加一次
            // this.lang = 4900;
            // this.carName = "BMW";
        }
        var car1 = new Car('red', 'ww')
        var car2 = new Car('green', 'bb')
    </script>
```

+ 對象如何查看原型: 隱式屬性`__proto__`
+ 對象如何查看對象的構造函數  constructor
+ 訪問一個對象的屬性時,先在基本屬性中查找,若是沒有,再沿着`__proto__`這條鏈向上找,這就是原型鏈。
+ 如何區分一個屬性究竟是基本的仍是從原型中找到的呢?——hasOwnProperty,特別是在for…in…循環中,必定要注意

![原型](media/原型.png)

+ 原型的修改和刪除,不能經過對象.屬性的方式修改和刪除,必須用`構造函數.prototype.屬性`的方式修改,刪除也不能使用`delete 對象.屬性`的方式刪除,要使用`delete 構造函數.prototype.屬性`的方式刪除。

```javascript
<script >
        // 原型屬性的修改
        Person.prototype.lastName = 'uu';
        function Person(name) {
            this.name = name
        }
        var person = new Person('ww');
        // 不能這樣修改原型的屬性
        person.lastName = 'bb'; // 這樣會在對象上增長一個屬性lastName
        Person.prototype.lastName = 'cc'; // 這樣纔會修改原型對象的屬性
    </script>
```

+ 另外一種寫法, 這種方式和函數.prototype.屬性 = 值 修改對象,一種是直接修改引用值。

```javascript
構造函數.prototype = {
  name="kk",
  age=18
}
```

+ 絕大多數的對象最終都會繼承自object.prototype,可是有一個例外,object.create(原型/null),使用null參數建立的對象是個例外。

總結:

- 任何函數都具備一個 `prototype` 屬性,prototype裏有`constructor`屬性
- 構造函數的 `prototype` 對象默認都有一個 `constructor` 屬性,指向 `prototype` 對象所在函數,能夠修改

```javascript
<script >
        function Person() {

        }
        function NewPerson() {

        }
        Person.prototype = {
            constructor: NewPerson
        };
        var person = new Person()
        console.log(person.constructor); //ƒ NewPerson() {}
    </script>
```

- 經過構造函數獲得的實例對象內部會包含一個指向構造函數的 `prototype` 對象的指針 `__proto__`

  ```javascript
  <script >
          Grand.prototype.lastName = 'grandProto'
          function Grand() {
          }
          var grand = new Grand();
          Father.prototype = grand
          function Father(name) {
              this.name = name
              this.fourth = {
                  card1: 'vasia'  // 對於引用值,能夠使用son.fourth.card2 = 'jianshe' 這樣進行修改
              }
              this.num = 100 // 不是引用類型的,經過son.num ++ ,這樣的操做,不能修改,只能增長到自身
          }
          var father = new Father('father')
          Son.prototype = father
          function Son(hobbit) {
              this.hobbit = hobbit
          }
          var son = new Son('somke')
      </script>
  ```

- 全部實例都直接或間接繼承了原型對象的成員

- Object.create(原型)

  ```javascript
  <script >
    Person.prototype.lastName = 'cc'
  function Person() {
    this.name = 'ww'
  }
  var bb = Object.create(Person.prototype) // 建立一個對象出來,建立出來的這個對象的原型就是括號裏面寫的對象。
  console.log(bb.lastName);
  </script>
  ========================
  var demo = {
      lastName: "小花"
    };
  var obj = Object.create(demo);
  // 而這個obj對象是個空對象,可是他裏面有個屬性__proto__值是demo,他自身沒有lastName屬性的時候,就會去原型上去找。
  // obj = {__proto__: demo}
  ```

- undefined,null沒有原型

- call/apply 改變this指向 區別後面傳的參數的形式不一樣。借用別人的函數,實現本身的功能

函數()=函數.call(參數1,參數2...)  參數1,改變this指向的對象,參數2之後正常的函數參數

```javascript
<script >
        function Person(name, age) {
            this.name = name;
            this.age = age;
        }
        obj = {};
        Person.call(obj, 'ww', 18);
        console.log(obj); // {name: "ww", age: 18}
    </script>
```

函數()=函數.apply(參數1,[參數2...]) 參數1,改變this指向的對象,函數的正常參數要放在一個數組中。

```javascript
function Person(name, age) {
            this.name = name;
            this.age = age;
        }
        obj = {};
        Person.apply(obj, ['ww', 18]);
        console.log(obj);
```

區別:

call:須要把實參按形參的個數傳進去

applay:須要傳一個arguments

應用:

```
// call、apply
function Father (name, age) {
    this.name = name;
    this.age = age;
}
function Son (name, age, phone, email) {
    Father.call(this, name,  age);
    this.phone = phone;
    this.email = email;
}
var son = new Son("小花", 13, 1443322323, "wlrjwr@163.com")
```

## 12、繼承

### 傳統形式:原型鏈繼承

過多的繼承了沒用的屬性

```javascript
<script >
        Grand.prototype.lastName = 'ji';
        function Grand(){}
        var grand = new Grand();
        Father.prototype = grand;
        function Father () {
            this.name = 'hehe'
        }
        var father = new Father();
        Son.prototype = father;
        function Son () {}
        var son = new Son()
    </script>
```

### 借用構造函數

不能繼承借用構造函數的原型

每次構造函數都要多走一個函數 

```javascript
function Person (name, age, sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
        function Student (name, age, sex, grade) {
            Person.call(this, name, age, sex);
            this.grade = grade;
        }
        var student = new Student('ww', 12, '女', 'bb')
```

### 共享原型

不能隨便改動本身的原型

```javascript
Father.prototype.lastName = '張';
function Father () {}
function Son () {}
Son.prototype = Father.prototype
var son = new Son()
```

當Son的原型想增長東西的時候,勢必形成Father的原型上也增長了東西

### 聖盃繼承

```javascript
// 聖盃模式 普通版
Father.prototype.lastname = "eee";
function Father (name) {
    this.name = name;
}
var father = new Father("mjc");
function Son (age) {
    this.age = age;
}
function Inherit (Target,Origin) {
    function F() {};
    F.prototype = Target.prototype;
    Origin.prototype = new F(); // 注意這行不能在F的原型改變以前,必定要在後面。緣由是new的時候的原型必定是要改變後的原型
    Origin.prototype.constructor = Origin; // 改變原型的constructor指向自身的構造函數,不改變的話,構造函數會指向父類
    Origin.prototype.uber = Origin.prototype; // 找到超類,究竟繼承自誰,爲了信息的一個存儲
}
Inherit(Father, Son);
var son = new Son(18);

// 聖盃模式 雅虎版
Father.prototype.lastname = "eee";
function Father (name) {
    this.name = name;
}
var father = new Father("mjc");
function Son (age) {
    this.age = age;
}
var inherit = (function () {
    var F = function () {}; // 閉包的屬性私有化,不想讓外界訪問這個屬性
    return function (Target,Origin) {
        F.prototype = Target.prototype;
        Origin.prototype = new F();
        Origin.prototype.constructor = Origin;
        Origin.prototype.uber = Origin.prototype;
    }
}());
inherit(Father, Son);
var son = new Son(18);
```




## 11、this指向

全局做用域裏this指向window

call/apply能夠改變函數運行時的this指向

```javascript
function test() {
  console.log(this)
}
test.call({name:'小花'});
// 至關因而
test() -- > AO {
  arguments: {},
  this: window --> {name:'小花'}
}
一、預編譯: this --> window
二、誰調用的this 指向誰
var name = 'window';
var obj = {
  name: 'obj',
  say: function (){
    console.log(this.name)
  }
}
obj.say() // obj
obj.say.call(window); // window
var fun = obj.say
fun() // window
fun.call(obj) // obj
三、call apply 改變指向
四、全局this --> window
```

普通函數中的this:window 至關因而window.函數(),(函數預編譯過程當中,this指向window)

對象方法中的this: 當前的實例對象;

定時器方法中的this:也是window

構造函數中的this:當前的實例對象

原型對象方法中的this:當前的實例對象;

jquery爲何能連續的點方法或屬性,由於return this。

當new一個函數時,至關因而在函數裏建立了一條下面的語句

`var this = Object.create(函數.prototype)`準確的來講是在這個對象裏添加了this對象,而這個this對象裏添加了`__proto__:函數.prototype`。

## 12、try catch

不拋出錯誤,後續代碼繼續執行(try裏的代碼出錯的那行如下不會再執行),把錯誤放到catch的參數e裏。

```javascript
try{
  console.log('a');
  console.log(b); // 出錯行
  console.log('c'); // 不執行
} catch(e){
  console.log(e.name); // 錯誤名稱
  console.log(e.message)
}
console.log('d') // 會執行
```

e.name 的六種對應的信息:

一、EvalError:eval()的使用與定義不一致;

二、RangeError:數值越界

三、ReferenceError: 非法或者不能識別的引用數值 ,變量、函數 沒聲明就使用,

四、SyntaxError:發生語法解析錯誤;

五、TypeError:操做類型錯誤;

六、uRLError:URL處理函數使用不當;

## 十3、es5嚴格模式

不使用嚴格模式的狀況下是:基於es3的+es5的新增方法,使用的,出現衝突,以es3的方法爲主。

嚴格模式就是出現衝突的時候以es5的方法爲主

"use strict"  寫在邏輯的最頂端。全局的。局部的,寫在函數代碼的最頂端

再也不兼容e3的一些不規範的語法,使用全新的es5規範

兩種用法:

一、全局嚴格模式

二、局部函數內嚴格模式(推薦)

就是一行字符串,不會對不兼容嚴格模式的瀏覽器產生影響。

嚴格模式下,不支持with(改變做用域鏈,改變AO), arguments.callee, func.caller 變量賦值前必須聲明,(隱式全局變量不能用了)局部this必須被賦值(Person.call(null/undefined,賦什麼就是什麼),拒絕重複屬性和參數。

```javascript
var obj = {
  name: "obj"
}
var name = "window";
function test() {
  var age = 123;
  var name = 'scope';
  with (obj){
    console.log(name); // obj
    console.log(age); // 123
  }
}
==================
"use strict"
function Test() {
  console.log(this) // 也就是預編譯的時候,再也不指向window而是指向了空
}
Test() // undefined
new Test() // test{}
Test.call({}) // {}
```



## 十3、小技巧工具方法

### 一、實現jquery連續調用方法

```javascript
<script >
        // 方法的連續調用
        var fanfa = {
            smoke:function () {
                console.log("抽菸有害健康");
                return this;
            },
            drink:function () {
                console.log('喝酒有害健康');
                return this;
            }
        }
        fanfa.smoke().drink();
    </script>
```

## 二、自定義的typeof

```javascript
function myType(target) {
  var ret = typeof(target);
  template = {
    "[object Array]": "arrery",
    "[object Object]": "object",
    "[object Number]": "number-object",
    "[object Boolean]": "boolean-object",
    "[object String]": "string-object"
  };
  if (target === null) {
    return 'null';
  }else if(ret == 'object') {
    var str = Object.prototype.toString.call(target);
    return template[str];
  } else {
    return ret;
  }
}
```

### 自定義的數組去重方法

```javascript
// 數組的去重,思路:把數組的每個元素放到對象中去,給一個隨意的值,由於對象中的每一個屬性是不重複的,達到去重的效果
Array.prototype.unique = function () {
  var temp = {},
      arr = [],
      len = this.length;
  for (var i=1;i<len;i++) {
    if (! temp[this[i]]) {
      temp[this[i]] = 'abc';
      arr.push(this[i]);
    }
  }
  return arr;
}
```




## 性能

循環裏添加匿名函數效率低,要改爲命名函數,放在循環的外面,若是不是循環的方式添加事件,推薦使用匿名函數

異步加載js

js加載的缺點:加載工具方法不必阻塞文檔,js加載會影響頁面效率,一旦網速很差,那麼整個網站將等待js加載而不進行後續的渲染等工做。

有些工具方法須要按需加載,用到再加載,不用不加載

異步加載的三種方案:

一、defer異步加載,可是要等到dom文檔所有解析完纔會被執行,只有ie能用,也能夠將代碼寫到內部

`script type="text/javascript" src="tools.js" defer="defer"></script>`

二、async w3c標準,異步加載,加載完就行,async只能加載外部腳本,不能把js寫在script標籤裏。

`script type="text/javascript" src="tools.js" aysnc="aysnc"></script>`

三、執行時也不阻塞頁面。

四、建立script,插入到dom中,加載完畢後callBack。

```javascript
demo.js
function test(){
  console.log(a)
}

<script type="text/javascript">
  var script = document.createElement('script');
	script.type = "text/javascript";
	script.src = "demo.js";
	// 因爲ie沒有onload事件,可是是他有一個狀態碼的觸發事件
script.onreadystatechange = function (){
  if (script.readState == "complete" || script.readState == "loaded") {
    test();
  }
} else {
  // safari chrome firefox opera
  script.onload = function () {
    test();
  }
}

document.head.appendchild(script);

=========== 封裝成函數============
function loadScript(url, callback){
  var script = document.createElement('script');
	script.type = "text/javascript";
  if(script.readyState){
     script.onreadystatechange = function (){
  if (script.readState == "complete" || script.readState == "loaded") {
    callback();
  }
 }
  }else {
    script.onload = function () {
    callback();
  }
  }
  script.src = url;
  document.head.appendchild(script);
}
loadScript('demo.js', function (){
  test();
})
```

JavaScript之js加載時間

在js加載開始的時候,瀏覽器會記錄js執行的這段過程。

    1.建立Document對象,開始解析web頁面,解析HTML元素和他們的文本內容後添加Element對象和Text節點到文檔中。這個階段Document。readyState = "loading"。
    
    2.遇到link外部css,建立線程加載,並繼續解析文檔。
    
    3.遇到script外部js,而且沒有設置async , defer ,瀏覽器加載,並阻塞,等待js加載完成並執行該腳本,而後繼續解析文檔
    
    4.遇到script外部js,而且設置有async,defer 瀏覽器建立線程加載,並繼續解析文檔,對於async屬性的腳本,腳本加載完成後當即執行(異步禁止使用docuemnt.write())。
    
    5.遇到img標籤等,先正常解析dom結構,而後瀏覽器異步加載src,並繼續解析文檔
    
    6.當文檔解析完成,document.readyState = "interactive";
    
    7.文檔解析完成後,全部設置有defer的腳本會按照順序執行。
    
    8..當文檔解析完成以後,document對象觸發DOMContentLoaded事件,這也標誌着程序執行從同步腳本執行階段,轉化爲事件驅動階段
    
    9.當全部saync的腳本加載完成並執行後,img等加載完成後,document.readyState = "complete" window對象觸發load事件
    
    10.今後,頁面以異步響應方式處理用戶輸入,網絡事件等。


```javascript

console.log(document.readyState);
document.onreadystatechange = function(){
console.log(document.readyState);
}
```

在這裏咱們說一下兩個事件的區別:DOMContentLoaded和load

    load事件咱們知道,在window上有這個事件window.onload  這個事件是在dom文檔徹底渲染完畢以後纔會觸發,那麼若是網速很差的時候,有那麼一丁點的數據沒有加載完成,這個事件就不會執行,這是一個很是脫瀏覽器後腿的事件。
    
    而DOMContentLoaded則不一樣了,這個事件表示的是當Dom解析完畢以後執行,沒有浪費瀏覽器運行效率,可是這個事件只能用addEventListener綁定。但這也不是個問題,因此,當咱們在head標籤裏面寫Javascript語句的時候用這個事件,千萬不要用load了。














相關文章
相關標籤/搜索