JavaScript筆記

JavaScript

1.基本認識

1.1 能夠直接在標籤中添加事件

<div id="wrap" onclick="alert(123);">123</div>

<a href="javascript:void(0);">gogogogogo</a>

<a href="javascript:alert('a標籤被點擊了!');">233333</a>

1.2 script標籤只能放在head或者body裏面

  • 一個html中能夠放無數個script標籤
  • script標籤載入有前後順序
  • 若是一個script標籤已經用來引入外部的js文件了,那麼在標籤內寫代碼無用
<script type="text/javascript" language="JavaScript">  //type和language是聲明語言格式,推薦不寫
     alert('潭州教育!轉義字符\\')
</script>

1.3 系統彈窗 confirm prompt

let a = confirm('確認不要媳婦啦?');
console.log(a);  //得到用戶選擇的結果,  "boolean"

let b = prompt('請輸入你媳婦的名字:');
console.log(b);  //用戶輸入的結果,     取消-> null -> "object"      肯定 -> string

2.數據類型

2.1 ES五、ES6定義變量的區別

ES6 定義變量,4種方式
- let      
- const    常量,不可更改,初始必須賦值
- function
- class

ES5 定義變量,2種方式
- var
- function

變量命名規則:javascript

  1. 嚴格區分大小寫;
  2. 只能包含 字母 數字 _ $ 四大類,且不能以數字開頭;
  3. 不能使用 關鍵詞/保留詞/已有的API;
  4. 見名知意。
  5. 函數聲明時會覆蓋掉同名變量

2.2 ES6的七大數據類型

  • number 數字
  • string 字符串
  • boolean 布爾值
  • undefined 未定義
  • null 空 可是在瀏覽器上 typeof null = "object"
  • symbol ES6新增的一種數據類型
  • object 對象
// number 
let x = 10;

// string 
let x = "10";
let x = '10';
let x = `456`;   //模板字符串  ES6中新的字符串定義方式
let x = "true";

// boolean 
let x = true;
let x = false; //布爾值有兩種,true 和 false

// undefined
let x;
let x = undefined;
const x = undefined;  //const不容許初始不賦值

// symbol  
let x = Symbol(123);
let y = Symbol(123);      // x和y都是獨一無二的   Symbol(變量)

// object  
let x = [10,true,10];  //數組是對象的一種
function 和 class 定義的變量 typeof 顯示"function", 其本質是object

2.3 typeof

let a = typeof NaN;       //number
let b = typeof a;         //b是string類型
let c;                    //undefined
let d = null;             //typeof在檢測null類型時返回object類型,其本質是null類型
let e = Symbol(123);      //symbol
let f = document;         //object
let g = function(){       //typeof在檢測function數據會返回"function",其本質是object
};

console.log(typeof(b));
console.log(typeof c);
console.log(typeof d);
console.log(typeof e);
console.log(typeof f);
console.log(typeof g);

3. js獲取dom元素節點

let a = document.getElementById("wrap");   //a就是節點對象
console.log(a);  //  <div id="wrap"></div>

//ClassName不惟一,因此Elements有s
let b = document.getElementsByClassName("box");  
console.log(b);  //類(似)數組  HTMLCollection(3) [div.box, div.box, div.box]
console.log(b.length);     // 3
console.log(b[0]);       // <div class="box">1</div>
b[1].innerHTML = '阿飛';

let d = document.getElementsByName('name');  //應用在input標籤
console.log(d);  // NodeList [input]

3.1 html惟一標籤獲取

注意:打印的是標籤,不是類數組節點php

console.log(document.body);       // body標籤及其子標籤
console.log(document.head);       // head標籤及內容
console.dir(document.title);    //標題

//獲取HTML,此處是引用,儘管在後面改變,但引用也會跟上
console.log(document.documentElement);   //打印的是整個html頁面

document.title = "阿飛";
document.documentElement.id = '狗蛋';

3.2 querySelector

let aaP = document.getElementById("wrap")
			.getElementsByTagName("div")[0]
			.getElementsByTagName("p");  //一層層查找,但性能仍然較querySelector好
console.log(aaP);  // HTMLCollection(3) [p, p, p]

let aP = document.querySelectorAll("#wrap div p"); //All多個,參數相似css選擇器
console.log(aP);  // NodeList(3) [p, p, p]

/*最低支持IE8*/
let sP = document.querySelector("#wrap div p");  //只能選到第一個       打印出的就是標籤

3.3 操做元素屬性

w3c容許的標籤屬性,既是合法 合法的標籤屬性,直接 . 操做css

- `class`比較特殊,須要使用`className`代替操做
 - `style` 這個屬性很是特殊,是個對象
let oDiv = document.getElementById("wrap");

//oDiv.title = '狗蛋';     直接寫
oDiv.className = 'wrap';  //屬性class是保留詞,這裏用className

oDiv.id = 'goudan';
oDiv.innerHTML = '<p>666</p>'; //雖然改了id,但oDIV仍指向這個節點對象總體,id只是其中一個屬性,不能影響總體
 //oDiv.innerHTML += '456';   能夠直接+=

let oGouDan = document.getElementById("goudan");
console.log(oDiv === oGouDan);    //徹底相等
/*
css樣式
  js中css屬性名用駝峯法:
        操做複合樣式的時候,去掉 - 號,後面的第一個字母大寫
*/
let oWrap = document.getElementById("wrap");
console.log(oWrap.style);

oWrap.style.height = "100px";
oWrap.style.backgroundColor = "pink";    //將background-color改成駝峯命名法,backgroundColor

oWrap.style.cssText +="width:100px;height:100px;background-color:pink"; // 也能夠這樣寫

/ oWrap.className += " box";     /   /* 操做className代替複雜的css樣式設置  */

3.4 自定義標籤屬性

  • getAttribute()
  • setAttribute()
  • removeAttribute() 移除屬性
let oWrap = document.getElementById("wrap");

//獲取自定義標籤屬性
console.log(oWrap.getAttribute("afei"));

//設置自定義標籤屬性
oWrap.setAttribute("afei","456");
oWrap.setAttribute("zhuque","123");

//移除自定義屬性
oWrap.removeAttribute("afei");

//能夠操做合法屬性,但通常不用,沒有直接.操做方便
console.log(oWrap.getAttribute("id"));

3.5 標籤數據 innerHTML、innerText(火狐低版本,textContent)、value

<div id="wrap"><i>阿飛飛</i> 小浪浪 海文文 銀時時 朱雀雀</div>

<input id="inp" type="text">
<button id="btn">按鈕</button>
<script>
/*
.innerHTML
.innerText    火狐低版本    .textContent
.value
*/
// let oWrap = document.getElementById("wrap");
//
// console.log(oWrap.innerHTML);  //獲取HTML
// console.log(oWrap.innerText);  //只獲取文本
//
// oWrap.innerHTML = "<b>朱雀雀真...</b>";
//oWrap.innerText = "<b>豬八戒...</b>";
document.getElementById("btn").onclick = function(){
alert(document.getElementById("inp").value);
}
</script>

3.6 css超級選擇器

<head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            div#wrap.on.goudan[title]{
                width:150px;
                height:150px;
                background-color:pink;
                border:5px solid #999;
            }
        </style>
    </head>
    <body>
        <div id="wrap" class="on goudan" title=""></div>
    </body>

4. 算術運算

4.1 隱式類型轉換

  • "+" 兩邊任意一邊有字符串,那麼都會進行隱式字符串轉換,再進行拼接
  • 布爾值和數字運算,會轉換成 1 0
  • 除開number string boolean以外,好比去討論一個對象和另外一個對象的加法等是沒有實際意義的
let a = 10;
let b = "20";
//alert(a + b);                 //  彈出  "1020",結果是字符串
//alert("123" + {});            //  123[object Object]
//alert("123" + document);      //  123[object HTMLDocument]
//alert("123" + undefined);     //  123undefined
console.log(true + 8);          //  返回9

//沒意義
// console.log({}+{});             //[object Object][object Object]
// console.log([]+{});             //[object Object]
// console.log([]+[]);             //

//同級運算從左到右
alert(1 + 2 + "3");             //  返回 "33"
alert("8" + 1 + 2);             //  返回 "812"

// 將字符串轉成數字, 前面帶一個 +
console.log(+"86867");
// 數組和任何東西相加,都會轉換成字符串
[1,2,3]+3        	// "1,2,33"
[1,2,3]+true     	// "1,2,3true"
[1,2,3]+null     	// "1,2,3null"
[1,2,3]+undefined 	// "1,2,3undefined"
[1,2,3]+''		    // "1,2,3"
[1,2,3]+NaN			// "1,2,3NaN"
undefined+[]	    //  "undefined"
{}+[]		        // "[object Object]"
- * / %都會變成數字再進行運算

出現非法運算(字符串非數字字符串進行計算)時,會出現NaN(not a number)
    
let a = '50p';  //非數字
let b = "40";

console.log(a - b);      // NaN
console.log(a * b);		// NaN
console.log(a / 20);	// NaN
console.log(a % 20);	// NaN

console.log(typeof(NaN));    //NaN是number類型,但不是一個數字

console.log(NaN + 10);   // 返回NaN

4.2 自增和自減

let a = 10;
console.log(a++);        //返回10

// let a = 10;
// let b = 5;
// console.log(a++ + b);     //返回15

let a = "5";
a ++;  // ++ 或 -- 會強行變數字進行計算,最終a的值也是數字
console.log(a);  // 6

4.3 模板字符串

/*
      單引號 或者 雙引號 描述的字符串,內部不能換行
      ` ` 模板字符串能夠
*/

let oWrap = document.getElementById("wrap");

let x = "阿飛老師有點皮"

// oWrap.innerHTML = "<ul>"+
//         "<li>"+
//             "<p>"+
//                 "<a href=''>"+x+"</a>"+
//             "</p>"+
//         "</li>" +
//     "</ul>";


/* ${}能夠直接引用變量,{}內是JS代碼 */
oWrap.innerHTML = `<ul>
	<li>
		<p>
			<i>${x}</i>
			<b>\$\{\}</b>
		</p>
		<p>\`\`是ES6的特色</p>
	</li>
</ul>`;

5. 運算符

5.1 賦值運算 a+=1

let a = 15;

a -= 1;     //a = a - 1
a *= 2;     //a = a * 2
a /= 3;     //a = a / 3
a %= 4;     //a = a % 4

alert(a);

5.2 比較=運算

/*
                   ==   只比較值相等與否,不關心數據類型
                   ===  值與數據類型都要相等

                   !=   不等
                   !==  不全等
*/
let a = 10;
let b = "10";

console.log(a == b);    //true
console.log(a === b);   //false

console.log(a !== b);   //true
console.log(a != b);    //false

5.3 對象引用類型比較地址

/*
基礎數據類型  (棧內存)   只比較值與類型
number string boolean undefined null symbol

引用數據類型  (堆內存)   比較地址
object
*/

/* a 和 b 是不一樣的對象,有本身的地址  */
let a = [10];
let b = [10];

console.log(a == b);       //false
console.log(a === b);      //false

console.log(a[0] === b[0]);  //true

//console.log(false == [0]);   //這樣不科學的,建議 ===

5.4 字符串比較

/*
            > < >=  <=
*/

//字符串比較,從首位的ASCII碼開始比較
let a = '3';
let b = '20';

console.log(a > b);  // '3' > '2' 的ACSII碼,因此返回 true

5.5 邏輯運算&& || !

/*
                &&  與      //只考慮布爾值時:真真爲真,其餘都是假
                            真正的做用:遇到假就停,而後取假值,不然取後面的值
                ||  或      //只考慮布爾值時:假假爲假,其餘都是真
                            真正的做用:遇到真就停,而後取真值,不然取後面的值
                !  非      //只考慮布爾值時:取反
                            真正的做用:取數據對應布爾值的非

                那些數據在被轉成布爾值的時候是 false:
                    0  undefined  null  false  ''  ""  NaN
*/

// let a = true && false;
// console.log(!a);

let a = 5 && 0;
console.log(a);  //取假值,返回 number 0

let b = 8 && 9;
console.log(b);  // 返回 9

console.log(NaN || 7 || 0);    //返回7

console.log(!1);        //返回 false
console.log(!0);        //返回 true
//取一個數據對應的布爾值
console.log(!! NaN);    //NaN的布爾值是false

5.6 逗號運算

/*
        逗號運算符,從左到右 從上到下 運算
*/

let a = (4,5,6);    //算到6後中止
console.log(a);     //返回 6

5.7 運算優先級

/*
     	運算符優先級
            . [] ()
            ++ -- - ~ ! delete new typeof void
            * / %
            + -
            < <= > >=
            == != === !==
            &&
            ||
            三目
            =
            ,
*/

// let a = 8 || 9 && 0;
// console.log(a);       //返回8

let a = 10;
let b = 5;

//瀏覽器會惰性運算,||的左邊已經肯定,右邊不會計算
// a = 8 || 5 && (b=6);
//console.log(a);         //8
//console.log(b);         //5  ,b的賦值沒有計算
a = 0 || 5 && (b=6);         //返回 a = 6, b = 6


console.log( 6 || (b=6) && 10  || 11);  //返回6
console.log(b);              //b仍未賦值

5.8 位運算(先取整再算)

/*
                二進制
                位運算時會將數值轉換爲32位整型來進行運算,
                因此位運算遇到小數時,直接處理掉小數部分當成整數來運算。
*/

let a = 15;
// 00000000 00000000 00000000 00001111

// -15的二進制
// 11111111 11111111 11111111 11110000   取反碼
// 11111111 11111111 11111111 11110001   反碼+1


/**
* 位運算操做符:按位非`~` 、按位與`&`、按位或`|`、按位異或`^`
*左移`<<`、 無符號右移`>>>`、 有符號右移`>>`
*/

//按位取反,  知足條件 a + ~a=-1
let a = 7;           // 0111
console.log(~a);     // -8 ( 1..1000 結果 取反 +1 )   (0...0111 -> 0...1000)

//按位與
console.log(10 & 8); // 1010 & 1000 = 1000 => 8

//按位或

//左移
a << 2;    //a * 2^2;

6. 判斷和循環

6.1 三目運算

/*
 哪些數據是假:
     六大假  0 undefined null false "" NaN
     
 當條件、真語句、假語句都是一條語句時,咱們可使用三目來改寫if    
 條件 ? 真語句 :假語句
*/
4<5 ? alert('真') : alert('假');



let val = true;
//三目運算符的 優先級 低於 +
let name = "val is" + val ?"狗蛋":"大錘";
//"val is true" ? "狗蛋" : "大錘"
console.log(name);

// 多級三目,從左到右
function f(n) {
    let a = n>100 ? n-100 :    n>99 ? n-99 : n;
    console.log(a);
}

6.2 switch

let a = '海文';

// if (a === "阿飛") {
//     alert(a + "老師通常帥!");
// }else if (a === "小浪") {
//     alert(a + "老師??");
// }else if (a === "海文") {
//     alert(a + "斯文");
// }else if (a === "朱雀") {
//     alert(a + "可愛");
// }else{
//     alert(a + "喵喵喵");
// }

//switch 是全等判斷
switch (a) {
    case "阿飛":
        alert(a + "帥!");
        break;
    case "小浪":
        alert(a + "也帥!");
        break;
    case "海文":
        alert(a + "斯文");
        break;
    case "朱雀":
        alert(a + "可愛");
        break;
    default:
        alert("喵喵喵?");
        break;
}

6.3 邏輯運算符代替判斷

let a = true;

function b() {
    console.log(123);
}

// if (a) {
//     b();
// }
a && b();         //遇到假中止,b()會運行


//先與再或,勉強能夠代替三目運算
let x = 5;
let y = 6;
//console.log(x<y ? 2 : 3);
console.log(x<y && 2 || 3);

6.4 for循環

// 2+2^2+2^3+2^4+...+2^10
let a = 1;
let sum = 0;
for(let i = 1; i <= 10; i++){
    console.log("i=" + i);
    a *= 2;         //a = a*2
    sum += a;
    console.log("sum=" + sum);
}

6.5 綜合案例,生成尖括號

/*
                 5   3
                 6  3
                 7   4
                 8  4
                 9   5
                 10 5
*/

let oWrap = document.getElementById("wrap");
let HTML = '';

let num = 11;
let mid = 0;

//計算oWrap的寬高
if(num & 1){          //奇數判斷
    mid = (num+1)/2;
}else{
    mid = num/2;
}
oWrap.style.width = num*50 + 'px';
oWrap.style.height = mid*50 + 'px';

for(let i = 0; i < num; i++){
    let x = i>(mid-1) ? num-i-1 : i;   //箭頭朝下
    let y = i>(mid-1) ? i+1-mid : mid-1-i;  //箭頭朝上
    HTML += `<div style="margin-top:${y*50}px;">${i+1}</div>`;
}
oWrap.innerHTML = HTML;

7. 循環

7.1 break vs continue

/*
    break:
    	switch裏面的break只對switch有用,不會影響到外面的for
    	if裏面的 break ,結束上級 for 循環 
    continue:  該次循環結束,進入下一個循環  
 */
for(let i=0;i<10;i++){
    switch (i) {
        case 5:
            break;   //做用不到for
    }
    console.log(i);
}


for(let i=0;i<9;i++){
    if(i===5){
        //continue;            //執行到continue,即刻中止,進入下一個循環
        break;         //結束 for 循環
    }
    console.log(i);
}

//break只能跳出一個for,要想跳出第二層,定義一個僞變量表示for循環,break aaa;
aaa:for(let i=0;i<5;i++){
    for(let j=0;j<4;j++){
        if(i*j ===6){
            break aaa;
        }
        console.log(`i===${i},j===${j}`);
    }
}

7.2 while

//let在for循環內定義時,是局部變量
for(let i = 0;;)
//var在for循環內定義時,至關於所有變量
for(var i = 0;;)


let i = 0;
for(;i<4;i++){

}
console.log(i);       //返回4



//全局變量下的for循環能夠用while代替
var i =0;
for(;i<5;){
    console.log(i);
    i++;
}

var j=0;
while(j<5){
    console.log(j);
    j++;
}

// do while
let x = 5;
do{
    console.log(x);
    x++;
}while(x<5);

8. 函數

8.1 定義函數方式

/*
                let a = function () {
                    alert(1);
                }
                a();         //函數加括號,自執行
*/


/*
                a(); //能夠放在function以前,let、var函數表達式定義的函數,不容許提早調用
                function a () {
                    alert(1);
                }
*/


/*  let、var定義的函數,不容許提早調用

                a();
                var a = function () {
                    alert(1);
                }
*/

let a = function b() {
    alert(2);
    console.log(b);      //在函數裏面能夠獲取b,此時b === a
    console.log(b === a);
}
a();
//b();  //顯示b()未定義,函數外面不能使用b

8.2 函數表達式

/*   使用fuction直接定義的函數不能直接加括號執行,只能經過名字再加括號執行
            function a() {
                alert(3);
            }
            a();
*/

//let定義的函數表達式,能夠直接在後面加括號執行
let b=function () {
    console.log(4);
}();
console.log(b);    //undefined,此時b不能表明函數,b成爲了函數的返回值

//匿名函數只能傳參或賦值,不容許直接出現
//[function () {}]   //容許

// function{}   //不容許

//匿名函數加括號變成函數表達式,括號可內可外
(function () {
    console.log(5);
})();

(function () {
    console.log(6);
}());

//改變函數的返回值,也是函數表達式
+function(){          //一元運算符 + - 能夠變爲函數表達式
    console.log(7);
}();

~function () {        //位運算非
    console.log(8);
}();

!function () {          //邏輯運算非
    console.log(9);
}();

8.3 參數

/*
                參數
                    形參
                    實參
                    不定參
*/
//定義函數的時候()裏面是容許寫變量名字的,這些變量名字就是形參,形參只針對函數內容起做用
function a(x,y=200){
    alert(x+y);
}
//函數調用的時候,()裏面寫的就是實參
a(7);


function f(a,b,c) {
    console.log(a);
    console.log(b);
    console.log(c);
}
f(1,8);       //從左到右進入形參,沒有傳入實參的,顯示undefined
f(1,5,3,4);   //實參多了,多的那個無效


function sum(a,b) {
    console.log(a+b);
}
sum(7,8);
sum(45,1);


//求 n 個數的和,每次不必定是相同的個數,實參傳入幾個數,就求幾個數的和
function sum(a,b,c,d) {
    //不定參    它是一個類數組,存儲着 全部實參
    //  console.log(arguments);
    let s = 0;
    for(let i=0,len=arguments.length;i<len;i++){
        s+=arguments[i];
    }
    console.log(s);
}
sum(4,5,6);
sum(1,2,3,4);
sum(8,6);

8.4 上下文this

console.log(this);     //打印Window  是頂層屬性

//  window.alert(4);
//  alert(a);       //未定義  報錯
//  alert(requestAnimationFrame);

//不存在即報錯
if(window.requestAnimationFrame){      //直接判斷時,若是不支持,直接報錯,不能進行判斷,此時最好用類屬性判斷
    console.log(requestAnimationFrame);
}


/*  函數聲明,默認位於window對象內
    函數(聲明式or表達式同樣)自執行,this指向window
*/
function a() {
    console.log(this === window);
}
console.log(a === window.a);          //  相等
a();


 //let定義的函數不掛載window內,var定義的函數在window內
let b = function () {
    console.log(this);        //this都是指向window
}
console.log(b === window.b);      
b();


/*
     對象內的this,找 爸爸 所在的對象
*/
let afei = {
    name:'阿飛',
    x : function () {
        console.log(this);
    }
}
afei.x(); //對象方法自執行。this指向對象

let zhuque = {
    xx:{
        name:"朱雀的xx",
        a:function () {
            console.log(this === zhuque.xx);
        }
    }
}
zhuque.xx.a();      // 打印 父級的對象

8.5 每一個函數都有返回值,默認 return undefined

//函數運行到return即中止,return後面的不執行
function a() {
    alert(1);

    return 2;

    alert(3);
}

console.log(a());

8.6 ES6

let關鍵詞定義的變量,起做用的範圍就是包含這個變量最近的html

var關鍵詞,只有在function內定義的變量,纔是局部變量,while、if、for內定義的都是全局變量前端

同名函數會被覆蓋java

function a() {
alert(2);
}

function a(x,y) {      //覆蓋上一個定義
alert(x+y);
}
a();

8.7 獲取元素的動態方法

動態有三個,意思是存儲節點的變量會隨着頁面的改變實時改變,少了或者多了node

  • getElementsByClassName()
  • getElementsByTagName()
  • getElementsByName()

靜態有如下,獲取後,選擇器被改也指向原對象es6

  • querySelectorAll
  • getElementById
<div id="wrap">
    <p class="goudan"></p>
    <p class="goudan"></p>
    <p class="goudan"></p>
</div>

<script>
    //getElementsByClassName是個動態的
    let aP = document.getElementsByClassName("goudan");    // 有三個

    let oP = aP[0];      // 這種就是靜態的,不存在因修改而改變

    oP.className = 'dachui';  //改變了 aP,只剩兩個 「goudan」
    oP.title = 'ppp';

    aP[0].className = "a2121";        //aP是動態數組,
    aP[0].innerHTML = "112121212";    //由於aP[0]的類名被改變了,動態獲取的內容更新了,如今又少了一個
</script>

9.做用域與解析順序

9.1 var、function在全局做用域定義的變量默認是window對象的屬性

//script標籤是最大的做用域,也是全局做用域
//若是var、function在全局做用域裏面定義變量。至關於給window添加了屬性
var b = 10;
console.log(window.b,this);   //window的屬性


//ES5定義變量的關鍵詞 var   funtion
//做用域是往上離變量最近的函數

function a() {
var g = 10;      // var在function內定義的纔是局部做用域
console.log(g,this.b,this);           //函數自執行this指向window
}
a();

//任意做用域裏面,若是不加var直接產生了沒有定義過的變量,那麼這個變量至關於window的屬性
//可是實際開發不容許這樣寫
function aa() {
bb = "bb";      // 賦值產生變量才行,若是直接使用則會報錯
}
aa();
console.log(bb);

//面試題
function f() {
var x=y=5;
console.log(x);  //x是局部的5
}
f();
console.log(y);  //y未聲明,所以算是window的屬性,y=5
//console.log(x);  //由於x是局部變量,外部訪問不到,故報錯

9.2 做用域鏈

//做用域鏈,操做變量時,一層層的做用域查找變量聲明的地方,
//若是沒有找到,調用變量會報錯
//若是是賦值,在非嚴格模式下,變量成爲windows的屬性

var x=10;
function a() {
x=15;       //本做用域找不到,去父級做用域找,找到後並賦值
var y=5;    //局部做用域
return x+y;
}

console.log(a());
console.log(x);     //全局變量被修改了,所以是15

9.3 es5解析順序

var、function解析順序

第一步:定義
    找出當前做用域裏面全部的var和function定義的變量名,不賦值,賦值是執行
    此時function定義的函數,是個完整的函數,因此函數定義能夠在函數執行的先後任意位置

第二步:執行
    從上到下執行
alert(x);     // 返回不是報錯,是undefined,變量已有,但未賦值
var x=10;
//let x=10;    // 報錯
/*
                1.定義
                    var x;
                2.執行
                    alert(x);   //undefined
                    x=10;
*/


alert(b);
function b() {

}
/*
                1.定義
                    function b(){}
                2.執行
                    alert(b);
*/

9.4 變量重名與覆蓋

/*
    定義過程當中,多個var聲明同一個變量,咱們只須要留一個
               多個函數聲明重名,只留最後一個函數
               var和function重名,不管前後,只留function
 */
function v() {
    alert(5);
}
function v() {       //  被打印 
    alert(10);
}

var v;
console.log(v);

9.5 閉包

函數執行每次都會產生一個新的做用域 (父級也是新的) ,彼此不相干web

/*
JS自帶變量回收機制,只有全局變量不會被回收,除非網頁關閉;
        閉包:一個使用了外部函數的參數或者變量的函數(做用域嵌套做用域,ES5只有函數能產生做用域)
 */
function a() {
    var x=10;
    function b() {
        x++;
        console.log(x,this);
    }
    return b;
}
//函數執行每次都會產生新的做用域,
var c=a(); //c指向函數體內的函數b,局部變量x只在a()時產生了一次,因此不會回收
//alert(c);  c是函數
//c()每次執行使用的都是同一個父級做用域下的變量x
c();  //11
c();  //12
c();  //13
c();  //14

//a()每次執行後返回的都是新的做用域,使用的變量x是新的,
a()();  //11
a()();  //11
a()();  //11

閉包的做用之一,閉包避免局部變量被回收面試

<div id="wrap">
    <p>aaaaaaaaaaa</p>
    <p>bbbbbbbbbbb</p>
    <p>cccccccccc</p>
    <p>dddddddddd</p>
    <p>eeeeeeeeee</p>
</div>

<script>

    //閉包的做用之一,閉包避免局部變量被回收,onclick不知道何時觸發,因此num不會被回收
    (function () {
        var num=10;
        document.onclick = function () {
            num++;
            alert(num);
        }
    })();


    let oP = document.getElementsByTagName("p");

    //ES6只要是{}就是做用域,{}內的onclick使用了父級的i,因此i沒有回收,子做用域能夠調用
    //產生了5次閉包,存了5個i,子做用域之間的i不相干
    //5個閉包是5個單獨的做用域,let i是5個父級做用域
    for(let i=0;i<5;i++){
        oP[i].onclick = function () {
            alert(++i);
        }
    }


    //var不能產生做用域,不是閉包,函數做用域用的是同一個變量i,(擴號內執行的結果是5)
    //i最後是5,因此每次點擊都是同一個i
    for(var i=0;i<5;i++){
        oP[i].onclick = function () {
            alert(i);
        }
    };

    //強行給var加閉包,創造一個父級做用域,使得點擊事件用上父級做用域的變量,產生5個閉包,存下5個變量
    for(var i=0;i<5;i++){
        function a(x){
            oP[x].onclick = function() {
                alert(x);
            };
        }
        a(i);  //a(i)執行了5次,產生了5次閉包
    }
    
    //等於自執行
    for(var i=0;i<5;i++){
        (function a(x){
            oP[x].onclick = function() {
                alert(x);
            };
        })(i);//a(i)執行了5次,產生了5次閉包
    }
    
    //能夠簡寫自執行
    for(var i=0;i<5;i++){
        !function a(x){
            oP[x].onclick = function() {
                alert(x);
            };
        }(i);//a(i)執行了5次,產生了5次閉包
    }
</script>

練習

fn()();
var a = 0;
function fn(){
    alert(a);
    var a = 3;
    function c(){
        alert(a)
    }
    return c;
}

/*
        1.定義
            var a;
            function fn(){}
        2.執行
            fn()  ===>    新做用域
                            1.定義
                                var a;
                                function c(){}
                            2.執行
                                alert(a)   undefined
                                a=3
                                return c;
            fn()()   ===>新做用域
                        alert(a),a從父級找,彈出3
 */
var a = 5;
function fn(){
    var a = 10;
    alert(a);
    function b(){
        a ++;
        alert(a);
    }
    return b;
}
var c = fn();
c();
fn()();
c();

/*
    10
    11
    10
        11
    12
 */

9.6 function屬於對象類型,相等判斷時是比較地址

console.log(5 === 5);

console.log([] === []);   //引用,須要比地址,false

var h = function () {};
var l = function () {};
console.log(h === l);     //false

function a() {
    return function () {};
}
var b = a();
var c = a();
console.log(b ===c);  //false

9.7 ES6的做用域

只要是在做用域裏面let過的變量,那就不容許提早使用

/*
       ES6定義變量
            let const function class

                 let 和 const沒有預解析,不一樣於var
                 先對定義function,進行解析
 */
alert(a);   //報錯
let a = 10;


let a = 20;
function b() {
    //從上到下讀
    //暫時性死區,只要是在做用域裏面let過的變量,那就不容許提早使用
    alert(a);
    let a = 30;  //死區了,報錯
}
b();


//var的做用域只認函數
if(false){
    var a=10;
}
console.log(a);  //undefined


//let的做用域是大括號
if(true){
    let a=1;
}
console.log(a);  //沒法訪問局部做用域
//for的小括號()是{}的父級做用域,但var不認這是做用域


const g = 10;  //不容許從新賦值的常量
const a = [];  //對象不能被從新賦值
a[0] = 10;         //但容許改變其內容
console.log(a);

10. call apply bind

10.1 函數內的this

function a() {
    console.log(this);
}

a();
/*
    普通模式下, 自執行this指向window,
    嚴格模式下, this指向undefined
    被動模式下,this指向觸發事件的對象
 */
document.onclick = a;

10.2 call apply

/*  call()內第一個參數是函數內this的指向,後面跟的是實參,調用後會執行  */
function a(x,y) {
    console.log(x);
    console.log(y);
    console.log(this);
}
a(8,9);        //自執行
//a.call();   //call()不加參數與自執行a()效果同樣
a.call(document,8,9);  //this指向document


/*  apply(),與call()相似,可是隻有兩個參數,第二個是傳參的數組  */
a.apply(document,[8,9]);  //this指向document
//多個參數要用數組的形式傳入

10.3 bind

bind以後至關於生成一個新的函數,還未執行

/*  bind不能執行  */
function a(x,y) {
    console.log(x);
    console.log(y);
    console.log(this);
}

//a.bind(document);  這樣直接寫是沒有效果的,只是至關於生成了一個新的函數,將this綁定給document

function b(x) {
    x();
}
b( a.bind(document) );  //bind後生成了有this新指向的函數,bind是定義函數,不能直接執行,須要手動執行

a.bind(document)(10,20);  //新的函數內的this指向 document

a.bind(10)(0,1);  //新的函數內this指向number  10
//bind定義this指向

document.onclick = function (x,y) {
    console.log(x);
    console.log(y);
    console.log(this);
}.bind({name:'阿飛'},200,250);        //這裏相似於call傳參,bind產生新函數

10.4 H5新API classList

oWrap.classList.[attr] attr = add、remove、toggle

let aDiv = document.querySelectorAll("#wrap .title"),
    aList = document.querySelectorAll("#wrap .friend .list"),
    len=aDiv.length;


for(let i=0;i<len;i++){
    aDiv[i].onclick = function () {
        //toggle,若是有就刪除,沒有就添加
        aList[i].classList.toggle("show");
    }
}

//classList 方法還有  add   remove
oWrap.classList.add("afei");   //直接添加類名

11. ES6的解構賦值

// ES6 定義變量的解構賦值
let a = 10,
    b = 20,
    c = 30;
//結構模式對應,賦值效果同上
let [a,b,c] = [10,20,30];

//多了   顯示  undefined
let [a,b,c,d] = [20,30,41];       //  d = undefined

//不用let的變量賦值語句,變量默認是window的屬性
[a,b] = [20,30,41];

//變種寫法
function fn() {
    let x=[];
    for(let i =0;i<5;i++){
        x[i]=i*i;
    }
    return x;
}
let [a,b,c,d,e] = fn();


//對象的解構賦值,屬性是用來對應的,只有變量定義了
let {a:x,b:y} = {a:10,b:20};
console.log(x);
console.log(a);  // 報錯,屬性不是定義的


let {x:x,y:y} = {a:10,b:20,y:30};
console.log(x);      //找不到右邊對象的x屬性,因此變量x顯示未定義
console.log(y);      //屬性對應才能賦值 y=30


//注,屬性和變量相同時,能夠只寫一個
let {x,y} = {x:10,y:30};
console.log(x,y);

//ES6新增簡寫規則
let a = 10,
    b = 20,
    c = {
        a,
        b
    };
/*屬性名和變量名相同,能夠簡寫,對象c的定義同下
    c = {
        a:a,
        b:b
    }
*/
console.log(c);

11.1 深層解構賦值

let [a,[b,c],d] = [1,[2,3],4];
console.log(a,b,c,d);


let [a,b,{x,y}] = [1,2,{x:10,y:20}];
console.log(a,b,x,y);

11.2 解構賦值時默認值寫法

只有右邊**嚴格等於undefined**時取默認值

不容許前面的默認值用後面的變量值
/*使用解構賦值,取默認值的方法*/
function fn(data) {
    let a = data.a;
    let b = data.b;
    let c = data.c || 100;  // 要確保傳入的值不是假,不然走默認值,這種不嚴格

    // 必須嚴格的走 全等undefined,再添加默認值
    if(c === undefined){
        c = 100;
    }
}
fn({a:10,b:20});


//ES6的默認值寫法,左邊寫一個等於,只有右邊嚴格等於undefined時取默認值
function fn(data) {
    let {a:a=1,b:b=2,c:c=100} = data;  //左邊嚴格上說不能認爲是對象,只有右邊是對象
    console.log(a,b,c);    // c = null
}
fn({a:10,b:20,c:null});   // 這裏 null===undefined 不成立,


//數組默認值寫法
let [d,e,f=90] = [7,8];
console.log(d,e,f);

//默認值是表達式時,若是不須要默認值,則默認值沒法執行
function f1() {
    console.log("12");
}
let [x = f1()] = [1];     //  x=1,  f1未執行
let [y = f1()] = [undefined];  //  y=undefined,  是f1執行後的返回值

//不容許前面的默認值用後面的變量值
let [m=n,n]=[undefined,1];
console.log(m,n);  //報錯

12. 字符串方法

12.1 基本數據類型包裝對象無心義

undefined null 等不能進行點操做,會報錯的

//基礎數據類型雖然能夠點操做,但沒有意義,拿不到包裝對象;
//點操做本質上是針對數據的包裝對象進行操做,每一次的包裝對象都是新產生的對象,不能肯定
//undefined null 等不能進行點操做,會報錯的
let a='阿飛';
a.index = 20;    //不能給字符串添加自定義屬性,不會報錯,顯示undefined,這是操做的a的包裝對象,用了即消失,存不下來
console.log(a,a.index);   //第二次的點操做是操做的全新的包裝對象,用後即消失


/*
let b={};
b.index = 20;      //對象能夠添加自定義屬性
console.log(b);
*/


let a = new String("阿飛");       //這裏的a是字符串對象
a.index = 20;                    //a的包裝對象是 new String(),能夠添加自定義屬性
console.log(a+"朱雀",a.index);

12.2 str.charAt() 取出字符串中的第幾位字符,不能賦值

let a = '阿飛';
//console.log(new String(a));   //能夠打印包裝對象屬性爲String的對象

//針對a的包裝對象的charAt
console.log(a.charAt(1));   //取出字符串中的第幾位字符
console.log(a[0]);  // a的包裝對象有a的內容,對象訪問時能夠的,可是IE6,7不支持,最好用charAt

//包裝對象不能賦值,沒有意義;使用即消失,存不了
a[0]="5";

console.log(a[0]);

12.3 str.charCodeAt() 獲取ASCII編碼

/*
    charCodeAt()
    調用第幾個字符的編碼,

    String.fromCharCode()
    與之相反,從ASCII碼到字符
 */

let a = "阿A飛";
let b = `阿
飛`;

console.log(a.charCodeAt(1));   //  65

console.log(b.charCodeAt(1));  //換行碼是 10

console.log(String.fromCharCode(39134));  // 飛


//加密,利用ASCII碼
let c = "小卑鄙我愛你";
let d = "";

for(let i=0,len=c.length;i<len;i++){
    let code = c.charCodeAt(i)+520;
    console.log(code);
    d += String.fromCharCode(code);
}
console.log(d);

12.4 str.substring(x,y) 字符串截取一段[x,y),xy大小無所謂,y默認爲len

/*substring(x,y)  從第x位到第y位截取,x要,y不要*/
// slice能夠倒着截取
let a="abc阿飛789456";

let b = a.substring(3,5);  //包含3,不包含5
console.log(b);  //阿飛

let bb=a.substring(5,3);   //沒有先後要求,會自動調整
console.log(bb); //阿飛

let c = a.substring(3);    //從3到結尾
console.log(c);  //阿飛789456

let d = a.substring(-2,3);   //沒有負值,會認爲0
console.log(d);  // abc

let e = a.slice(-5,-2);      //負值表示從後開始數,倒着數,要知足前後順序
console.log(e);  // 894

12.5 大小寫轉換toLocaleUpperCase

//主要針對英文字母大小寫
/*
        toLocaleUpperCase()
 */
let a = "abc";

let b = a.toLocaleUpperCase();
console.log(b);

console.log(b.toLocaleLowerCase());

12.6 indexof()返回座標,默認-1

/*
        找位置,返回num
 */

let a = "我以爲阿飛老師是最皮的";

console.log(a.indexOf("阿飛"));

//指定位置開始找,後面加一個參數
console.log(a.indexOf("老師",3));

//找不到返回 -1

12.7 split(",")切割返回數組,join(",")拼接成字符串

// 使用split()進行切割,返回一個包含分開特定字符先後元素的數組
let a = "阿飛,朱雀,心艾,嵐嵐,丫丫,艾米";

let b = a.split(",");
console.log(b);

console.log(b.join("php"))
// let c = a.split("");
// console.log(c);

12.8 ES字符串擴展

function fn(a,b) {
    console.log(arguments);  // [ 0:["1,2", "阿飛", ""], 1:5 , 2:6 ]
    console.log(a+b);  // 1,2,阿飛,5
}
//fn(1,2);
let b=5;
let a = 6;
fn`1,2${b}阿飛${a}`;

13. 數組方法

13.1 push pop shift unshift

增長,返回數組長度,刪除,返回被刪的內容

/*
    push
        參數:任意數據
        功能:直接改變原數組
        返回值:返回改變後數組的長度
    pop
        參數:null
        功能:改變原數組,刪除最後一位
        返回值:刪除的元素
    shift
        功能:改變原數組,刪除第一位
        返回值:刪除的元素
    unshift
        功能:改變原數組,從第一位添加
        返回值:數組長度
        
 */

let a = ["阿飛","無慮"];

console.log(a.push("小浪","海文"));
console.log(a);
console.log(a.pop());
console.log(a);
console.log(a.shift());
console.log(a);
console.log(a.unshift("first"));
console.log(a);


//騷操做,
// pop()返回的是刪除的最後一個函數,後面跟參數執行
let x = [5,function(x){alert(x)}];
x.pop()(x[0]);

13.2 a.indexOf() a.slice()

//類數組除了.length,不能執行其餘api

let a = ["阿飛","無慮","朱雀"];

console.log(a.indexOf("朱雀"));       //2

//數組截取
let b = a.slice(1); 
console.log(b);    //  ["無慮", "朱雀"]

13.3 數組切割splice()

返回被切割的部分

//數組切割,單個參數時,包含前面而不含後面的
let a = ['阿飛','無慮','小浪'];

console.log(a.splice(1));  //從第1個切,切到最後       ["無慮", "小浪"]
console.log(a);            // ["阿飛"]


//第二個參數表示切除幾個
console.log(a.splice(1,1));  //從第1個開始切除1個   ["無慮"]
console.log(a);		// ["阿飛", "小浪"]


//添加與替換
a.splice(1,1,'朱雀','心艾');  //切除一個,替換了2個    ["無慮"]
console.log(a);     // ["阿飛", "朱雀", "心艾", "小浪"]

13.4 數組排序a.sort() a.reverse()

二分法排序

不加參數,默認升序數組被改變了,但引用地址沒變,仍相等

//通常只是針對num類型數組排序,其餘類型沒有意義
// sort()從小到大排序,升序
// reverse()  反序,元素從後往前排,能夠先升序再反序實現降序排列
// 返回值是排列完成以後的數組,
let a=[12,78,50,20,32,40,90];

a.sort();
console.log(a);
a.reverse();
console.log(a);

console.log(a.sort() === a);  //改變以後仍是a自己,相等

//降序
console.log(a.sort().reverse());


//JS二分法排序   a-b: 爲升序          b-a: 爲降序
a.sort(function (a,b) {
    return a-b;           
})
console.log(a);
let a = [
    {name:'阿飛',age:20},
    {name:'朱雀',age:30},
    {name:'丫丫',age:18},
    {name:'心艾',age:80},
    {name:'嵐嵐',age:22},
    {name:'發發',age:22},
    {name:'艾米',age:28}
];

//a.sort();  沒法直接對對象排序

a.sort(function (a,b) {
    return b.age-a.age;   //後者減前者,降序
})

console.log(a);

13.5 數組拼接數組 a.concat(b)

//  concat   拼接數組

let a = [1,2,3];
let b = [4,5,6];

let c = a.concat(b);   //將b拼接到a的後面

console.log(a,b);  //不改變原數組
console.log(c);

13.6 數組方法 Array.isArray(a)

//  只有 Array 可使用 isArray()方法

let a = [1];
let b = document.querySelectorAll("div");

console.log(Array.isArray(a));
console.log(Array.isArray(b));    //經常使用於判斷類數組,其沒有數組經常使用的方法

13.7 數組拼接字符串 a.join(",")

let a = ["阿飛",'心艾','朱雀'];

let b = a.join("<==>");    //一般將字符串數組元素拼接成一個新的長的字符串

console.log(a);  //不改變原數組
console.log(b);  //b是返回的長字符串   阿飛<==>心艾<==>朱雀

13.8 數組遍歷 a.forEach(v,i)

//forEach  遍歷數組,必需要有函數做爲參數,自動執行length次,不支持函數return
/*
    接收函數,該函數第一個形參表明每一位的數據,
                 第二個形參表明每一位的序號,
                 第三個形參表明原數組
 */

let a = [4,5,6,7,8,9];
let b=a.forEach(function (x,y,z) {
    console.log(x,y,z);
});
console.log(b);  //undefined

//與forEach效果同樣
for(let i=0;i<a.length;i++){
    (function (x,y,z) {
        console.log(x,y,z);
    })(a[i],i,a);
}

13.9 數組遍歷 a.map(cb(val,i))

//map是有返回值的數組遍歷,返回一個基於原數組結構的數組
let a = [1,2,4,5];

let b = a.map(function (x,y,z) {
    console.log(x,y,z);
    return x*x;
});

console.log(a);  //map不改變a
console.log(b);  //b是基於a結構的新生數組   [1, 4, 16, 25]
**ES6 的Map對象,可用於記數**
let a = [1,2,4,5];
let c = new Map()
a.map(function (val,index) {
    c.set(index,value)     // 實例方法,設置 map數據
})
console.log(c);       // Map對象實例  Map(4) {0 => 1, 1 => 2, 2 => 4, 3 => 5}

c.get(3);    // 5      按set時的index查找   
c.has(0);    // true   index
c.keys();    //  MapIterator {0, 1, 2, 3}
c.values();  //  MapIterator {1, 2, 4, 5}
[...c];      //  [[0,1], [1,2], [2,4], [3,5]]

13.10 過濾 a.filter(cb(val,i))

/* 遍歷
    func:過濾
        生成一個過濾後的數組,return true 留下,false 過濾掉

 */

let a=[10,20,5,7,89,41];
let b=a.filter(function (x,y,z) {
    console.log(x,y,z);
    return x>10;   //將x>10的留下,新生一個數組
});

console.log(a);  //不改變原數組
console.log(b);  //b是過濾後的數組

13.11 ES6 ...擴展

let a = [1,2,3];
console.log(...a);  //去除數組括號,拆解成單個,ES6兼容,babel可轉
console.log(1,2,3); //與上等價


//param形參
function f(param) {
    console.log(param);    // 只有一個形參  1
}
//f(1,2,3);
f(...a);

/*
let c = (...a);   //這樣作是不容許的
console.log(c);
*/

...數組拼接

// ...數組拼接

    let a = [1,2,4];
    let b = [5,6,7];

    //let c = a.concat(b);
    let c = [...a,...b];

    console.log(c);

...解構賦值

//b是數組,拆開後賦值,  ...b只能放在後面,表示接受所有
let [a,...b]=[1,2,3,4];

console.log(a);  // 1
console.log(b);  // [2, 3, 4]

...與iterator接口

//常見的Iterator遍歷器接口
/     Array String nodelist arguments     /

// Nodelist是節點對象集合

function fn(a,b,c) {
    console.log(a,b,c);
}

fn("753");    	 //   753 undefined undefined
fn(..."753");    //   7 5 3

...與NodeList

let aP = document.getElementsByTagName("p");
// 類數組不能用數組的遍歷
// aP.forEach(function (val,index) {
// });

//ES5就有辦法將 aP 先搞成數組,以後再使用forEach
//slice不傳參數就不切割,數組切割,方法slice使用call改變切割對象執行,返回一個真數組
let x = [].slice.call(aP);    //生成一個新數組
console.log(x);
x.forEach(function (node,index) {
    node.onclick = function () {
        alert(index);
    }
})

//ES5   類數組=>真數組遍歷遍歷
[].slice.call(aP).forEach(function (node,index) {
    node.onclick = function () {
        alert(index);
    }
});


//ES6 ,  ...將Nodelist拆了,加上[]成爲真數組
console.log([...aP]);
[...aP].forEach(function (n,i) {
    n.onclick = function () {
        alert(i);
    }
});

...與function

//任何拆解都要放在最後面
function fn(a,...b) {
    console.log(a);
    console.log(b);
}
fn(4,5,6);


function fn(...argu) {
    console.log(argu);     //ES6的...能夠直接代替arguments
}
fn(7,8,9);

14. 數學對象

14.1 Math

  • Math.pow(x,y)表示x的y次方
  • Math.trunc(-5.999991) 去小數點取整 -5
/*
    Math 對象
        屬性:
        方法:
 */

//小數表示方式: 0表示正負   10表示小數點的位置爲2  10.1010的整數部分爲2,小數部分是1010/2^4,    10/16
//var a = 0 10 10.1010;    //表示 2.625

/*
    Math.abs()
        1.傳入的值是正確的,返回一個新的絕對值結果,字面量賦值
        2.傳入的值是數字字符串,會取value值取絕對值
        3.單個數字元素的數組也會取值,多個數字元素也是NaN
        4.傳入的值其餘類型,返回NaN,表示not a number
 */
console.log(Math.abs(["-888"]));      //  888

//Math.pow(x,y)表示x的y次方
console.log(Math.pow(2,10));       // 1024
//開方,y小於1
console.log(Math.pow(256,1/2));    // 16
//過氣的開二次方
console.log(Math.sqrt(256));       // 16

//取整,floor接地氣,往小了取整,正負同樣
console.log(Math.floor(2.5),Math.floor(-2.01));      //2    -3
//向上取整
console.log(Math.ceil(2.5),Math.ceil(-2.9));         //3    -2
//四捨五入取整
console.log(Math.round(4.49),Math.round(-4.6));      //4 -5
//去小數點取整
console.log(Math.trunc(-5.999991));     // -5

14.2 三角函數

/*
    圓周  2PI    360deg
          PI/6   30deg
          PI/3   60deg

          sin  正弦   對/斜
          cos  餘弦   鄰/斜
          tan  正切   對/鄰

          反三角
          arcsin
 */

console.log(Math.sin(Math.PI/6),Math.cos(Math.PI/3),Math.tan(Math.PI/4));  //結果有小數,不精確

console.log(Math.asin(0.5),Math.PI/6);

14.3 隨機數 Math.random()

/*
        Math.random()     返回一個[0,1)的數
 */

//console.log(Math.random(),Math.round(Math.random()*10));

//  生成一個n到m的隨機數,m取不到
const rdm = function(n=0,m=n+1){
    return Math.floor((m-n)*Math.random()+n);
}
console.log(rdm(1,7));

14.4 parseInt() parseFloat()

/*
    非數學對象
         parseInt(a,b)
            a   須要轉換的數值,隱式轉換成字符串
            b   進制(2,36)  10+26
 */

console.log(parseInt("123abc"));   //返回字符串中的整數部分,遇到NaN中止 返回123

//第二個可選參數是進制
console.log(parseInt("ff",16));    //按16進制解析,結果是10進制255
console.log(parseInt("0xa"));     // 10

/*
        parseFloat()返回帶小數點的
            在底層parseFloat會先判斷傳入的參數類型,轉換成字符串;
            若是傳入對象,會默認調用對象的toString()方法
 */
console.log(parseFloat("12.3254a"));

console.log({}.toString());   //  打印 "[object Object]"


//ES6次方簡寫
console.log(3**2);  //表示3的平方

14.5 立方根cbrt,e的冪exp, 單精度浮點 fround

//   cbrt是取立方根結果,相似  Math.pow(27,1/3)
console.log(Math.cbrt(27),Math.pow(27,1/3));          //3 3

//   exp是天然對數e的冪函數,e^ln2 = 2;
console.log(Math.exp(Math.LN2),Math.exp(Math.LN10));  //2 10

//  轉成最近的單精度浮點數的數字
console.log(Math.fround(100.1));

15. 對象方法

15.1 對象遍歷 for in

let a={
    name:'阿飛',
    'age':18,
    marry:true,
    handsome:true
}

//for in循環,遍歷對象,也能夠是數組
for(let key in a){
    console.log(key,":",a[key]);
}

15.2 對象的增刪改查

//對象的屬性是無序的,通常按照字母前後順序展現
let a={
    name:'阿飛',
    age:18,
    marry:true
}

console.log(a);  //這裏a是引用,後面改了,這邊也能相應

//增
a.GF = ['朱雀','丫丫','嵐嵐','茜茜'];

//改
a.age = 21;

//刪除
delete a.marry;

//查找,是否存在
console.log('age' in a);

15.3 json JSON.stringify() JSON.parse()

//json  是一個格式很是標準長得像對象的字符串
//通用字符串,基本上全部語言都能識別的字符串格式

//let a = '{"name":"阿飛","age":18,"marry":true}';

let a={
    'name':'阿飛',
    age:18,
    marry:true
};

//將一個對象轉爲JSON格式  JSON.stringify() 反序列化
let b=JSON.stringify(a)
console.log(b);

//將JSON序列化,  JSON.parse()   解析成對象
let c = '{"a":10,"b":"狗蛋","c":true}';
//必須是標準嚴格的JSON格式才能解析,裏面必須用雙引號包起來""
console.log(JSON.parse(c));

15.4 es6的默認值

let [a,b=10]=[5];                  // a=5  b=10
let {x:hh,y:tt=20} = {x:11}; 	   // hh=11  tt=20
 
// function fn([a,b]) {
//     console.log(a,b,arguments);
// }
// fn([5]);

function fn({a=10,b=100}) {
    console.log(a,b,arguments);
};
//fn({a:5});
//fn({a,b});
fn({});  // 10 100

//無實參取形參的默認值{x,y},有實參對應實參的默認值{x:10,y:30}
function ffn({x,y} = {x:10,y:30}) {
    console.log(x,y);
}
ffn();     //10  30
ffn({});   //un un

15.5 箭頭函數

/*
    ES6     箭頭函數
        () =>
 */
/*      形參  返回值 */
let fn = v => v;
//ES5寫法以下
var fn = function (v) {
    return v;
}


/* 加法寫法 */
var fn = function (a,b) {
    return a+b;
}
let fn = (a,b) => {a+b};


/*  函數內容較多   */ 
var fn=function (a,b) {
    let c = a+2;
    let d = b-3;
    return(c+d);
}
let fn = (a,b)=>{
    let c = a+2;
    let d = b-3;
    return(c+d);
}


/*  若是返回對象時,須要再加上()  */
var fn = function () {
    return {a:10,b:20};
}
let fn = () => ({a:10,b:20})


/*
document.onclick = function () {
    console.log(this);
}
*/

//一般用在回調函數內,方便使用
let arr=[1,2,3];
arr.forEach((value,key)=>{
    console.log(value);
});
let b = arr.map(v=>v*v);  //結果平方返回
console.log(b);

16.定時器

16.1 setTimeout(cb,T)

/*
    setTimeout  一次執行定時器
        param1:回調函數,或者是字符串包裹的js腳本,或者是引號包裹的全局做用域內的函數自執行
        param2:數字(毫秒單位)
 */

setTimeout(function () {
    alert("timeout!");
},1000);



let fn = function () {
    alert(1);
    return function () {
        alert(3);
    }
};
setTimeout(fn(),1000);    //不能是返回值,第一個參數是函數



let str = "let a=10;alert(a);";    //能夠接收字符串參數,當成JS代碼來讀
setTimeout(str,2000);


let fn = function () {          // 若是fn不在全局做用域內,則 "fn()"找不到將報錯
    alert(4);
};
setTimeout("fn()",1500);         //默認在全局中執行引號的內容,做用域在全局

16.2 setInterval(cb,T)

/*
    setInterval   循環定時
 */

let num=0;
let fn = function () {
    console.log(++num);
}
setInterval(fn,1000/60);       //最小時間間隔最可能是60次每秒,

16.3 定時器隊列

主程序執行完以後才執行定時器隊列

//讀到setTimeout時將定時器放入隊列中,主程序執行完以後才執行隊列
//因此先彈出3,後彈出4

setTimeout(function () {   //進入隊列後執行
    alert(4);
},0);

!function fn() {        //先執行
    alert(3);
}();

16.4 參數

回調函數帶參時,放在定時器第二個參數以後

//定時器的函數有參數時,直接放在第二個參數以後

(function () {
    function fn(a,b) {
        console.log(a+b);
    }

    //setInterval(fn(2,7),1000);   //這樣會直接執行
    
    /*
    setInterval('fn(2,7)',1000);        //雙引號內的內容默認丟在全局中執行,全局中找不到fn,報錯
    window.fn = fn;  //將局部fn賦值到window
    */
    
    setInterval(fn,1000,25,14);      //參數接着放
})();

16.5 返回值

/*
       返回值是按定時器出現順序從1號開始的編號,做用是用來清除定時器的
       編號不區分做用域
 */
let x = setTimeout(function(){alert(3);},50000);
let y = setTimeout(function(){alert(4);},60000);
let z = setTimeout(function(){alert(5);},70000);
let w = setInterval(function(){alert(6);},80000);
let v = setInterval(function(){alert(7);},90000);
console.log(x,y,z,w,v);       // 1 2 3 4 5

16.6 清除定時器

  • clearInterval(t)
  • clearTimeout(t)
let x = setTimeout(function(){console.log("a")},2000);         // 1

let y = setTimeout(function(){console.log("b")},2000);         // 2

console.log(x,y);

clearTimeout(y);      //清除編號爲2的定時器

// 定時器的隊列編號跟做用域不要緊,按出現順序編號
(function () {
    let x = setTimeout(function(){console.log("a")},2000);     // 3

    let y = setTimeout(function(){console.log("b")},2000);     // 4
    console.log(x,y);
})();

16.7 requestAnimationFrame(cb)

canselAnimationFrame()

/*
    H5出的新的API
    requestAnimationFrame()   不須要第二個參數,間隔是瀏覽器的刷新頻率,單次執行
    主要是讓動畫很流暢,瀏覽器準備好就刷新

    CSS3關於動畫的API底層都是它

    取消
    canselAnimationFrame()
 */

let oW = document.getElementById("wrap");
let start=0;
function m(){
    start += 2;
    oW.style.left = start+'px';
    requestAnimationFrame(m);
}
requestAnimationFrame(m);


// 兼容
window.requestAnimationFrame = window.requestAnimationFrame || function (fn) {
    setTimeout(fn,1000/60);
};
window.cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;

16.8 案例,自動無縫輪播圖

關鍵點: oImg.style.transitionDuration = 0+'s';

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            body{font-family: "Microsoft YaHei",serif;}
            body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
            ol,ul,li{margin:0;padding:0;list-style:none;}
            img{border:none;}

            #wrap{
                overflow: hidden;
                position: relative;
                width:520px;
                height:280px;
                margin:50px auto;
                -webkit-user-select: none;
                -moz-user-select: none;
                -ms-user-select: none;
                user-select: none;
            }
            #wrap .img{
                position: absolute;
                top:0;
                left:0;
                width:1000%;
                height:100%;
                transition-property: left;
            }
            #wrap .img li{
                position: relative;
                float:left;
                width:10%;
                height:100%;
            }
            #wrap .tab{
                position: absolute;
                left:0;
                right:0;
                bottom:15px;
                z-index:5;
                width:80px;
                margin:auto;
                background-color: rgba(255,255,255,.3);
                border-radius: 10px;
                font-size:0;
                text-align:center;
            }
            #wrap .tab li{
                float: left;
                width:10px;
                height:10px;
                margin:3px;
                border-radius: 10px;
                background-color: white;
                cursor:pointer;
            }
            #wrap .tab li.active{
                background-color: #ff5000;
            }
            #wrap>span{
                display: none;
                z-index:5;
                position: absolute;
                top:0;
                bottom: 0;
                width:30px;
                height:30px;
                margin:auto;
                background-color: rgba(0,0,0,.3);
                border-radius: 30px;
                color:#fff;
                font-size:22px;
                line-height:30px;
                cursor: pointer;
            }
            #wrap:hover>span{
                display: block;
            }
            #wrap>span:hover{
                background-color: rgba(0,0,0,.5);
            }
            #wrap .left{
                left:-12px;
                text-indent: .5em;
            }
            #wrap .right{
                right:-12px;
                text-indent: .1em;
            }
        </style>
    </head>
    <body>
        <div id="wrap">
            <ul class="img">
                <li>
                    <img src="img/05.webp">
                </li>
                <li>
                    <img src="img/01.webp">
                </li>
                <li>
                    <img src="img/02.jpg">
                </li>
                <li>
                    <img src="img/03.jpg">
                </li>
                <li>
                    <img src="img/04.png">
                </li>
                <li>
                    <img src="img/05.webp">
                </li>
                <li>
                    <img src="img/01.webp">
                </li>
            </ul>
            <ul class="tab">
                <li class="active"></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
            </ul>
            <span class="left">&lt;</span>
            <span class="right">&gt;</span>
        </div>
        
        <script>
            (function () {
                //定義變量
                let oWrap = document.getElementById("wrap"),
                    aTabLi = document.querySelectorAll("#wrap .tab li"),
                    oImg = document.querySelector("#wrap .img"),
                    aImgLi = document.querySelectorAll("#wrap .img li"),        //作不到無縫
                    oLeft = document.querySelector("#wrap .left"),
                    oRight = document.querySelector("#wrap .right"),
                    len = aImgLi.length-1,
                    lastIndex=1,
                    timer='';

                //作一個定時器動畫
                window.requestAnimationFrame = window.requestAnimationFrame || function (fn){setTimeout(fn,1000/60);};
                window.cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;

                oImg.style.left = '-'+lastIndex*100+'%';    //初始是顯示第一個

                //封裝動做事件
                function move(x) {
                    aTabLi[x].classList.remove("active");
                    oImg.style.transitionDuration = .3+'s';    //動畫時間
                    oImg.style.left = '-'+lastIndex*100+'%';   //動畫步驟
                    if(lastIndex === len){      //到達最後一個了!len = 6
                        requestAnimationFrame(function () {
                            //偷天換日,改到第一個
                            lastIndex=1;
                            aTabLi[0].classList.add("active");
                        });
                        //座標移動該怎麼不被動畫發現呢,延時吧,等於duration 0.3s
                        setTimeout(function () {
                            oImg.style.left = '-'+lastIndex*100+'%';
                            oImg.style.transitionDuration = 0+'s';
                        },300);
                    }else if(lastIndex === 0){  //到達第0個了!len-1 = 5
                        requestAnimationFrame(function () {
                            //偷天換日,改到第一個
                            lastIndex=len-1;
                            aTabLi[4].classList.add("active");
                        });
                        //座標移動該怎麼不被動畫發現呢,延時吧,等於duration 0.3s
                        setTimeout(function () {
                            oImg.style.left = '-'+lastIndex*100+'%';
                            oImg.style.transitionDuration = 0+'s';
                        },300);
                    }else{
                        aTabLi[lastIndex-1].classList.add("active");
                    }
                }

                //tab點擊事件
                [...aTabLi].forEach((oTabLi,index)=>{
                    oTabLi.onclick = function () {
                        if(index === lastIndex-1)return;
                        let x = lastIndex-1;
                        lastIndex = index+1;
                        move(x);
                    }
                });

                //left點擊事件 , lastIndex = 0 1 2 3 4
                oLeft.onclick = function () {
                    let x = lastIndex-1;    // [0,4]
                    lastIndex --;
                    move(x);
                }

                //right點擊事件
                oRight.onclick = function () {
                    let x = lastIndex-1; //x從0開始
                    lastIndex++;
                    move(x);
                }

                //定時器
                timer = setInterval(function () {
                    let x = lastIndex-1; //x從0開始
                    lastIndex++;
                    move(x);
                },3000);

                //中止
                oWrap.onmouseenter=function () {
                    clearInterval(timer);
                }
                //繼續
                oWrap.onmouseleave=function () {
                    timer = setInterval(function () {
                        let x = lastIndex-1; //x從0開始
                        lastIndex++;
                        move(x);
                    },3000);
                }

            })();
        </script>
    </body>
</html>

17. 時間API

17.1 Date類

/*Date類
    new Date()
        本地此時此刻的日期對象/時間戳
 */

let d = new Date();    	 		//獲取的是對象
console.dir(d);

console.log(d.getTime());        // 時間戳
let t = new Date(d.getTime());
console.log(t);

//如下API返回數字   number
console.log(d.getFullYear());         //獲得  年
console.log(d.getMonth()+1);          //獲得  月(從0開始計數,應該+1返回)
console.log(d.getDate());             //日
console.log(d.getHours());            //時
console.log(d.getUTCHours());         //0時區  UTC
console.log(d.getMinutes());          //分
console.log(d.getSeconds());          //秒
console.log(d.getDay());              //星期   星期日是0

console.log("====================");

console.log(d.toUTCString());
let x = new Date();  //日期對象能夠作減法,會自動調用getTime進行相減
//定時器都不是 精準的計時
setInterval(function () {
    let y=new Date();
    console.log(y-x);
    x=y;
},50);      //週期很小,則偏差較大

17.2 設置時間戳

//無參是獲取,有參是設置
let x=new Date(2018,8-1,8,1,1,1);    //月份從0開始的,因此設置8月應輸入7
let x=new Date(2018);    //只有一個參數時,會被認爲是毫秒時間戳,從1970年開始加
let x=new Date(2018,5-1);  //默認1日,0時0分0秒
console.log(x);


let a = new Date().getTime();
console.log(new Date(a-3600000));   //打印一個小時前的時間

17.3 網頁倒計時跳轉

<p>404 頁面未找到~~</p>
<div><span>8</span>秒後,返回 <a href="">主頁</a></div>

<script>

    (function () {
        let oS = document.querySelector("div span");
        let oVal = 8;

        setInterval(function () {
            oS.innerHTML = --oVal;
            if(oVal === 1){
                window.location.href = "http://web.tanzhouedu.com";
            }
        },1000)

    })();

</script>

17.4 新年倒計時

(function () {
    let oW = document.getElementById("wrap");

    let x = new Date(2020,2-1,24);  //過年時間

    function fn(){
        let d = x - new Date();    //差了多少秒

        let DD = Math.floor(d/1000/60/60/24);   //天
        let HH = Math.floor(d/1000/60/60%24);
        let MM = Math.floor(d/1000/60%60);
        let SS = Math.floor(d/1000%60);

        if(DD<10) DD = '0'+DD;
        if(HH<10) HH = '0'+HH;
        if(MM<10) MM = '0'+MM;
        if(SS<10) SS = '0'+SS;

        oW.innerHTML = `距離過年還有 <span>${DD}</span> 天 <span>${HH}</span> 小時 <span>${MM}</span> 分 <span>${SS}</span> 秒;`;
    };
    fn();

    setInterval(fn,1000);
})();

18. 運動框架

18.1 基礎的移動

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            #wrap{
                position: absolute;
                left:0;
                top:0;
                width:100px;
                height:100px;
                background-color: pink;
            }
        </style>
    </head>
    <body>
        <div id="wrap"></div>
        
        <script>
            (function () {
                let oWrap = document.getElementById("wrap");
                let startVal = 0;

                function m() {
                    startVal +=3;
                    oWrap.style.left = startVal + 'px';
                    requestAnimationFrame(m);          //推薦,保證前一個動畫執行完成後,進入下一次動畫
                    //setTimeout(m,1000/60);
                }
                m();

            })();
        </script>
    </body>
</html>

18.2 封裝好的運動框架

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="keywords" content="關鍵詞">
        <meta name="description" content="描述">
        <meta name="author" content="Danew">
        <style>
            body{font-family: "Microsoft YaHei",serif;}
            body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
            ol,ul,li{margin:0;padding:0;list-style:none;}
            img{border:none;}

            #wrap{
                width:50px;
                height:50px;
                margin-left:300px;       /*百分比在IE顯示百分比,要轉成px*/
                background-color: pink;
                opacity: .8;
                filter:alpha(opacity=80);    /*標準IE瀏覽器的兼容,opacity 0-100 */
            }
        </style>
        <script src="move.js"></script>
    </head>
    <body>
        <div id="wrap"></div>
        
        <script src="move.js"></script>
        <script>
            var oW = document.getElementById("wrap");

            Move(oW,"marginLeft",600,3);
            Move(oW,"width",500,3);
            Move(oW,"height",500,3);
            Move(oW,"opacity",0,.01);       //opacity沒有單位
        </script>
    </body>
</html>
'use strict';
/*
 * 運動框架
 * param:
 *      ele     - object 必須 表示要進行運動的節點
 *      attr    - string 必須 表示要改變的css屬性
 *      target  - number 必須 表示屬性的終點值
 *      step    - number 選填 表示運動速度的正值,默認5
 *return:
 *
 */
window.Move = function () {
    //兼容定時器
    window.requestAnimationFrame = window.requestAnimationFrame || function (fn) {
        setTimeout(fn, 1000 / 60);
    };
    window.cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;

    //框架函數
    return function Move(ele, attr, target) {
        var step = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 5;

        //ele.style.marginLeft  只能獲取行內樣式
        //console.log(getComputedStyle(ele));              //原生JS,存儲着節點對象所有的樣式

        //獲取存儲着ele展現樣式的對象
        var cssObj = ele.currentStyle || getComputedStyle(ele); //解決兼容性問題IE8用currentStyle
        //初始的值
        var sVal = parseFloat(cssObj[attr]); //去掉單位,變成數字
        //兼容IE的opacity
        if(attr === "opacity" && isNaN(sVal))sVal=1;

        //考慮初始值與目標值大小的問題
        var bool = sVal>target;
        if(sVal > target){
            step = -Math.abs(step);   //負值
        }else if (sVal < target){
            step = Math.abs(step);    //正值
        }else{
            return;
        }

        function f() {
            sVal += step;         // + -step
            if (bool?sVal<=target:sVal>=target) {
                sVal = target;
            }else {
                requestAnimationFrame(f);
            }
            if(attr === 'opacity'){
                ele.style[attr] = sVal;
                ele.style.filter = "alpha(opacity="+100*sVal+")";      // IE瀏覽器兼容
            }else if(attr === 'zIndex'){
                ele.style[attr] = sVal;         //不加單位
            }else{
                ele.style[attr] = sVal + 'px';   //加單位
            }

        }
        requestAnimationFrame(f);
    };
}();

19. DOM

19.1 節點nodeType nodeName nodeValue

/*
     元素節點的nodeType是   1     nodeName是 大寫的標籤名   nodeValue=null
     元素屬性的nodeType是   2     nodeName是 屬性名        nodeValue=屬性值
     文本節點的nodeType是   3     nodeName是 #Text         nodeValue=文本內容
     註釋節點的nodeType是   8     nodeName是 #comment      nodeValue=註釋內容
  */
 let oW = document.getElementById("wrap"),
 oC = document.getElementsByClassName("content")[0];

 console.dir(oW);
 console.log(oW.nodeType);       //1  元素節點
 console.log(oW.nodeName);       //DIV

 console.log(oW.childNodes);     //子節點,包含全部節點類型

console.log(oW.attributes[2].nodeType);         // 2
// console.log(typeof oC.childNodes[0].nodeValue);

 oW.attributes[2].nodeValue = '朱雀';   //不建議這樣修改,應該座標是不肯定的
 console.log(oW.attributes[2]);        // afei='朱雀'

19.2 子節點 childNodes children

<div id="wrap">
    阿飛飛
    <p>gg</p>
    <p>ss</p>
    <a href="">gg</a>
</div>

<script>

    let oW = document.getElementById("wrap");

    console.log(oW.childNodes);   //IE不兼容,谷歌連換行也能獲取,不實用

    //經常使用   !!!!!!
    console.log(oW.children);    //只獲取子元素節點哦 ,有三個子元素(標籤)

    //innerHTML是刷新整個內容,要求必須刷新後再get元素,這樣很不方便
</script>

19.3 插入節點createElement

  • createElement 建立元素節點
  • createTextNode 建立文本節點
  • appendChild 建立的是子節點
  • insertBefore(A,B) 建立子節點,A元素節點放在B元素節點以前
<div id="wrap">
    阿飛飛
    <p>pp</p>
    <p id="on">gg</p>
    <a href="#">123</a>
</div>

<script>
    let oW = document.getElementById("wrap");
    let oN = document.getElementById("on");
    let oP = document.querySelector("p");

    oP.onclick = function(){    //節點的變化不影響其操做和屬性
        alert(5);
    }

    //建立文本節點對象
    let text = document.createTextNode("朱雀");
    //console.dir(text);

    //建立元素節點對象
    let oDiv = document.createElement("div");

    //從後面添加子節點    appendChild
    oW.appendChild(text);
    //oW.appendChild(oDiv);

    //在某個子元素的前面添加  (a,b)  a是新元素節點
    //oW.insertBefore(oDiv,oP);

    //放在子元素第一位
    oW.insertBefore(oDiv,oW.children[0]);   //oW.childNodes[0] 全部的第一位

</script>

19.4 修改節點位置

<div id="wrap">
    <p>阿飛</p>
    <p>朱雀</p>
</div>
<div id="box"></div>

<script>
    let oBox = document.getElementById("box");
    let aP = document.getElementsByTagName("p");

    //轉移子元素,原來元素的屬性和方法不會改變
    oBox.appendChild(aP[0]);
</script>

19.5 刪除節點 removeChild()

<div id="wrap">
    <p>555</p>
    <p>666</p>
</div>
<div class="box"></div>
<script>
    //只有父級節點才能刪除子節點
    let oW = document.getElementById("wrap");
    let oBox = document.getElementsByClassName("box")[0];
    let oP = document.getElementsByTagName("p")[1];

    //父級刪除了子節點,但變量oP 仍保留了被刪除的節點
    oW.removeChild(oP);

    document.onclick = function () {
        oBox.appendChild(oP);       //oP仍可使用
    }

</script>

19.6 獲取節點

  • firstChild 第一個子節點,通常獲取的都是文本節點 ->換行符
  • firstElementChild 第一個元素子節點
  • nextSibling 下一個兄弟節點
  • nextElementSibling 下一個兄弟元素節點
  • previousElementSibling 上一個兄弟元素節點
<div id="wrap">
    <p>11</p>
    <p>22</p>
    <p>33</p>
</div>

<script>

    let oW = document.getElementById("wrap");
   
    console.log(oW.firstChild);         //第一個子節點,文本節點->換行符
    console.log(oW.firstElementChild);  //第一個元素子節點,  <p>11</p>
    console.log(oW.children[0]);        //第一個元素子節點,  <p>11</p>


    var aChild = oW.children;        //是動態的更新,根據兒子變化而變化,
    var p1 = aChild[0];       //元素節點
    var p2 = aChild[1];
    var p3 = aChild[2];


    console.log(p1.nextSibling);   //下一個兄弟節點(文本換行符)
    //標準瀏覽器
    console.log(p1.nextElementSibling);   //下一個兄弟元素(若是沒有,打印null)
    console.log(p2.nextElementSibling);   //
    console.log(p3.nextElementSibling);   //沒有返回null
    //上一個兄弟節點  previousElementSibling
    console.log(p2.previousElementSibling);


    //IE兼容,只有nextSibing,下一個兄弟元素節點
    function getNextSibing(ele) {
        if(ele.nextElementSibling !== undefined){
            return ele.nextElementSibling;
        }else{
            return ele.nextSibling;        //IE的
        }
    }
    console.log(getNextSibing(p1));
    console.log(getNextSibing(p2));
    console.log(getNextSibing(p3));
</script>
  • parentNode 父親節點
  • offsetParent 定位父級,離得最近的擁有定位的父級,都沒有時就是body
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #wrap{
            position: relative;
        }
    </style>
</head>
<body>
    <div id="wrap">
        <p id="btn">4545454</p>
    </div>

    <script>
        let oBtn = document.getElementById("btn"),
            oW = document.getElementById("wrap");

        console.log(oBtn.parentNode); //  === oW        typeof oW = "object"
        console.log(oW.parentNode);   //  body

        //自刪除
        //oBtn.parentNode.removeChild(oBtn);

        console.log(oBtn.offsetParent);    //定位父級  oW
    </script>
</body>

19.7 克隆節點 oP.cloneNode()

節點的事件不被克隆

  • oP.cloneNode() 默認不復制內容
  • oP.cloneNode(true) 包括內容所有複製,但事件不會複製
<div id="wrap">
    <p class="gg">745545</p>
</div>

<div id="btn">444</div>

<script>
    //節點具備惟一性,只有clone能夠   默認不復制裏面的內容,參數爲true內容也克隆,  事件不能複製
    let oP = document.getElementsByClassName("gg")[0],
    oBtn = document.getElementById("btn");

    oP.onclick =function () {alert(1);};       //事件不能clone

    //oBtn.appendChild(oP);   直接appendChild是移動節點,並未增長
    let clone = oP.cloneNode(true);            //克隆得到一個新的節點對象

    oBtn.appendChild(clone);
</script>

19.8 節點替換 replaceChild(A,B) , A將B替換掉

<div id="wrap">
    123
</div>
<div id="btn">456</div>

<script>
    let oW = document.getElementById("wrap"),
        oB = document.getElementById("btn");

    oW.replaceChild(oB,oW.childNodes[0]);
</script>

19.9 節點片斷 document.createDocumentFragment()

(function () {
    let oW = document.getElementById("wrap");

    //生成10個小球
    (function () {
        //節點片斷,暫時存放節點的對象
        let oF = document.createDocumentFragment();

        //生成十個小球,一次性append進oW內,省的渲染屢次
        for(let i=0;i<10;i++){
            let oP = document.createElement("p");
            oF.appendChild(oP);
        }
        oW.appendChild(oF);
    })();

    //運動
    (function () {
        let aP = [...oW.children];
        let MaxL,MaxT;

        window.onresize = (function r(){
            MaxL = window.innerWidth - 100;
            MaxT = window.innerHeight - 100;
            return r;
        })();

        //隨機初始速度
        let speedArr = [];
        aP.forEach((ele,index)=>{
            speedArr[index] = {
                stepX : Math.floor(Math.random()*12+4),
                stepY : Math.floor(Math.random()*12+4)
            };
        });

        //隨機顏色
        function changeColor(ele) {
            let [r,g,b] = [
                Math.floor(Math.random()*256),
                Math.floor(Math.random()*256),
                Math.floor(Math.random()*256)
            ];
            ele.style.backgroundImage = `radial-gradient(white,rgb(${r},${g},${b}))`;
        }

        //遍歷運動
        !function m(){

            aP.forEach((ele,index)=>{
                let left = ele.offsetLeft + speedArr[index].stepX;
                let top = ele.offsetTop + speedArr[index].stepY;

                if(left >= MaxL){
                    left = MaxL;
                    speedArr[index].stepX = -speedArr[index].stepX;
                    changeColor(ele);
                }
                if(left <=0){
                    left = 0;
                    speedArr[index].stepX = -speedArr[index].stepX;
                    changeColor(ele);
                }
                if(top>=MaxT){
                    top = MaxT;
                    speedArr[index].stepY = - speedArr[index].stepY;
                    changeColor(ele);
                }
                if(top<=0){
                    top = 0;
                    speedArr[index].stepY = - speedArr[index].stepY;
                    changeColor(ele);
                }
                ele.style.left = left+'px';
                ele.style.top = top + 'px';
            });

            requestAnimationFrame(m);
        }();

    })();


})();

20. DOM寬高屬性與事件對象

20.1 視圖頁面寬高,無單位

  • window.innerWidth
  • document.documentElement.clientWidth
<div id="wrap"></div>

<script>

    /*  Window視圖屬性
        獲取頁面顯示區的寬高,IE8及如下不兼容
     */
    console.log(window.innerWidth);
    console.log(window.innerHeight);

    document.body;
    document.head;
    document.title;
    document.documentElement;   //獲取html元素節點
    console.log(document.documentElement === document.querySelector("html"));   // true

    //Document文檔視圖  下面的IE兼容
    console.log(document.documentElement.clientWidth);    //html頁面寬度
    console.log(document.documentElement.clientHeight);   //html頁面高度

</script>

20.2 元素寬高,無單位

  • getComputedStyle(oWrap).width css樣式寬度,有單位
  • oWrap.clientWidth 客戶端寬度 width+padding 無單位
  • oWrap.offsetWidth 客戶端寬度 + border
  • oWrap.scrollWidth 滾動寬度,通常用在出現滾動條, = 客戶端寬度
/*
number類型
    clientHeight/clientWidth        width+padding
    offsetHeight/offsetWidth        width + padding + border
    scrollHeight/scrollWidth        滾動寬度,超出視圖仍顯示正常寬度,無論有沒有超出隱藏
*/

let oWrap = document.getElementById("wrap");

console.log(getComputedStyle(oWrap).width);       //獲取元素css樣式設置的寬度,有單位
console.log(oWrap.clientWidth);   //width + padding
console.log(oWrap.offsetWidth);   //width + padding + border

//scrollWidth  元素佔用的寬度,生成滾動條,內容不超出時數值等於clientWidth
console.log(oWrap.scrollWidth);   //若是有超出部分,正確的反映出超過以後的寬度,無論有沒有加超出隱藏

20.3 定位left值offsetLeft與top值offsetTop

只有距離定位父級的左值和上值 ,沒有右下

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            #wrap{
                /*position: relative;*/
                margin:50px;
            }
            p{
                width:10px;
                height:10px;
                background-color: pink;
            }
        </style>
    </head>
    <body>
        <div id="wrap">
            8888
            <p></p>
        </div>
        
        <script>
            /* 只有距離定位父級的左值和上值  */

            let oP = document.querySelector("#wrap p");

            //wrap沒加position,則定位父級是body
            console.log(oP.offsetLeft);    //到定位父級的距離
            console.log(oP.offsetTop);     //到定位父級的距離

            //獲取元素到文檔body的距離
            function getOffset(ele) {
                let dis = {
                    top:0,left:0
                };
                while(ele !== document.body){
                    dis.top += ele.offsetTop;
                    dis.left += ele.offsetLeft;
                    ele = ele.offsetParent;         //定位父級
                }
                return dis;
            }

            console.log(getOffset(oP));
        </script>
    </body>
</html>

20.4 body的滾動高度,用document.documentElement.scrollTop

<body style="height:2000px;">
    <div id="wrap"></div>
    <script>
        document.onclick = function () {
            //頁面滾動高
            console.log(document.documentElement.scrollTop);
            //document.body.scrollTop  谷歌棄用了,可是手機可能還未改

            //最好這樣寫去獲取頁面的滾動高
            console.log(document.body.scrollTop || document.documentElement.scrollTop);  //保險起見
        }
    </script>
</body>

20.5 元素的滾動高,父級的scrollTop

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            #wrap{
                overflow-y:auto ;     /*y豎直方向有滾動條*/
                width:300px;
                height:500px;
                background-color: pink;
                margin:50px auto;
            }
            #wrap p{
                height:2000px;
            }
        </style>
    </head>
    <body>
        <div id="wrap">
            <p></p>
        </div>
        
        <script>

            let oW = document.getElementById("wrap");

            oW.onclick = function(){
                console.log(oW.scrollTop);   //oW元素豎直方向的滾動高度
            }
        </script>
    </body>
</html>

20.6 scrollTop無單位,能夠賦值

<body style="height: 2000px">
    <div id="wrap"></div>
    
    <script>

        document.onclick = function () {
            document.documentElement.scrollTop = 500;
        }

    </script>
</body>

20.7 getBoundingClientRect()獲取邊界客戶端矩形,對象形式,無單位

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            #wrap{
                /*position: relative;*/
                margin:50px;
            }
            p{
                width:10px;
                height:10px;
                background-color: pink;
            }
        </style>
    </head>
    <body>
        <div id="wrap">
            8888
            <p></p>
        </div>
        
        <script>

            let oP = document.querySelector("#wrap p");

            console.log(oP.getBoundingClientRect());  
//  DOMRect {x: 50, y: 71, width: 10, height: 10, top: 71, bottom:81, left:50, right:60}
            
            //top  bottom left right   對應 邊 到 body的距離
            // x y是座標

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

20.8 oW.scrollIntoView(true) 滾動到可視區

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            #wrap{
                position: absolute;
                top:1500px;
                width:100px;
                height:100px;
                background-color: pink;
            }
        </style>
    </head>
    <body style="height: 3000px;">
        <div id="wrap"></div>
        <script>
            let oW = document.getElementById("wrap");
            document.onclick = function () {
                //oW.scrollIntoView(false);    //true是跳轉到視圖頂部,false跳轉到視野底部
                oW.scrollIntoView(true);
            }
        </script>
    </body>
</html>

20.9 event事件對象

/*
    event事件對象
        事件函數執行時,第一個形參就是事件對象:存儲着和該次事件相關的一些信息
        IE8及如下瀏覽器,使用event全局變量來表示事件對象

    該對象裏面比較重要的一些屬性
        clientX/clientY  事件觸發時,鼠標距離可視區的距離
        pageX/pageY      鼠標距離文檔的位置(IE8 不兼容)
 */

//IE的事件函數沒有形參
//兼容
document.onclick = function (ev) {
    ev = ev || window.event;  // IE的Event是全局變量
    console.log(ev);         
}

20.10 鼠標事件 onmousedown onmousemove onmouseup

document.onmousedown = function () {
    console.log("down");
    document.onmousemove = function () {
        console.log("move");
    }
}

document.onmouseup = function () {
    console.log("up");
    document.onmousemove = null;         //默認屬性是null
}

20.11 案例:可拖拽的盒子

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            #wrap{
                position: absolute;
                left: 0;
                top:0;
                width:100px;
                height:100px;
                background-color: pink;
            }
        </style>
    </head>
    <body>
        <div id="wrap"></div>
        
        <script>

            let oW = document.getElementById("wrap");

            oW.onmousedown = function (ev) {
                //獲取鼠標初始的位置
                let sX = ev.clientX;
                let sY = ev.clientY;
                //獲取按下時,盒子的位置
                let sLeft = oW.offsetLeft;
                let sTop = oW.offsetTop;
                document.onmousemove = function (eve) {
                    //獲取鼠標當前的位置
                    let mX = eve.clientX;
                    let mY = eve.clientY;

                    //計算鼠標位置的變化量
                    let x = mX - sX;
                    let y = mY - sY;

                    //盒子當前的位置 = 盒子按下的位置 + 變化量
                    oW.style.left = sLeft + x + 'px';
                    oW.style.top = sTop + y + 'px';
                };
            };

            document.onmouseup = function () {
                console.log("up");
                this.onmousemove = null;
            }
        </script>
    </body>
</html>

20.12 案例:十球發射

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="keywords" content="關鍵詞">
        <meta name="description" content="描述">
        <meta name="author" content="Danew">
        <style>
            body{font-family: "Microsoft YaHei",serif;}
            body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
            ol,ul,li{margin:0;padding:0;list-style:none;}
            img{border:none;}

            div.box{
                position: absolute;
                left:0;
                top:0;
                width:100px;
                height:100px;
                background-color: #db3a45;
                border-radius: 50%;
            }
        </style>
    </head>
    <body>
        <div id="wrap">
            <div class="box"></div>
            <div class="box"></div>
            <div class="box"></div>
            <div class="box"></div>
            <div class="box"></div>
            <div class="box"></div>
            <div class="box"></div>
            <div class="box"></div>
            <div class="box"></div>
            <div class="box"></div>
        </div>

        
        <script>
            (function () {
                let aBox = [...document.getElementsByClassName("box")];

                //最大邊距
                let MaxLeft,MaxTop ;
                window.onresize = (function s() {
                    MaxLeft = window.innerWidth-100;
                    MaxTop = window.innerHeight-100;
                    return s;
                })();

                //步長
                let step = [
                    {
                        stepX:3,
                        stepY:4,
                    },
                    {
                        stepX:5,
                        stepY:6,
                    },
                    {
                        stepX:6,
                        stepY:7,
                    },
                    {
                        stepX:7,
                        stepY:8,
                    },
                    {
                        stepX:8,
                        stepY:9,
                    },
                    {
                        stepX:9,
                        stepY:10,
                    },
                    {
                        stepX:10,
                        stepY:11,
                    },
                    {
                        stepX:11,
                        stepY:12,
                    },
                    {
                        stepX:12,
                        stepY:13,
                    },
                    {
                        stepX:13,
                        stepY:14,
                    },
                ];

                aBox.forEach((ele,index)=>{
                    ball(ele,index);
                });

                //rgb函數
                function color() {
                    let r = Math.floor(Math.random()*256),
                        g = Math.floor(Math.random()*256),
                        b = Math.floor(Math.random()*256);
                    return `rgb(${r},${g},${b})`;
                }

                //小球運動函數
                function ball(ele,index) {
                    //初始位置
                    let left = ele.offsetLeft,
                        top = ele.offsetTop;

                    !function m() {
                        //步長
                        left += step[index].stepX;
                        top += step[index].stepY;
                        //left
                        if(left>=MaxLeft){
                            left=MaxLeft;
                            ele.style.backgroundColor = color();
                            step[index].stepX = -step[index].stepX;
                        }
                        if(left<=0){
                            left=0;
                            ele.style.backgroundColor = color();
                            step[index].stepX = -step[index].stepX;
                        }
                        //top
                        if(top>=MaxTop){
                            top = MaxTop;
                            ele.style.backgroundColor = color();
                            step[index].stepY = -step[index].stepY;
                        }
                        if(top<0){
                            top = 0;
                            ele.style.backgroundColor = color();
                            step[index].stepY = -step[index].stepY;
                        }
                        ele.style.left = left+'px';
                        ele.style.top = top+'px';
                        requestAnimationFrame(m);
                    }();
                }
            })();
        </script>
    </body>
</html>

21. DOM事件

21.1 事件冒泡

冒泡觸發順序:從子元素開始到窗口

  • event.stopPropagation() 主流瀏覽器阻止冒泡:
  • event.cancelBubble = true; IE阻止冒泡
<div id="box">
    box1
    <div id="box1">
        box2
    </div>
</div>

<script>
    /*
        事件的冒泡
            子元素觸發了事件  若是父元素也有同類型的事件的話,父元素也會觸發
            觸發的順序是從子級開始,向父級方向

            冒泡的觸發順序
            box2 -> box1 -> body -> html

            冒泡觸發順序
                從子元素開始到窗口,(從兒子到爸爸)window

            阻止冒泡   event.stopPropagation()  阻止傳播   IE不兼容
            box2  box1
     */
    var box = document.getElementById("box"),
        box1 = document.getElementById("box1");

    document.onclick = function(){
        console.log("我也觸發了事件");
    }

    box.onclick = function () {
        console.log(1);
    }
    box1.onclick = function (event) {

        event = event ||window.event;

        //event.stopPropagation();       //冒泡中止(主流瀏覽器)

        console.log(2);

        //ie阻止冒泡的   屬性
        //event.cancelBubble = true;

        //兼容性寫法
        event.stopPropagation ? event.stopPropagation():event.cancelBubble=true;
    }
</script>

21.2 事件監聽

  • attachEvent("onclick",cb) IE8
  • detachEvent(事件類型,回調方法);
  • addEventListener(事件類型,回調方法,捕獲|冒泡) 主流瀏覽器
  • removeEventListener(事件類型,回調方法,捕獲|冒泡);

捕獲與冒泡順序相反

var oW = document.getElementById("wrap");

//DOM 0級事件,   相同名字的事件被覆蓋,只能監聽一個事件
oW.onclick = function () {
    console.log(1);           //被覆蓋
};
oW.onclick = function () {
    console.log(2);
};



/*
     事件監聽(默認事件冒泡)
        用到事件的地方最好就是使用 DOM2級來監聽

     監聽事件
        主流瀏覽器         事件類型  "click"
            ele.addEventListener(事件類型,回調方法,捕獲|冒泡)
            1.this指向節點自己
            2.捕獲與冒泡
                默認是false  冒泡事件
                true爲捕獲,與冒泡的順序相反,從最大父級到子級開始(也能使用阻止冒泡的方式)

        ie瀏覽  ie8       事件類型  "onclick"
            oW.attachEvent(事件類型,回調方法)
            1.this再也不指向節點自己,指向window
            ie8沒有事件捕獲,默認是冒泡事件

     移除事件
        主流瀏覽器
            ele.removeEventListener(事件類型,回調方法,捕獲|冒泡);

        IE8
            ele.detachEvent(事件類型,回調方法);

 */
//事件監聽DOM   2級事件
//IE8
oW.attachEvent("onclick",function (e) {
    e = e||window.event;
    console.log(this);      //this 再也不指向監聽事件的節點自己
    console.log(e);
});

/* 主流瀏覽器  */
oW.addEventListener("click",function () {
    console.log("我又監聽了一次點擊事件,理解一下DOM 2級事件");
})


var callback = function () {
    console.log(1);
};
oW.addEventListener("click",callback);

//文檔雙擊,註銷事件
//該事件必須事先用變量保存,removeEventListener的參數必須與添加事件監聽的參數同樣,才能移除
document.ondblclick = function () {
    oW.removeEventListener('click',callback);
}

21.3 事件默認行爲

  • oncontextmenu 默認行爲指右鍵可選事件
  • return false; dom0級阻止默認行爲
  • event.preventDefault(); 阻止默認行爲
  • event.returnValue = false; IE8阻止默認行爲
<div id="wrap">
    <p>默認行爲</p>
    <p>默認行爲</p>
    <p>默認行爲</p>
    <p>默認行爲</p>
    <p>默認行爲</p>
    <p>默認行爲</p>
    <p>默認行爲</p>
    <p>默認行爲</p>
    <p>默認行爲</p>
    <p>默認行爲</p>
    <p>默認行爲</p>
    <p>默認行爲</p>
</div>

<script>
    //事件的默認行爲是右邊鼠標顯示的可選事件  oncontextmenu

    /*
        阻止默認行爲
            DOM 0級在事件裏面直接  return false,
            DOM 2級
                主流瀏覽器
                    event.preventDefault();
                ie
                    event.returnValue = false;

    */


    //DOM 0級在事件裏面直接  return false,
    document.oncontextmenu = function () {
        return false;
    }


    //DOM 2級   preventDefault
    document.addEventListener('contextmenu',function (e) {
        e.preventDefault();
    })


    //IE8
    document.attachEvent('oncontextmenu',function (e) {
        e = e||window.event;
        e.returnValue = false;
    })


    //阻止默認的滾輪事件
    wrap.addEventListener('mousewheel',function (e) {
        e.preventDefault();
    })

</script>

21.4 滾輪事件

  • mousewheel 滾輪事件 event.wheelDelta 滾動的幅度 下負上正 120 谷歌+ie
  • DOMMouseScroll 火狐的滾輪事件 event.detail 滾輪的幅度 上負 3
let oW = document.getElementById("wrap");
/*
        谷歌以及ie
        event.wheelDelta   滾動的幅度
            -120  下滾
            120   上滾

        火狐的  滾動事件名都不同
            DOMMouseScroll  只能經過DOM 二級事件監聽
            event.detail   滾動的幅度
                3  下滾
                -3 上滾

        只有谷歌和ie有onmousewheel事件屬性,默認值爲null
        火狐根本就沒有onmousewheel屬性,爲undefined
 */

/*
oW.addEventListener("mousewheel",function (e) {
    console.log(e.wheelDelta);
})
*/

//只能經過建立一個新的節點來判斷兼容
if(document.createElement("div").onmousewheel === null){
    console.log("谷歌");
}else{
    console.log("火狐");
}

兼容的事件監聽

var oW = document.getElementById("wrap");

//元素的事件
var fn = addEvent(oW,'click',function () {
    this.style.backgroundColor = 'red';
});

//文檔雙擊移除事件
addEvent(document,"dblclick",function () {
    removeEvent(oW,'click',fn);
})

//滾輪事件
addEvent(oW,'mousewheel',function () {
    console.log('我滾動了');
})


//添加監聽事件
function addEvent(ele,eType,callback,capture) {

    //主流瀏覽器
    if(ele.addEventListener){

        //兼容一下火狐的滾輪事件
        if(eType === 'mousewheel' && document.createElement("div").onmousewheel === undefined){
            eType = 'DOMMouseScroll';
        }

        ele.addEventListener(eType,callback,capture);

        return callback;
    }else{
        //處理ie的this指向,ie低版本不支持bind
        var codeCall = function(){
            callback.call(ele);
        }
        ele.attachEvent('on'+eType,codeCall);

        return codeCall;
    }
}

//移除事件
function removeEvent(ele,eType,callback,capture) {
    ele.removeEventListener? ele.removeEventListener(eType,callback,capture)
                            : ele.detachEvent("on"+eType,callback);
}

兼容的文檔滾動

//自定義滾動
addEvent(oW,'mousewheel',function (event) {
    event = event || window.event;
    var dir;
    if(event.detail){       //火狐的滾動值
        dir = event.detail / 3;        //下滾
    }else{
        dir = event.wheelDelta / -120; //下滾
    }
    //console.log(dir);
    this.scrollTop += dir*50;
})

21.5 案例 自定義滾動條

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="keywords" content="關鍵詞">
        <meta name="description" content="描述">
        <meta name="author" content="Danew">
        <style>
            #wrap{
                position: relative;
                width:400px;
                height:500px;
                margin:20px auto;
                overflow: hidden;
                user-select: none;
            }
            #wrap .content{
                position: absolute;
                left:0;
                top:0;
                width:370px;
                font-size:14px;
            }
            #wrap .content li{
                width:100%;
                padding:5px 0 5px 10px;
                margin-bottom:1px;
                background-color:#eeeef0;
                line-height:30px;
            }
            #wrap .scrollbar{
                position: absolute;
                right:0;
                top:0;
                width:20px;
                height:496px;
                background-color: #ccc;
                background-color:rgba(200,200,200,.5);
                border-radius: 10px;
                border:2px solid #aaa;
                box-shadow: 0 0 20px #ccc ;
            }
            #wrap .scrollbar .bar{
                position: absolute;
                left:0;
                top:0;
                width:20px;
                height:80px;
                background-color: white;
                border-radius:10px;
            }
        </style>
    </head>
    <body>
        <div id="wrap">
            <ul class="content">
                <li>
                    <p>1. It is never too old to learn.</p>
                    <p>活到老,學到老。</p>
                </li>
                <li>
                    <p>2. There is no royal road to learning.</p>
                    <p>學問無坦途。書山有路勤爲徑,學海無涯苦做舟.</p>
                </li>
                <li>
                    <p>3. A man becomes learned by asking questions.</p>
                    <p>不恥下問纔能有學問。</p>
                </li>
                <li>
                    <p>4. A young idler, an old beggar.</p>
                    <p>少壯不努力,老大徒傷悲。</p>
                </li>
                <li>
                    <p>5. Study to be what you wish to seem. </p>
                    <p>學習可成爲你所理想的人物。</p>
                </li>
                <li>
                    <p>6. By reading we enrich the mind, by conversation we polish it.</p>
                    <p>讀書令人充實,交談令人精明。</p>
                </li>
                <li>
                    <p>7. Books and friends should be few but good.</p>
                    <p>讀書如交友,應求少而精。</p>
                </li>
                <li>
                    <p>8. Readingis to the mind while exercise to the body.</p>
                    <p>讀書健腦,運動強身。</p>
                </li>
                <li>
                    <p>9. A good beginning makes a good ending.</p>
                    <p>良好的開端就是成功的一半。 善始者善終。</p>
                </li>
                <li>
                    <p>10. No matter how bad your heart has been broken, the world doesn’t stop for your grief. The sun comes right back up the next day.</p>
                    <p>無論你有多痛苦,這個世界都不會爲你中止轉動。太陽照樣升起。</p>
                </li>
                <li>
                    <p>11. Experience is the mother of wisdom.</p>
                    <p>實踐出真知。</p>
                </li>
                <li>
                    <p>12. Don't trouble trouble until trouble troubles you.</p>
                    <p>不要自尋煩惱。</p>
                </li>
                <li>
                    <p>13. Everybody dies, but not everybody lives.</p>
                    <p>人人都會死,但非人人都曾活過。</p>
                </li>
                <li>
                    <p>14. Doing is better than saying.</p>
                    <p>行勝於言。</p>
                </li>
                <li>
                    <p>15. Commitment in many, can do. It is just a lie.</p>
                    <p>承諾再多,都作不到。那也只不是是謊話。</p>
                </li>
                <li>
                    <p>16. No cross, no crown.</p>
                    <p>不經歷風雨,怎能見彩虹。</p>
                </li>
            </ul>
            <div class="scrollbar">
                <div class="bar"></div>
            </div>
        </div>
        
        <script>
            (function () {
                var oW = document.getElementById("wrap"),
                    oContent = document.querySelector("#wrap .content"),
                    oScroll = document.querySelector("#wrap .scrollbar"),
                    oBar = document.querySelector("#wrap .bar"),
                    docMove= function () {};

                //內容區的滾動事件
                createEvent(oW,"mousewheel",function (event) {
                    event = event||window.event;       //兼容IE
                    var sT = oContent.offsetTop;
                    var dir = 0;
                    var top = 0;
                    if(event.detail){    //火狐
                        dir = event.detail / 3;         //下滑
                    }else{               //谷歌和IE
                        dir = event.wheelDelta / -120;  //下滑值
                    }
                    if(dir>0){
                        top = Math.max((sT-dir*50),-756);
                    }else{
                        top = Math.min((sT-dir*50),0)
                    }
                    oContent.style.top = top + 'px';
                    oBar.style.top = -top/1.82 + 'px';
                    event.stopPropagation ? event.stopPropagation():(event.cancelBubble=true);
                },false);

                //自定義滾輪區的點擊事件
                createEvent(oScroll,'click',function (event) {
                    event = event||window.event;
                    var y_ = event.clientY - oBar.offsetHeight/2 - oW.offsetTop;
                    if(y_<=0) y_=0;
                    if(y_>=416)y_=416;
                    oBar.style.top = y_+'px';
                    oContent.style.top = -y_*1.82 + 'px';
                    //阻止子級冒泡
                    event.stopPropagation ? event.stopPropagation():(event.cancelBubble=true);
                },true);

                //自定義滾輪的滾動(點擊時拖放)
                createEvent(oBar,'mousedown',function (event) {
                    event = event||window.event;
                    var sT = oBar.offsetTop;
                    var sY = event.clientY;
                    var top = 0;
                    docMove = createEvent(document,'mousemove',function (event) {
                        event = event||window.event;
                        var _Y = event.clientY - sY;
                        if(_Y>0) top = Math.min((sT+_Y),416);
                        if(_Y<0) top = Math.max((sT+_Y),0);
                        oBar.style.top = top+'px';
                        oContent.style.top = -top*1.82 + 'px';
                    })
                })

                //清除移動事件
                createEvent(document,'mouseup',function (){
                    removeEvent(document,'mousemove',docMove);
                });

                //雙擊清除移動事件
                createEvent(document,"dblclick",function () {
                    removeEvent(document,'mousemove',docMove);
                });



                //生成監聽事件
                function createEvent(ele,eType,callback,capture) {

                    if(ele.addEventListener){     //主流
                        //兼容火狐的滾動事件
                        if(eType === 'mousewheel' && document.createElement("div").onmousewheel === undefined){
                            eType = "DOMMouseScroll";
                        }
                        //生成監聽
                        ele.addEventListener(eType,callback,capture);
                        return callback;
                    }else{             //IE8
                        var codeCall = function(){
                            callback.call(ele);
                        }
                        ele.attachEvent('on'+eType,codeCall);
                        return codeCall;
                    }
                }
                
                //清除事件
                function removeEvent(ele,eType,callback,capture) {
                    if(ele.removeEventListener){
                        //兼容火狐的滾動事件
                        if(eType === 'mousewheel' && document.createElement("div").onmousewheel === undefined){
                            eType = "DOMMouseScroll";
                        }
                        ele.removeEventListener(eType,callback,capture);
                    }else{
                        ele.detachEvent("on"+eType,callback);
                    }
                }

            })();
        </script>
    </body>
</html>

22. 表單事件

22.1 表單事件

<div id="wrap"></div>
<a href="" id="x">455454</a>
<form action="" method="" id="form">
    <input type="text" name="user">
    <input type="radio" name="sex">
    <input type="radio" name="sex">
    <input type="submit">
</form>

<script>
    //表單是 .name 就能直接獲取對象
    // name相同,獲取的是相同name的數組
    // checkbox多選框,name不要同樣
    let oForm = document.getElementById("form");
    console.log(oForm.sex);         //   RadioNodeList(2) [input, input, value: ""]
    oForm.user.value = "阿飛飛";


    /*
        onfocus   焦點事件
        onblur    失去焦點事件
            並非全部的元素都能添加焦點事件,只有能得到焦點的元素才能添加焦點事件

            頁面tab鍵能得到焦點的元素(document,a,window,以及表單相關的元素能夠)
     */
    let ox = document.getElementById("x");    
    x.onfocus = function () {              //  TAB鍵觸發
         console.log("我得到焦點了");
    }
    x.onblur = function () {
        console.log("嚶嚶,我失去焦點了");
    }

    //window的焦點事件
    window.onfocus = function () {
        document.title = "烏龍閣的博客";
    }
    window.onblur = function () {
        document.title = "握草,出BUG!快來看看啊";
    }

22.2 定時器關閉

/*
       頁面失去焦點時,定時器setTimeout速度降低,可能影響佈局渲染
                    requestAnimationFrame會當即中止
 */

let num=0;
let timer = null;
function m(){
    document.title = ++num;
    timer = setTimeout(m,50);
    //requestAnimationFrame(m);
};
m();

window.onblur = function () {
    clearTimeout(timer);
}
window.onfocus = function () {
    clearTimeout(timer);
    m();
}

22.3 表單事件 onchange

  • onchange 輸入框,當失去焦點時與獲取焦點時發生改變時觸發
  • oninput 輸入框發生變化時,實時的觸發
  • onselectstart 選中文字,觸發
  • onsubmit 表單觸發提交事件
  • 用select標籤的name屬性獲取選中的option值,如 oForm.gg.value
<form action="" method="" id="form">
    <input type="text" name="user">
    <input type="radio" name="sex">
    <input type="radio" name="sex">
    <input type="submit">
    <select name="gg" id="h">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
    </select>
</form>

<div id="wrap">
    文字文字文字文字文字文字文字文字
</div>
<script>
    /*
        輸入框的onchange,判斷獲取焦點時與失去焦點時的差別
        oninput  響應實時變化事件
     */

    let oForm = document.getElementById("form");
    /*
    oForm.user.onchange = function () {
        console.log(1);
    }
    */
    /*
    oForm.user.oninput= function () {
        console.log(1);
    }
    */
    
    oForm.gg.onchange=function () {
        console.log("選項發生了改變",oForm.gg.value);
    }

    //onselectstart  選中文字時,觸發事件
    document.getElementById("wrap").onselectstart = function () {
        console.log(2);
        return false;        //阻止默認操做
    }

    //表單的提交事件,提交後跳轉一個頁面
    oForm.onsubmit = function () {
        console.log("提交");

        return false;    //拒絕提交(用於判斷是否知足提交條件)
    }

</script>

22.4 案例,限制焦點

<form action="" method="" id="form">
    <input type="text" name="user">
    <input type="text" name="user1">
    <input type="text" name="user2">
</form>

<button id="btn">
    按鈕
</button>

<script>

    let oForm = document.getElementById("form");
    let oBtn = document.getElementById("btn")

    /*  API
        focus()   加焦點
        blur()    失去焦點
        submit()  提交api
     */
 
    let aInp = [...oForm.children];      //動態的
    aInp.forEach((ele,index)=>{
        ele.oninput = function () {
            if(this.value.length >= 5){        //大於5個離開
                this.disabled = true;
                aInp[index+1] && aInp[index+1].focus();    //存在則轉移到下一個焦點
            }
        };
        ele.onblur = function () {
            if(this.value.length<5){        //不滿5個不能離開
                this.focus();
            }
        }
    })

22.5 window.onready window.onload

//等待所有加載完畢
window.onload = function () {

}
//只須要結構加載完畢便可
window.onready = function () {

}

22.6 鍵盤事件

  • keydown 按鍵按下
  • keyup 按鍵擡起
/*
  按鍵按下:  keydown  keypress
        keydown 在 keypress以前觸發
        down響應全部按鍵
        press事件只響應能鍵入值的按鍵,enter也能響應,不響應功能鍵(退格,上下左右)
  按鍵擡起:  keyup
        按鍵擡起時響應
 */

document.onkeydown = function () {
    console.log("處於按下去狀態ing");
}

document.onkeypress = function(){
    console.log("press");
}

document.onkeyup = function () {
    console.log("按鍵擡起了!");
}

鍵值

  • 回車鍵 keyCode = 13
  • F12 keyCode = 123
/*
    事件event只包含鍵盤的屬性,沒有鼠標的信息
    e.keyCode
 */
document.onkeydown = function (e) {
    console.log(e);
    console.dir(e.keyCode);
    if(e.keyCode === 123){            // 123 阻止按鍵 F12 打開調試面板
        return false;
    }
}

按鍵控制盒子移動

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="keywords" content="關鍵詞">
        <meta name="description" content="描述">
        <meta name="author" content="Danew">
        <style>
            body{font-family: "Microsoft YaHei",serif;}
            body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
            ol,ul,li{margin:0;padding:0;list-style:none;}
            img{border:none;}

            #wrap{
                position: absolute;
                left:200px;
                top:200px;
                width:100px;
                height:100px;
                background-color: pink;
            }
        </style>
    </head>
    <body>
        <div id="wrap"></div>
        
        <script>
            let oW = document.getElementById("wrap");
            document.onkeydown = function (ev) {
                let keyCode = ev.keyCode;
                switch (keyCode) {
                    case 65:   //a
                        oW.style.left = oW.offsetLeft-5+'px';
                        break;
                    case 87:    //w
                        oW.style.top = oW.offsetTop-5+'px';
                        break;
                    case 83:   //s
                        oW.style.top = oW.offsetTop+5+'px';
                        break;
                    case 68:   //d
                        oW.style.left = oW.offsetLeft+5+'px';
                        break;
                }
            };

            //運動
        </script>
    </body>
</html>

多按鍵同時控制

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="keywords" content="關鍵詞">
    <meta name="description" content="描述">
    <meta name="author" content="Danew">
    <style>
        body{font-family: "Microsoft YaHei",serif;}
        body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
        ol,ul,li{margin:0;padding:0;list-style:none;}
        img{border:none;}

        #wrap{
            position: absolute;
            left:200px;
            top:200px;
            width:100px;
            height:100px;
            background-color: pink;
        }
    </style>
</head>
<body>
    <div id="wrap"></div>

    <script>
        let oW = document.getElementById("wrap");
        let ifDown = {
            65:{
                bool:false,
                timer:null,
                setTimer(){
                    oW.style.left = oW.offsetLeft-5+'px';
                    this.timer = requestAnimationFrame(this.setTimer.bind(this));
                },
                clearTimer(){
                    cancelAnimationFrame(this.timer);
                }
            },
            87:{
                bool:false,
                timer:null,
                setTimer(){
                    oW.style.top = oW.offsetTop-5+'px';
                    this.timer = requestAnimationFrame(this.setTimer.bind(this));
                },
                clearTimer(){
                    cancelAnimationFrame(this.timer);
                }
            },
            83:{
                bool:false,
                timer:null,
                setTimer(){
                    oW.style.top = oW.offsetTop+5+'px';
                    this.timer = requestAnimationFrame(this.setTimer.bind(this));
                },
                clearTimer(){
                    cancelAnimationFrame(this.timer);
                }
            },
            68:{
                bool:false,
                timer:null,
                setTimer(){
                    oW.style.left = oW.offsetLeft+5+'px';
                    this.timer = requestAnimationFrame(this.setTimer.bind(this));
                },
                clearTimer(){
                    cancelAnimationFrame(this.timer);
                }
            }
        }

        //按下啓動定時
        document.onkeydown = function (ev) {
            let keyCode = ev.keyCode;
            if(!ifDown[keyCode]) return;
            ifDown[keyCode].bool || ifDown[keyCode].setTimer();
            ifDown[keyCode].bool = true;
        };

        //擡起清除定時
        document.onkeyup = function (ev) {
            let keyCode = ev.keyCode;
            if(!ifDown[keyCode]) return;
            ifDown[keyCode].clearTimer();
            ifDown[keyCode].bool = false;
        }
    </script>
</body>
</html>

23. 正則表達式

23.1 有什麼用

不用正則時,通常用 !isNaN(121)=true 來提取數字

/*
    正則表達式
        對象
        配合一些api來驗證字符串
 */
let a="456阿飛789朱雀12";   //["456","789,"12"]
let b="454sjjdsiaodao5454";
let c="sds45sd45s21a";

console.log(fn(a));
console.log(fn(b));
console.log(fn(c));
console.log("*************************");
console.log(zz(a));
console.log(zz(b));
console.log(zz(c));

function zz(str) {
    return str.match(/\d+/g);
}

function fn(str) {
    let len = str.length;
    let s ="";
    let arr = [];
    for(let i=0;i<len;i++){
        let n=str.charAt(i);
        if(!isNaN(n)){  //數字字符不是NaN,其餘字符是NaN
            //console.log(n);
            s+=n;
        }else{       //NaN
            s && arr.push(s);
            s="";
        }
    }
    s && arr.push(s);
    return arr;
}

23.2 正則表達式

建立正則表達式對象的兩種方法

  • let a = /abc/
  • let b = new RegExp("abc")

驗證正則的方法

  • a.test(str) 返回 true or false
/*
    正則表達式對象 兩種建立方式
        1. 雙斜槓包括的字符
        2. new RegExp("")
 */

let a = /abc/;
console.log(typeof a);      //object
let b = new RegExp("abc");  //和第一種建立的效果同樣

/*api1

    test()
    正則.test(字符串)
    匹配成功返回true,不然返回false
 */
let a = /abc/;    //匹配完整連續的abc字符串
console.log(a.test("阿飛abc朱雀"));;



/*
     / /不能傳變量
 */
let s = "abc";
//let a=/s/;       //這種定義方式,是沒有辦法根據變量來制定正則的
let a = new RegExp(s);      //能夠用變量
console.log(a.test("阿飛abc朱雀"));

23.3 轉移符號\的用法

字符串中實現轉義 "\\" 打印 "\"

/*
    \轉義符號,默認在字符串中的\有特殊意義,不能單獨出現
 */
console.log("阿飛\"love\"朱雀\n123456\t789021");

//轉義符號將有特殊意義的字符變成沒有特殊意義
let str = "/\\";
let a=/\/\\/;          //用轉義字符"\"轉義"/"和"\"
console.log(a.test(str));


/*
    轉義符號配合一些字母使用,有很是獨特的意思
        \s   各類空格, \t  \n  \r  " "
        \S   非空格,\s的補集

        \d   數字
        \D   \d的補集

        \w   數字、字母、下劃線   通常匹配用戶名的
        \W

        \b  連詞符 起始  結束  (空格 以及 (除了\w以外)  全部內容都是獨立部分)
        \B
 */
let a = /\s/;
let s = "   ";

let a=/\d\d/;        //連續兩個數字
let s="fffff79pppp";

let a = /\w/;
let s = "abc";

/*  算做"afei"獨立的字符
        "I am afei-1"
        "I am afei阿飛"
        "I am afei.abc"

    \b只能用於匹配英文,中文自己就不獨立,不能使用\b獨立匹配
 */
let a = /\bafei\b/;    //要匹配獨立的部分
let s = "I am afei.abc";   //能夠   "afeihui"就不行
console.log(a.test(s));

23.4 修飾符 i m g

驗證正則的方法 match

  • str.match(a) 返回全部匹配正則的元素組成的數組,(a是加了g的全局匹配)
/*
    修飾符(寫在//後面
        i   不區分大小寫
        g   全局匹配
        m   換行匹配
 */
let a = /g/i;
let s = "G";
console.log(a.test(s));


/*
    .match()
    字符串.match(正則)
    尋找匹配的內容,拿到並組成一個數組返回,不然返回null
 */
let a = /xx/ig;
let s = "XxgfxxhxXx";     //xXx只能識別前兩個
console.log(s.match(a));  //加了g後是純粹的數組,沒有別的屬性

23.5 量詞

/*
    量詞 { }
        {n} n個
        {n,m} n~m包含n也包含m
        {n,} n~無窮大 包含n

            默認按多的取(貪婪模式)
            量詞後面加問號"?"就成了(惰性模式)

    幾個特殊量詞有專屬的符號代替
        {1,}   +            至少一個
        {0,}   *            至少0個
        {0,1}  ?            要麼有要麼沒有

 */
let a = /\d\d\d\d\d\d\d\d\d\d\d/g;
let s = "阿飛18860900316阿飛";

let a = /飛\d{11}/g;  //{11}只表示\d重複11次
let s = "阿飛18860900316阿飛15357875321";

let a = /\d{2,4}?/g;   // 惰性匹配,因此只匹配2個的 
let s = "1-23-234-456阿飛18860900316阿飛15357875321";
// ["23", "23", "45", "18", "86", "09", "00", "31", "15", "35", "78", "75", "32"]

let a = /\d{2,}/g;          //至少2個
let s = "1-23-234-456阿飛18860900316阿飛15357875321";
// ["23", "234", "456", "18860900316", "15357875321"]


//let a = /\d+/g;      //最少一個取
//let a = /\d+?/g;     //匹配到後,一個個取
//let a = /\d*?/g;     //返回的全是空  至關於 //g
let a = /\d??/g;       //全是空
let s = "gh777scsf45dsdsd454s35";
console.log(s.match(a));

23.6 子項()

加了括號的成爲子項,使用全局g,則不打印子項

獲取第一個子項 s.match(a)[1]

匹配失敗,返回null

/*
    子項 ( )
 */

let a = /(ab)+/;    //  不加括號,只能匹配abbbb
let s = "abababab"; //  ["abababab", "ab", index: 0, input: "abababab", groups: undefined]

let a = /gg(ab)+f(f)/;    //加了括號的子項也會打印出來,使用全局g,則不打印子項
let s = "ababggababffababa";  
//不加g,打印子項["ggababff", "ab", "f", index: 4, input: "ababggababffababa", groups: undefined]


//利用子項,只獲取子項中的號碼
let a = /阿飛:(\d{11})/;
let s = "阿飛:12121212321,朱雀:32321232123";
console.log(s.match(a),s.match(a)[1]);
// ["阿飛:12121212321", "12121212321", index: 0, input: "阿飛:12121212321,朱雀:32321232123", groups: undefined] "12121212321"

23.7 一個[]字符集只匹配一個字符

/*
    |   或者
    []  字符集,一個字符集只匹配一個字符
        [a-z]  字符區間("-"在"[]"內有了特殊意義)
        [abc]  或者的意思
        [^abc] 放在正則字符的首位,表示除了這些,(不放在首位表示一個單純的字符)
        [{}?*.+()] 這些原來有特殊意義的字符放在[]內沒有了特殊意義,就是單純的字符

        [a-z]
        [A-Z]全部的字母

 */

let a = /abc|edf/g;       //或者匹配
let s = "edfabcedfabc";

let a = /(阿飛|朱雀)老師/g;       //用子級匹配,加外面公用的
let s = "朱雀老師美,阿飛老師帥";

let a = /1|2|3|4|5|6|7/g;      //1或者7中的任何一個
let a = /[1-7]{5}/g;           //區間,表明1到7之間任何一個連續5個

//ascii碼的匹配,注意要有先後順序
let a = /[2-B]/g;
let s = "23456789:;C<=>?@AB";

//unicode字符編碼也能匹配
let a = /[阿-飛]/g;      //意義不大
let s = "阿飛老師";


let a = /[abc0-9]/g;       //a或b或c,0到9
let s = "2345abc";

//匹配全部的數字和字母
let a = /[a-zA-Z0-9]/g;
let s = "2345abcAfejnfjGHjfbj";

let a = /[^abc]/g;       //除了,取反只能放在首位
let s = "2345abcAfejnfjGHjfbj";

let a = /[{}?*./+()[\]\-]/g;       //字符集內的字符失去了特殊意義
let s = "2345abcAfejnfjGHjfbj";
console.log(s.match(a));

23.8 起止字符

/*
    起止字符
       ^    起始位置
       $    結束位置
 */

let a = /^abc$/;      //只能匹配"abc",空格都不能夠有
//let s = "gabcgg";   //必須是a起始的字符串才能匹配
let s = "gabcgg";
console.log(s.match(a));


//
console.log("ddabcdd".match(/(a|^)bc/));     // abc   a是子項
console.log("bcjfjfjfjfj".match(/(a|^)bc/)); // bc    子項爲""

23.9 .字符

/*
    .  匹配任意字符   除了換行等以外  \n  \r

    [.]的.是單純的匹配字符.
 */

let a = /./g;
let s = ".123\r46\n5";
console.log(s.match(a));

//匹配全部的字符
/[\s\S]/
/[\w\W]/

23.10 應用案例

/*
                /a/
                new RegExp()
                \s \S \w \W \d \D \b \B
                修飾詞  igm
                量詞{} *+?      惰性?取短的
                子項()
                字符集[]
                | ^  $  .

             */

let reg={
    //qq:5~10,只能是數字,第一位不是0
    qq: /^[1-9]\d{4,9}$/,
    //用戶名:6~18,數字字母_,必需要字母開頭
    user:/^[a-z]\w{5,17}$/i,
    //密碼:6~18,數字字母_全部符號
    pwd:/^[\w<>,.?/\-+=*@#$%^&()[\]`~|\\{}<>]{6,18}$/,
    //手機號:
    tel:/^1[3-9]\d{9}$/,
    //郵箱
    mail:/^[a-z1-9_]\w{0,17}@[0-9a-z]{2,}(\.[a-z]{2,4}){1,2}$/i,
    //身份證
    IDCard:/^[1-9]\d{5}(18|19|20)\d{2}(0[13578]|1[02])(0[1-9]|[12][0-9]|3[01])|(0[469]|11)(0[1-9]|[12][0-9]|30)|(02(0[1-9]|[12][0-9]))\d{3}[0-9x]$/i,

}

// let a = reg.qq;
let b = reg.mail;
// let s = "3045282682";
// console.log(a.test(s));
console.log(b.test("1886@163.com"));

// let a = reg.IDCard;
// console.log(a.test("341221199411178765"));

//大月
//31天
/*
            /(0[13578]|1[02])(0[1-9]|[12][0-9]|3[01])/
            //30天
            /(0[469]|11)(0[1-9]|[12][0-9]|30)/
            //2月
            /(02(0[1-9]|[12][0-9]))/
            //一塊兒
            /(0[13578]|1[02])(0[1-9]|[12][0-9]|3[01])|(0[469]|11)(0[1-9]|[12][0-9]|30)|(02(0[1-9]|[12][0-9]))/

            /((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01])|(0[469]|11)(0[1-9]|[12][0-9]|30)|(02(0[1-9]|[12][0-9])))/
            */

23.11 捕獲組

捕獲的是子項 RegExp.$1 最近的一次正則結果中的子項

捕獲用 \n 表示,表明一個子項

let a = /a(b)(c)/;
let s = "abc";
console.log(a.test(s));


let a = /(阿飛|朱雀)老師/;
let s = "abc阿飛老師";
let s1 = "abc朱雀老師";
a.test(s);
s1.match(a);
console.log(RegExp.$1);      //離它最近一次正則結果的子項1  朱雀
console.log(RegExp.$9);      //最多存9個子項  沒有就是 空



//捕獲組,1表示重複第1個子項,沒有加g,因此第一次匹配到後就結束匹配
let a = /(\d)\1/;     //捕獲組,重複子項   aa bb
let a = /(\d\d)\1/;   //捕獲組,重複子項   abab
let a = /(\d(\d))\1\2/; //捕獲組,重複子項   ababb
let a = /(\d\d)\1{9}/;  //捕獲組,能夠用量詞   abab*n
let a = /(\d(\d))\2\1/; //捕獲組,重複子項   abbab
let s = "797994545545";

console.log(s.match(a));

23.12 案例 表單驗證

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="keywords" content="關鍵詞">
        <meta name="description" content="描述">
        <meta name="author" content="Danew">
        <style>
            body{font-family: "Microsoft YaHei",serif;}
            body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
            ol,ul,li{margin:0;padding:0;list-style:none;}
            img{border:none;}

            #wrap{
                position: relative;
                width:430px;
                height:550px;
                margin:50px auto 0;
                background-color: #00baff;
            }
            #wrap .title{
                height:40px;
                line-height: 40px;
                background-color: #008ccf;
                color:white;
                font-size: 24px;
                text-align: center;
                font-weight: bold;
            }
            #wrap input{
                display: inline-block;
                width:250px;
                height:40px;
                padding-left: 20px;
                margin-left: 80px;
                margin-top:20px;
            }
            #wrap input.error{
                border: 2px solid red;
            }
            #wrap input.ok{
                border:2px solid #479552;
            }
            #wrap img{
                display: none;
                width:30px;
                height:30px;
                vertical-align: middle;
            }
            #wrap input[type=submit]{
                width:270px;
                padding:0;
                background-color: #008ccf;
                outline-style: none;
                color:white;
                font-weight: bold;
                cursor:pointer;
            }
            #wrap label{
                overflow: hidden;
                display: block;
                height:0;
                margin-left: 80px;
                color:red;
                font-size: 12px;
            }
            #alert{
                position: absolute;
                left: 0;
                right:0;
                top:0;
                bottom:100px;
                visibility: hidden;
                width:150px;
                height:40px;
                margin: auto;
                background-color: black;
                color:white;
                text-align: center;
                line-height: 40px;
                opacity: 0;
                transition: bottom .4s,opacity .5s ;
            }
            #alert.on{
                visibility:visible;
                bottom: 0;
                opacity: 1;
            }
        </style>
    </head>
    <body>
        <div id="wrap">
            <p class="title">註冊</p>
            <form action="" method="" id="form">
                <input type="text" name="name" id="name" placeholder="請輸入您的用戶名">
                <img src="img/yes.png">
                <label for="name">錯誤:用戶名以字母開頭,長度爲6~16位</label>
                <input type="password" name="pwd" id="pwd" placeholder="請輸入您的密碼">
                <img src="img/yes.png">
                <label for="name">錯誤:注意密碼長度爲6~18位</label>
                <input type="password" name="repwd" id="repwd" placeholder="請再次輸入您的密碼">
                <img src="img/yes.png">
                <label for="name">錯誤:兩次密碼輸入不一致</label>
                <input type="text" name="phonenumb" id="phonenumb" placeholder="請輸入您的手機號">
                <img src="img/yes.png">
                <label for="name">錯誤:手機號格式不正確</label>
                <input type="text" name="qq" id="qq" placeholder="請輸入您的QQ號">
                <img src="img/yes.png">
                <label for="name">錯誤:QQ號碼格式不正確</label>
                <input type="text" name="mail" id="mail" placeholder="請輸入您的郵箱">
                <img src="img/yes.png">
                <label for="name">錯誤:郵箱格式不對,請從新輸入</label>
                <input type="submit" value="提交" id="submit">
                <div id="alert">請先輸入密碼!</div>
            </form>
        </div>
        
        <script>
            (function () {
                let aLabel = document.querySelectorAll("#wrap label"),
                    aImg = document.querySelectorAll("#wrap img"),
                    oName = document.getElementById("name"),
                    oPwd = document.getElementById("pwd"),
                    oRepwd = document.getElementById("repwd"),
                    oPnumb = document.getElementById("phonenumb"),
                    oQQ = document.getElementById("qq"),
                    oMail = document.getElementById("mail"),
                    alert = document.getElementById("alert")
                ;

                //驗證規則
                let reg={
                    //用戶名
                    name:/^[a-z]\w{5,15}$/i,
                    //密碼
                    pwd:/^[\w~`!@#$%^&*()\-+=[\]{}'";:,.<>/?\\]{6,18}$/,
                    //手機號
                    tel:/^1[3-9]\d{9}$/,
                    //qq
                    qq:/^[1-9]\d{4,9}$/,
                    //郵箱
                    mail:/^[a-z1-9_]\w{0,17}@[0-9a-z]{2,}(\.[a-z]{2,6}){1,2}$/i
                };
                let isCheck=[];

                //定義添加驗證函數
                function addCheckEvent(ele,reg,index) {
                    //輸入時,取消對勾
                    ele.addEventListener("focus",function () {
                        aImg[index].style.display = "none";
                    })

                    //離開時驗證
                    ele.addEventListener("blur",function () {
                        if(!ele.value){
                            ele.className="";
                            ele.className="";
                            aImg[index].style.display = "none";       //不顯示對勾
                            aLabel[index].style.height = 0+'px';        //錯誤不提示
                            return;
                        };       //未填寫則返回
                        //驗證成功
                        if(reg.test(ele.value)){
                            ele.className="ok";     //綠框
                            isCheck[index]=true;    //表示驗證過
                            aImg[index].style.display = "inline-block"; //對勾
                            aLabel[index].style.height = 0+'px';        //錯誤不提示
                        }else{
                            ele.className="error";  //紅框
                            isCheck[index]=false;   //未驗證經過
                            aImg[index].style.display = "none";       //不顯示對勾
                            aLabel[index].style.height = 16+'px';     //提示錯誤
                            ele.focus();            //鎖定焦點
                        }
                    });
                }

                //1. 驗證用戶名
                addCheckEvent(oName,reg.name,0);

                //2.驗證密碼
                addCheckEvent(oPwd,reg.pwd,1);

                //3.二次密碼focus
                oRepwd.addEventListener("focus",function () {
                    //先取消對勾
                    //aImg[2].style.display = "none";
                    //判斷第一次密碼輸入狀態
                    if(!oPwd.value){       //密碼未輸入
                        setTimeout(function () {
                            alert.classList.add("on");  //動畫提示
                            oPwd.focus();
                        });
                        setTimeout(function () {
                            alert.classList.remove("on"); //定時消失
                        },2000);
                    }
                })
                //二次密碼驗證blur
                oRepwd.addEventListener("blur",function () {
                    if(!oRepwd.value){
                        oRepwd.className="";
                        aImg[2].style.display = "none"; //對勾
                        aLabel[2].style.height = 0+'px';        //錯誤不提示
                        return;
                    };     //未填寫則返回

                    if(isCheck[1]){     //第一次密碼已經驗證
                        if(oRepwd.value === oPwd.value){   //密碼同樣
                            oRepwd.className="ok";              //綠框
                            isCheck[2]=true;                    //表示驗證過
                            aImg[2].style.display = "inline-block"; //對勾
                            aLabel[2].style.height = 0+'px';        //錯誤不提示
                        }else{                               //不經過
                            oRepwd.className="error";              //綠框
                            isCheck[2]=false;                    //表示驗證過
                            aImg[2].style.display = "none"; //對勾
                            aLabel[2].style.height = 16+'px';        //錯誤不提示
                            oPwd.focus();                    //鎖定第一次輸入密碼
                        }
                    }
                })

                //4.驗證手機號
                addCheckEvent(oPnumb,reg.tel,3);

                //5.驗證QQ號
                addCheckEvent(oQQ,reg.qq,4);

                //6.驗證郵箱
                addCheckEvent(oMail,reg.mail,5);

            })();


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

23.13 正向斷言(?=a)

/*
    斷言,JS只有正向斷言,放在後面,括號不算子項
        (?=a)    格式限定後面緊接着必須是a,但不但願匹配結果中有a
        (?!a)    格式限定後面緊接着不能是a
 */

 // let r = /(阿飛|朱雀)老師,\1老師/;
 // let s = "阿飛老師,阿飛老師";

let r = /Window(?=XP)/;   //但願格式是WindowXP,但不但願結果中有XP,全部用?    這個()不是子項
let s = "WindowXPx";

let r = /Window(?!XP)/;   //不但願格式是Window後接着XP,?!  這個()不是子項
let s = "Window111";

console.log(s.match(r));
console.log(RegExp.$1);

23.14 replace

/*
    replace
        str.replace(正則,字符串|函數);
        替換匹配到的內容變成第二個參數的內容
        (若是是字符串直接替換,若是是函數,替換返回值)
 */
let reg = /(阿飛|風嶼|海文)(老師|先生|大大)/g;
let str = "阿飛老師是個純粹的大豬蹄,風嶼先生真自戀,海文大大脾氣很差";

let newStr = str.replace(reg,"小浪");

let newStr = str.replace(reg,(...rest)=>{
     //通過了不少運算以後,獲得用來替換的字符串
     console.log(rest);
     return '小浪';
});


let newStr = str.replace(reg,(a,b,c)=>{
    //通過了不少運算以後,獲得用來替換的字符串
    console.log(a,b,c); //a表示正則形參,b表示第一個子項,c表示第二個子項
    return '小浪'+c+c.slice(1);
});

console.log(newStr);

23.15 髒字過濾器

<div id="wrap">
    <input type="text">
    <button class="btn">發送</button>
    <ul></ul>
</div>

<script>
    let Btn = document.getElementsByClassName("btn")[0],
        Input = document.getElementsByTagName("input")[0],
        oU = document.getElementsByTagName("ul")[0]
    ;

    Btn.onclick = function () {
        let str = Input.value;
        if(str === "")return;

        let reg=/傻[,./<>\-+=\d]*逼|草|操|cao|艹|你[爸媽]|王八蛋|/g;

        str = str.replace(reg,($0)=>{
            let s="";
            [...$0].forEach(()=>s+="□")
            return s;
        })

        let oLi = document.createElement("li");
        oLi.innerText = str;
        oU.appendChild(oLi);
        Input.value="";
    }
</script>
/*
    適合小數據的存儲,字符串緩存,存在本地的
    1.不一樣的瀏覽器存放的cookie位置不同,也是不能通用的
    2.cookie的存儲是以域名形式進行區分的
    3.cookie的數據能夠設置名字的
    4.一個域名下存放的cookie的個數是有限制的,不一樣的瀏覽器存放的個數不同
    5.每一個cookie存放的內容大小也是有限制的,不一樣的瀏覽器存放大小不同
        本地文件不支持cookie,火狐瀏覽器支持,經過Webstorm打開支持
 */

/*
    若是不給cookie設置過時時間,那麼瀏覽器關閉以後,cookie就清除了
    在存儲本地cookie確定是須要設置過時時間的
    expires  一個日期對象轉換成的字符串,默認是UTC時間
 */
//每條cookie都須要單獨設置,不支持一次賦值設置多個cookie
document.cookie = "user=阿飛;pwd=123";     沒用的

let date = new Date(new Date().getTime()-7*24*3600*1000);
document.cookie = "goudan=阿飛;expires="+date.toUTCString(); //date轉成UTC時間進行賦值
document.cookie = "pwd=123";

//獲取所有cookie
console.log( document.cookie );

24.2 封裝cookie的增刪改查API

let Cookie ={
   //設置,修改
    set(mJson,day) {
        //設置過時時間,不設置day默認undefined,計算時 = NaN,此時設置的cookie關閉瀏覽器釋放
        let date = new Date(new Date().getTime()+day*24*3600*1000).toUTCString();
        Object.entries(mJson).forEach(([key,value])=>{
            document.cookie = `${key}=${value};expires=${date}`;
        })
    },
   //獲取
    get(key) {
         //不傳值返回所有cookie構建的對象
        if(!key){
            let json=document.cookie;
            let obj={};
            while(json){
                let reg=/(^|\s)(\w+)=([^;]+)(;|$)/;
                let arr = json.match(reg);
                json = json.split(arr[0])[1].toString();
                obj[RegExp.$2]=RegExp.$3;
            }
            return obj;
        }else{
            let str = document.cookie;
            //  /(^|\s)aaa=([^;]+)(;|$)/
            let reg = new RegExp("(^|\\s)"+key+"=([^;]+)(;|$)");
            if(reg.test(str)){
                return RegExp.$2;      
            }else{
                return undefined;   //匹配不成功返回undefined
            }
        }
    },
   //刪除
   remove(key) {
       Cookie.set({
           [key]:""    //清空
       },-1);
   }
};

Cookie.set({
    a:'阿飛',
    b:123,
    goudan:"afei"
},7);  //7天

//測試get
console.log(Cookie.get("goudan"));
//刪除cookie
Cookie.remove("b");

24.3 ES6的Object的API

//ES6寫法 ,屬性名的變量寫法

let a = "name";
let obj= {
    [a]:"阿飛"          // 這裏a加【】代指變量 「name」
};
console.log(obj);


let afei= {
    name :"阿飛",
    age:18,
    sex:0
};

console.log(Object.keys(afei));        //提取對象全部屬性名,返回數組
console.log(Object.values(afei));      //提取對象全部值,返回數組
console.log(Object.entries(afei));     //提取對象的鍵值,返回二位數組
<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="keywords" content="關鍵詞">
        <meta name="description" content="描述">
        <meta name="author" content="Danew">
    </head>
    <body>
        <div id="wrap">
            歡迎訪問本站!您上次訪問本站的時間爲:2018-11-10,20:50:20
        </div>
        <script>
            //封裝的cookie
            let Cookie ={
                set(mJson,day) {
                    let date = new Date(new Date().getTime()+day*24*3600*1000).toUTCString();
                    Object.entries(mJson).forEach(([key,value])=>{
                        document.cookie = `${key}=${value};expires=${date}`;
                    })
                },
                get(key) {
                    //不傳值返回所有cookie構建的對象
                    if(!key){
                        let json=document.cookie;
                        let obj={};
                        while(json){
                            let reg=/(^|\s)(\w+)=([^;]+)(;|$)/;
                            let arr = json.match(reg);
                            json = json.split(arr[0])[1].toString();
                            obj[RegExp.$2]=RegExp.$3;
                        }
                        return obj;
                    }else{
                        let str = document.cookie;
                        let reg = new RegExp("(^|\\s)"+key+"=([^;]+)(;|$)");
                        if(reg.test(str)){
                             return RegExp.$2;      
                        }else{
                            return undefined;   //匹配不成功返回undefined
                        }
                    }
                },
                remove(key) {
                    Cookie.set({
                        [key]:""    //清空
                    },-1);
                }
            };

            (function () {
                //lastTime存儲上一次的時間
                let oW = document.getElementById("wrap");
                let lastTime = Cookie.get("lastTime");
                let date = new Date().getTime();
                function showText(lastTime) {
                    if(lastTime){
                        let date = new Date(lastTime-0);
                        return `歡迎訪問本站!您上次訪問本站的時間爲:${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()},${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
                    }else{
                        return "您是第一次訪問本站喲!";
                    }
                }

                oW.innerText = showText(lastTime) ;
                Cookie.set({
                    lastTime:date
                },9999);
            })();
        </script>
    </body>
</html>

25. ajax

/*
    Ajax
        異步的javascript和xml
            同步
                一心一意
            異步
                三心二意
        功能
        無刷新頁面的狀況下,實現與後臺的數據交互,同時在頁面進行更新
    跨域
        默認不容許跨域請求資源
        安全問題
        前端能不能請求到數據,是後端說了算
 */

//建立  ajax對象
const ajax = new XMLHttpRequest();
//監聽狀態的改變
/*
    0~4
        0   初始化狀態  ajax已經被建立
        1   open()方法已經調用
        2   send()方法已調用
        3   全部的響應已經收到
        4   http響應已經徹底接收
 */
ajax.onreadystatechange = function(){
    if(ajax.readyState === 4 & ajax.status === 200){
        //前端 就可以接收到數據了
        //console.log(ajax.response);
        //把對應的數據  轉換成對應的數據類型
        console.log(JSON.parse(ajax.response));
    }
}
//路徑不能出現中文
//本地測試
//ajax.open('get','./data.php',true);      //經過什麼樣的方式,向什麼樣的後端服務器  發送什麼的請求(true表示異步)
//ajax.send();                             //執行請求命令

//真實服務器, 數據先行, 數據驅動視圖
ajax.open('get','http://www.tanzhouweb.com/48/data.php',true);
ajax.send();

25.1 封裝一個ajax

//調用方式
ajax({
  	url:"www.baidu.com",
    method:"get",
    data:{
        name:"peter",
        age:18
    },
    success:function(msg){
        
    },
    error:function(err){
        
    }
})
function ajax(json){
    var method  = json.method.toUpperCase() || "GET";
    var data = json.data || {};
    
    var xhr = new XMLHttpRequest();
    switch(method){
        case 'GET':
            xhr.open(method,json.url+"?"+jsonUrl(json.data),true);
            xhr.send(null);
            break;
        case 'POST':
            xhr.open(method,json.url,true);
            //設置post請求頭
            xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
            xhr.send(jsonUrl(json.data));
            break;
    }
}

xhr.onreadystatechange=function(){
    if(xhr.readyState === 4){
        if(xhr.status>=200 || xhr.status<=300 || xhr.status === 304){
            json.success(xhr.responseText);      //responseText 纔是服務器返回數據
        }else{
            json.error(xhr.status);
        }
    }
}


function jsonUrl(data){
    var arr=[];
    for(var key in data){
        arr.push(key+'='+data[key]);
    }
    return arr.join("&");
}

25.2 jsonp跨域解決方案

/*
    jsonp   一種跨域問題的解決方案
*/
function getData(data) {
    console.log(data);
}

//核心本質   就是後端服務器  返回一個函數調用   getData('js')
createJsonp();
function createJsonp() {
    const s = document.createElement('script');
    // s.src='http://www.tanzhouweb.com/48/jsonp.php?callback=getData';
    s.src='http://localhost/data.php?callback=getData';
    document.body.appendChild(s);
}

25.3 CORS服務器容許跨域

設置響應頭,res.writeHeader(200,{'Access-Control-Allow-Origin':'*'})

/*
    cmd檢測nodejs的安裝
            node -v
            npm  -v
 */
//經過 node的原生模塊  http  搭建服務器  提供數據接口
const http = require('http');

http.createServer(function () {
    res.writeHeader(200,{
        'Access-Access-Control-Allow-Origin':'*'
    })
    res.end("hi~這裏是node服務器返回的數據");
}).listen(6060);

express

const express = require('express');
const app = express();
//在中間件設置容許先後端跨域
app.use((req,res,next)=>{
    res.set('Access-Control-Allow-Origin','*');
    next();
})

26. 面向對象

26.1 封裝一個對象函數

/*
    OOP
    封裝  繼承  多態
 */

var afei = teacher(1111,'阿飛',18);
var zhuque = teacher(2222,'朱雀',20);

//封裝一個對象函數
function teacher(id,name,age) {
    var o = {};
    o.id = id;
    o.name=name;
    o.age=age;
    o.showID = function () {      //堆內存佔用了多個
        alert(this.id);
    }
    return o;
}

26.2 new

/*
    new Date()
    new Image()
    new XMLHttpRequest()
    new RegExp()
    new Array()

    new 關鍵詞     後面緊跟一個  函數
        經過new執行函數對函數的影響:
            ①:函數內部生成一個全新的對象,函數的this指向這個對象
            ②:函數默認返回上述對象
 */

//fn();    //函數自執行;非嚴格模式指向window,嚴格模式指向undefined
function fn() {
    // console.log(this);   //new的this指向全新的對象,只有this能指向這個對象
    this.x = 10;
}
new fn();  //先初始化一個空{},而後將{}的proto即隱式原型指向fn的prototype,而後執行了fn.call({})將this做用域交予{},完成實例化
console.log(new fn());   // fn {x: 10}
var afei = new Teacher(1111,'阿飛',18);
var zhuque = new Teacher(2222,'朱雀',20);

console.log(afei.showID === zhuque.showID);  //false       每一個對象都佔用一個堆內存存放函數

//構造函數  / 類
function Teacher(id,name,age) {
    this.id = id;
    this.name=name;
    this.age=age;
    this.showID = function () {      //堆內存佔用了多個
        alert(this.id);
    }
}

26.3 原型

/*
    原型
    prototype  是一個對象數據類型
    它是構造函數的一個屬性

    每個實例都共享這個原型的屬性
 */

//構造函數
function Teacher(id,name,age) {
    this.id = id;
    this.name=name;
    this.age=age;
}
// console.dir(Teacher);
Teacher.prototype.x = 10;     //原型也是對象
Teacher.prototype.showID=function () {       //全部實例公用一個showID屬性
    alert(this.id);
}

var afei = new Teacher(1111,'阿飛',18);       //  實例
var zhuque = new Teacher(2222,'朱雀',20);


console.log(afei);
console.log(afei.x,zhuque.x,afei.__proto__===zhuque.__proto__);
console.log(afei.__proto__ === Teacher.prototype);  //實例的__proto__ 全等於 構造函數的 prototype屬性
// 構造函數的原型是對象數據類型 {x: 10, showID: ƒ, constructor: ƒ}

//afei.showID();
console.log(afei.showID === zhuque.showID);   // true   共享一個堆內存

26.4 原型鏈

/*
    當訪問對象的屬性時,先從自身找,自身沒有,才進入原型中找;原型找不到去原型的原型裏面找,直到Object.prototype 爲止,由於Object沒有__proto__屬性,原型鏈到此結束
    實例沒有 prototype 屬性;Object沒有__proto__屬性
    
    構造函數的隱式原型是Function:   A.__proto__ === Function.prototype
    構造函數的原型是其實例的隱式原型:A.prototype === new A().__proto__  
    Function比較特殊   			   Function.__proto__.__proto__ === Object.prototype
    
    goudan.__proto__ = Fn.prototype   
    Fn.prototype.__proto__ = Object.prototype
 */
function Fn() {
    this.x=10;            //實例的x屬性
}
Fn.prototype.x=20;        //原型的x屬性
console.log(Fn.prototype.constructor === Fn);      //true  構造屬性

var goudan = new Fn();       //  實例

console.log(goudan.x);
console.log(goudan.__proto__ === Fn.prototype);            //true   Fn的原型

console.log(Fn.prototype);
console.log(Fn.prototype.__proto__ === Object.prototype);   //true   Fn.prototype 是 Object的原型
// 構造函數的原型 是 Object 的實例化對象

//Object不存在 .__proto__  屬性,
/*
    私有屬性寫在構造函數裏面
    公共屬性寫在原型上
    先有原型,再有實例
 */
function Teacher(n,a,i) {
    this.name = n;
    this.age = a;
    this.id = i;
}
/*
Teacher.prototype.showID=function () {
    alert(this.id);
}
*/
Teacher.prototype = {      //重寫了 prototype屬性,注意保留constructor屬性
    constructor:Teacher,
    showID:function () {
        alert(this.id);
    },
    showName:function () {
        alert(this.name);
    },
    showAge:function () {
        alert(this.age);
    }
}

var afei = new Teacher("阿飛",18,1111);
afei.showID();
/*
	原型鏈繼承
	    構造函數的原型 = 一個函數的實例化對象    實現繼承該函數的原型鏈
 */
function C() {}
C.prototype.x = 10;

function B() {}
B.prototype = new C();       // B的原型指向C

function A() {}
A.prototype = new B();


Object.prototype.x = 40;   //頂層鏈


var a = new A();
console.log(a.x);    //  10         原型鏈查找,就近原則
/*
    獲得一個實例的構造函數
 */
function A() {}

var a = new A();
console.log(a.constructor);    //  A(){}   a沒有constructor,其實是原型 A.prototype.constructor


//注意。原型鏈可能致使不肯定
function B() {}
B.prototype = {};   // 這裏將原型置爲{},上一級原型不存在constructor,
var b = new B();
console.log(b.constructor); // Object() { [native code] }  再向上級找,找到Object原型的構造函數


//全部大括號構建對象都至關於new一個Object對象
// let x={};                   // 原型 = Object.prototype
let x = new Object();

26.5 ES5的繼承

先繼承私有屬性,而後是原型

function A(n,a) {
    this.name = n;
    this.age = a;
}
A.prototype.getName = function () {
    return this.name;
}

//ES5實現繼承(組合繼承)
function B(n,a,i) {
    A.call(this,n,a);    //1.繼承了A的私有屬性
    this.id = i;   //新增的私有屬性
}
//2.再繼承A的原型,這裏只繼承原型,因此使用中間構造函數,若是用new A(),原型會有A的屬性
function Fn(){};
Fn.prototype = A.prototype;
B.prototype = new Fn();         //這裏只傳遞了原型,但原型缺乏構造函數
// 新增原型
B.prototype.constructor = B;   // 補上構造函數
B.prototype.xx=10;             // 新增原型


var afei = new A('阿飛',18);
var xinai = new B('心艾',20,5555);

console.log(afei);
console.log(xinai);

26.6 instanceof實現對象的深拷貝

/*
    instanceof運算符用於測試構造函數的prototype屬性是否出如今對象的原型鏈中的任何位置
                   對象  instanceof 構造函數(通常是頂層構造函數Object,Array,Function)

*/
function deepclone(obj) {
    var o = obj instanceof Array?[]:{};
    for(var key in obj){
        if(typeof obj[key] === 'object'){
            o[key] = deepclone(obj[key]);
        }else{
            o[key] = obj[key];
        }
    }
    return o;
}

var a = {
    a:20,
    b:50,
    k:{             //不支持複雜類型
        aa:1,
        cc:{
            h:2333
        }
    }
}

var b = deepclone(a);      //深拷貝後,引用值類型不會被影響

b.c = 40;
b.k.bb = 2;
b.k.cc.i=120;

console.log(a);
console.log(b);

26.7 JSON的API實現對象拷貝

/*
        JSON只會傳數字和字符串,不能存 函數 等其餘類型
 */
var a = {
    a:20,
    b:50,
    k:{        
        aa:1,
        cc:{
            h:2333
        }
    },
    f:function () {      //JSON  不支持函數類型,因此過濾掉
        console.log(1)
    }
}

console.log(JSON.stringify(a));     //沒有函數 f
var b = JSON.parse(JSON.stringify(a)); //這樣實現的b也和a不同了

b.z=30;
b.k.o=80;
console.log(b);
console.log(a);

26.8 對象案例,選項卡

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="keywords" content="關鍵詞">
        <meta name="description" content="描述">
        <meta name="author" content="Danew">
        <style>
            body{font-family: "Microsoft YaHei",serif;}
            body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
            ol,ul,li{margin:0;padding:0;list-style:none;}
            img{border:none;}
            #wrap,#wrap1{
                position: relative;
                width:300px;
                height:300px;
                border:1px solid pink;
                margin:50px auto;
            }
            #wrap .con,#wrap1 .con{
                position: absolute;
                top:30px;
                left:0;
                width:300px;
                height: 270px;
            }
            #wrap .con  ul,#wrap1 .con  ul{
                width:100%;
                height:100%;
            }
            #wrap .con  li,#wrap1 .con  li{
                display: none;
                position: absolute;
                width:100%;
                height:100%;
            }
            #wrap .con  li.active,#wrap1 .con  li.active{
                display: block;
            }
            #wrap .tab,#wrap1 .tab{
                position: absolute;
                left:0;
                top:0;
                width:100%;
                height:30px;
            }
            #wrap .tab li,#wrap1 .tab li{
                float: left;
                width:99px;
                height:30px;
                border-right:1px solid red;
                background-color: #abcded;
                cursor: pointer;
            }
            #wrap .tab li.active,#wrap1 .tab li.active{
                background-color: pink;
            }
        </style>
    </head>
    <body>
        <div id="wrap">
            <div class="con">
                <ul>
                    <li class="active" style="background-color: red">A內容</li>
                    <li style="background-color: #06aaff">B內容</li>
                    <li style="background-color: #f9a886">C內容</li>
                </ul>
            </div>
            <div class="tab">
                <ul>
                    <li class="active">A</li>
                    <li>B</li>
                    <li>C</li>
                </ul>
            </div>
        </div>
        
        
        <script>
            (function () {
                //對象
                function Tab({conEle,tabEle,conClass='active',tabClass='active'}){
                    this.conEle = conEle;
                    this.tabEle = tabEle;
                    this.conClass = conClass;
                    this.tabClass = tabClass;

                    this.lenth = this.tabEle.length;
                    this.index = 0;

                    this.addClick();
                }
                Tab.prototype = {
                    constructor : Tab,
                    addClick:function () {
                        for(var i=0;i<this.lenth;i++){
                            (function (i) {         //函數做用域造成閉包
                                this.tabEle[i].onclick=function () {
                                    this.change(i);
                                }.bind(this);
                            }).call(this,i);
                        }
                    },
                    change:function (i) {
                        this.conEle[this.index].classList.remove(this.conClass);
                        this.tabEle[this.index].classList.remove(this.tabClass);
                        this.index = i;
                        this.conEle[this.index].classList.add(this.conClass);
                        this.tabEle[this.index].classList.add(this.tabClass);
                    }

                };

                //實例化
                new Tab({
                    conEle:document.querySelectorAll("#wrap .con li"),
                    tabEle:document.querySelectorAll("#wrap .tab li"),
                });
            })();
        </script>
    </body>
</html>

26.9 對象繼承案例,自動輪播選項卡

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="keywords" content="關鍵詞">
        <meta name="description" content="描述">
        <meta name="author" content="Danew">
        <style>
            body{font-family: "Microsoft YaHei",serif;}
            body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
            ol,ul,li{margin:0;padding:0;list-style:none;}
            img{border:none;}
            #wrap2{
                position:relative;
                width:780px;
                height:380px;
                margin:50px auto 0;
                user-select:none;
            }
            #wrap2 .img{
                width:100%;
                height:330px;
            }
            #wrap2 .img ul{
                width:100%;
                height:330px;
            }
            #wrap2 .img ul li{
                position:absolute;
                width:100%;
                height:330px;
                opacity: 0;
                transition: opacity .3s;
            }
            #wrap2 .img ul li.active{
                opacity: 1;
                z-index:2;
            }
            #wrap2 .tab{
                position:absolute;
                left:0;
                bottom:0;
                width:100%;
                height:50px;
            }
            #wrap2 .tab ul{
                width:100%;
                height:50px;
            }
            #wrap2 .tab ul li{
                float:left;
                z-index:4;
                width:20%;
                height:100%;
                background-color: #121112;
                color:#fff;
                text-align:center;
                line-height:50px;
                cursor: pointer;
            }
            #wrap2 .tab ul li.active{
                background-color: #303030;
                color:#e9c06c;
            }
        </style>
    </head>
    <body>
       
        <div id="wrap2">
            <div class="img">
                <ul>
                    <li class="active"><img src="img/1.jpg" alt=""></li>
                    <li><img src="img/2.jpg" alt=""></li>
                    <li><img src="img/3.jpg" alt=""></li>
                    <li><img src="img/4.jpg" alt=""></li>
                    <li><img src="img/5.jpg" alt=""></li>
                </ul>
            </div>
            <div class="tab">
                <ul>
                    <li class="active">開黑嗎?</li>
                    <li>我壓縮賊六</li>
                    <li>只要E的夠快</li>
                    <li>隊友的問號</li>
                    <li>就追不上我</li>
                </ul>
            </div>
        </div>
        
        <script>
            (function () {

                //對象
                function Tab({conEle,tabEle,conClass='active',tabClass='active'}){
                    this.conEle = conEle;
                    this.tabEle = tabEle;
                    this.conClass = conClass;
                    this.tabClass = tabClass;

                    this.lenth = this.tabEle.length;
                    this.index = 0;

                    this.addClick();
                }
                Tab.prototype = {
                    constructor : Tab,
                    addClick:function () {
                        for(var i=0;i<this.lenth;i++){
                            (function (i) {
                                this.tabEle[i].onclick=function () {
                                    this.change(i);
                                }.bind(this);
                            }).call(this,i);
                        }
                    },
                    change:function (i) {
                        if(this.index === i)return;
                        this.conEle[this.index].classList.remove(this.conClass);
                        this.tabEle[this.index].classList.remove(this.tabClass);
                        this.index = i;
                        this.conEle[this.index].classList.add(this.conClass);
                        this.tabEle[this.index].classList.add(this.tabClass);
                    }

                };

                
                function TabAuto({conEle,tabEle,conClass='active',tabClass='active',wrap}) {
                    Tab.call(this,{conEle,tabEle,conClass,tabClass});   //繼承私有屬性
                    this.wrap = wrap;
                    this.timer = null;
                    this.autoplay();
                    this.addTimer();
                }
                function Fn(){}
                Fn.prototype = Tab.prototype;
                TabAuto.prototype = new Fn();              //繼承原型
                TabAuto.prototype.constructor = TabAuto;         
                TabAuto.prototype.autoplay = function () {
                    this.timer = setInterval(function () {
                        var i = this.index;
                        i++;
                        i = i%this.lenth;
                        this.change(i);
                    }.bind(this),2000);
                }
                TabAuto.prototype.addTimer = function () {
                    this.wrap.onmouseenter = function () {
                        clearInterval(this.timer);
                    }.bind(this);
                    this.wrap.onmouseleave = function () {
                        this.autoplay();
                    }.bind(this);
                }

                //實例化
                new TabAuto({
                    conEle:document.querySelectorAll("#wrap2 .img li"),
                    tabEle:document.querySelectorAll("#wrap2 .tab li"),
                    wrap:document.getElementById("wrap2")
                });
            })();
        </script>
    </body>
</html>

26.10 多態

function fn(x) {
    if(x<10){
        return '0'+x;
    }else{
        return ''+x;
    }
}

26.11 ES6面向對象class

/*
        ES5的構造函數和原型是分開的,ES6的類都定義在一個{}內
 */
function A(n,a) {
    this.name = n;
    this.age = a;
}
A.showName = function () {       // 這裏的函數是 構造函數A的屬性,並不屬於原型的函數
    alert(this.name);
}
A.prototype.showName = function(){      //這裏纔是給原型的函數,A的實例化對象能調用的函數
    alert(this.name)
}



/*ES6
    構造函數,也就是私有屬性,寫在constructor裏面
    其餘內容就是原型裏面的內容
    原型裏面加屬性(能夠在外面加,A.prototype.x=10)
    每一個方法結束後,千萬不要寫 , 號
 */
class A{
    constructor(n,a) {
        this.name = n;
        this.age = a;
    }
    showName(){

    }
    x(){
        return 10;
    }
}

//
A.prototype.x=10;

26.12 ES6繼承extends

class A{
    constructor(n,a) {
        this.name = n;
        this.age = a;
    }
    showName(){
        alert(this.name);
    }
    showAge(){
        alert(this.age);
    }
    x(){
        return 10;
    }
}

class B extends A{
    constructor(n,a,id){
        super(n,a);     //必要的super,把父類的私有屬性繼承一下(傳參),相似ES5的 call
        this.id = id;
    }
    x(){
        //return A.prototype.x()+10;       //原型的super表明 A.ptototype
        return super.x()+10;
    }
}

let a = new A('阿飛',18);
let b = new B('朱雀',81,111);

console.log(a);       // {name: "阿飛", age: 18}
console.log(b);       // {name: "朱雀", age: 81, id: 111}
console.log(a.x());   // 10
console.log(b.x());   // 20

26.13 選項卡案例 ES6對象

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="keywords" content="關鍵詞">
        <meta name="description" content="描述">
        <meta name="author" content="Danew">
        <style>
            body{font-family: "Microsoft YaHei",serif;}
            body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
            ol,ul,li{margin:0;padding:0;list-style:none;}
            img{border:none;}
            #wrap2{
                position:relative;
                width:780px;
                height:380px;
                margin:50px auto 0;
                user-select:none;
            }
            #wrap2 .img{
                width:100%;
                height:330px;
            }
            #wrap2 .img ul{
                width:100%;
                height:330px;
            }
            #wrap2 .img ul li{
                position:absolute;
                width:100%;
                height:330px;
                opacity: 0;
                transition: opacity .3s;
            }
            #wrap2 .img ul li.active{
                opacity: 1;
                z-index:2;
            }
            #wrap2 .tab{
                position:absolute;
                left:0;
                bottom:0;
                width:100%;
                height:50px;
            }
            #wrap2 .tab ul{
                width:100%;
                height:50px;
            }
            #wrap2 .tab ul li{
                float:left;
                z-index:4;
                width:20%;
                height:100%;
                background-color: #121112;
                color:#fff;
                text-align:center;
                line-height:50px;
                cursor: pointer;
            }
            #wrap2 .tab ul li.active{
                background-color: #303030;
                color:#e9c06c;
            }
        </style>
    </head>
    <body>
        <div id="wrap2">
            <div class="img">
                <ul>
                    <li class="active"><img src="img/1.jpg" alt=""></li>
                    <li><img src="img/2.jpg" alt=""></li>
                    <li><img src="img/3.jpg" alt=""></li>
                    <li><img src="img/4.jpg" alt=""></li>
                    <li><img src="img/5.jpg" alt=""></li>
                </ul>
            </div>
            <div class="tab">
                <ul>
                    <li class="active">開黑嗎?</li>
                    <li>我壓縮賊六</li>
                    <li>只要E的夠快</li>
                    <li>隊友的問號</li>
                    <li>就追不上我</li>
                </ul>
            </div>
        </div>
        
        <script>
            (function () {

                class Tab{
                    constructor({conEle,tabEle})
                    {
                        this.conEle = conEle;
                        this.tabEle = tabEle;
                        this.index = 0;
                        this.lenth = this.tabEle.length;
                        this.addClick();
                    }
                    addClick(){
                        [...(this.tabEle)].forEach((ele,index)=>{
                            ele.onclick = function() {
                                this.change(index);
                            }.bind(this);
                        })
                    }
                    change(i){
                        if(this.index === i)return;
                        this.conEle[this.index].classList.remove('active');
                        this.tabEle[this.index].classList.remove('active');
                        this.index = i;
                        this.conEle[this.index].classList.add('active');
                        this.tabEle[this.index].classList.add('active');
                    }
                }

                class TabAuto extends Tab{
                    constructor({conEle,tabEle,wrap}){
                        super({conEle,tabEle});        // 繼承父類私有屬性
                        this.wrap = wrap;
                        this.timer = null;
                        this.autoplay();
                        this.addTimer();
                    }
                    autoplay() {
                        this.timer = setInterval(()=>{
                            let i = this.index;
                            i++;
                            i = i%this.lenth;
                            this.change(i);
                        },2000);
                    }
                    addTimer() {
                        this.wrap.onmouseenter = ()=> {
                            clearInterval(this.timer);
                        };
                        this.wrap.onmouseleave = ()=>{
                            this.autoplay();
                        };
                    }
                };

                //實例化
                new TabAuto({
                    conEle:document.querySelectorAll("#wrap2 .img li"),
                    tabEle:document.querySelectorAll("#wrap2 .tab li"),
                    wrap:document.getElementById("wrap2")
                });
            })();
        </script>
    </body>
</html>

27. ES6

27.1 默認值

/*
    函數的小括號,會被當成做用域
 */

let x=5;
function fn(x,y=x) {
    console.log(x,y);
}
fn(1);    // 1 1

27.2 for of只限於遍歷iterator接口

做用是遍歷拿到數組的value值

對象使用for of 遍歷時,先拿到對象的成員, for (let [key,value] of Object.entries(obj))

let arr=[
    '阿飛',
    '風嶼',
    '小浪',
    '海文'
];
console.log(Object.keys(arr),Object.values(arr));  // 一維數組
console.log(Object.entries(arr)); // 二維數組

let obj={
    name:'afei',
    age:18,
    sex:'男',
    marry:true
}

/*
    for of只限於用於 iterator接口

 */
for (let string of arr) {
    console.log(string);          //拿到數組的值value
}

for (let objElement of Object.values(obj)) {
    console.log(objElement);
}

for (let objElement of Object.entries(obj)) {      //打印數組
    console.log(objElement);
}

for (let [key,value] of Object.entries(obj)) {     //結合使用適合遍歷obj的鍵和值
    console.log(key,value);
}

27.3 ...用於對象合併

  • 合併後的對象是新的對象
  • 合併對象時同名屬性被覆蓋
let x={
    aa:1,
    bb:2
};
let y={
    bb:0,
    cc:3,
    dd:4
};

let z = {...x,...y}

x.aa=10;
console.log(x);
console.log(z);

27.4 symbol

Object.getOwnPropertySymbols(obj); 獲取對象內部全部的symbol屬性,返回一個數組

Symbol.for('a')的名字好比a相同,就表明相同的Symbol

//獨一無二的Symbol
console.log(Symbol() === Symbol());    //false

let obj = {name:'阿飛'};
let n=Symbol();        //獨一
obj[n]='朱雀';

n=Symbol();        //n被賦值,只是‘朱雀’取不到了,但仍存在
obj[n]='心艾';
console.log(obj[n]);  //獲取的是 心艾

obj[Symbol.for('name')]='朱雀';    // obj中添加一個屬性  
//  {name: "阿飛", Symbol(): "朱雀", Symbol(): "心艾", Symbol(name): "朱雀"}

 //獲取全部的Symbol
 let symbolArr = Object.getOwnPropertySymbols(obj); // [Symbol(), Symbol(), Symbol(name)]
 console.log(obj[symbolArr[0]]);       //找到朱雀



 //傳值是別名
 console.log(Symbol('a'),Symbol.for('a'));
 //Symbol的名字相同,仍不一樣
 console.log(Symbol('a')===Symbol('a'));     //false
 //Symbol.for的名字相同,就表明相同的Symbol
 console.log(Symbol.for('a') === Symbol.for('a'));      //true

27.5 Set

new Set(data) data必須是能被迭代的數據

實例的add方法,能夠追加數據到對象內

/*
    對象
        特色:沒有重複值
        只接收一個參數,必須能被迭代的數據,字符串,數組,NodeList,argument,Set,Net
 */
let set = new Set([1,2,3]);



let set = new Set("阿飛老師阿飛老師朱雀老師");        //默認去重
set.add('心艾');          //add的內容被 當成一條數據傳入,不被拆開
set.add('心');
console.log(set);         // 心艾 和 心  並不會去重


//去重
let arr=[1,2,4,5,6,1,2,4,2,3];
let s = new Set(arr);
console.log([...s]);

27.6 Map

map.set(key,value); 隊列設置

/*
    Map可使用一個對象當成鍵名
        支持各類數據類型當鍵使用,對象,實例,
 */

let map = new Map();

// let key = 'name';
// let value = '阿飛';

let key = {goudan:'狗蛋'};         //對象當成鍵
let value = 'afei';

map.set(key,value);
console.log(map);
//取值
console.log(map.get(key));

27.7 Object的toString方法

var a={m:'n'};
var b= a.toString();

console.log(b,typeof b,b.length);  //  [object Object] string 15

27.8 Proxy

//Proxy 能夠理解成,在目標對象以前架設一層「攔截」,外界對該對象的訪問,都必須先經過這層攔截,
// 所以提供了一種機制,能夠對外界的訪問進行過濾和改寫。
let o ={
    a:1,
    b:2
}

let obj = new Proxy(o,{
    //攔截對象的獲取
    get(target,key,receive){
        console.log(target);    // {a: 1, b: 2}
        console.log(key);       // a
        console.log(receive);   // Proxy {a: 1, b: 2}
        return target[key];     // 1
    },
    //攔截對象的賦值
    set(target,key,value,receive){
        console.log(target);    //{a: 1, b: 2}
        console.log(key);       //a
        console.log(value);     //123
        console.log(receive);   // Proxy {a: 1, b: 2}
    }
    //...  針對框架開發使用
})

console.log(obj.a);    //觸發get
obj.a = 123;           //觸發set

27.9 Promise

new Promise() 返回一個promise對象

Promise.all([new Promise(),newPromise()]).then().catch() 批量執行,all傳入的是數組包裹的promise對象,都成功走then回調,都失敗,走catch回調,只顯示失敗的

Promise.race([new Promise(),newPromise()]).then().catch() 競爭執行,哪一個實例先改變狀態(不論resolve仍是reject),那麼then和catch就走哪一個實例

//回調地獄->解決異步編程
setTimeout(()=>{
    console.log("123")
},0)
console.log("abc")

//resolve 表示成功      reject表示失敗
let x = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve("200");       //成功,永遠在當前環境的最後執行
        console.log("我先打印,再進入resolve事件")
    },0)
}).then((val)=>{            //then表示成功回調
    console.log("成功回調"+val);
},(err)=>{                   //第二個函數是失敗回調
    console.log("失敗回調"+err);
})


//all  只有數組成員都成功才執行then
let p = Promise.all([
    new Promise((resolve,reject)=>{
        resolve('1');
    }),new Promise((resolve,reject)=>{
        resolve('1');
    }),new Promise((resolve,reject)=>{
        reject('0');
    })
]).then(data=>{
    console.log(data);     //都成功[1,1,0]
}).catch(err=>{
    console.log(err);      //有一個失敗,就走失敗,這裏只顯示失敗的 '0'
})

/*
    Promise.race()  有競爭的意思
    只要`p1`、`p2`、`p3`之中有一個實例率先改變狀態,`p`的狀態就跟着改變。
    那個率先改變的 Promise 實例的返回值,就傳遞給`p`的回調函數。
 */
let p1 = Promise.race([
    new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve('1');
        },100);
    }),new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve('2');
        },101);
    }),new Promise((resolve,reject)=>{
        setTimeout(()=>{
            reject('3');
        },99);
    })
]).then(data=>{
    console.log('resolve '+data);     //只顯示最快的  3,不管是 resolve仍是reject
}).catch(err=>{
    console.log('reject '+err);
})
相關文章
相關標籤/搜索