一、函數補充 1.1 arguments類數組對象 arguments 是一個對應於傳遞給函數的參數的類數組對象。 在函數中,使用特殊對象 arguments,開發者無需明確指出參數名,就能訪問它們。 在其它編程語言中,比如java:如果一個函數被定義過兩次,每次參數個數都不同。相當於定義了兩個不同 ...
一、函數補充
1.1 arguments類數組對象
arguments 是一個對應於傳遞給函數的參數的類數組對象。
在函數中,使用特殊對象 arguments,開發者無需明確指出參數名,就能訪問它們。
在其它編程語言中,比如java:如果一個函數被定義過兩次,每次參數個數都不同。相當於定義了兩個不同的函數,根據參數個數不同,會選擇不同的函數執行。一個函數名定義了兩個函數,稱為“函數重載”(overloaded)。
複習一下函數,定義函數時,參數要羅列在圓括弧中,這些參數,叫“形參”:
function fun(a,b,c){ console.log(a,b,c); } function fun(a,b){ console.log(a,b); } fun(1,2); fun(1,2,3); //合法的,參數多了和少了,都不報錯。
調用函數時,傳的參數叫“實參”,JS不要求形參和實參數量一樣多。
實際上,這種叫做方法的重載。在Java中,同一個函數名,但是參數個數不一樣,視為是兩個函數。
也就是說,Java中能夠定義兩個同名函數。
同名的兩個function,都是fun函數,java允許這樣做,但是js沒有這種操作。
JavaScript函數中有一個非常強大的參數,就是每一個函數內部,都可以使用arguments這個類數組對象。
這個arguments對象,就是涵蓋了所有實參(調用函數時傳入的所有實際參數)
function fun(a,b){ console.log(a,b); //等價於arguments[0]和arguments[1] //此時函數內部,arguments就有下標,依次等於實參的值 console.log(arguments); console.log(arguments[0]); console.log(arguments[1]); console.log(arguments[2]); arguments[5] = 88888; console.log(arguments[8]); console.log(arguments.length); //輸出實參的個數 console.log(arguments.callee); //callee等價於函數本身 console.log(arguments.callee.length); //callee的length是形參的個數 console.log(arguments.callee.name); //函數的名稱 } fun(10,20,30,40,50,88,99,100,999); // console.log(arguments); 由於是函數內部的對象,所以函數外是沒有定義的,報錯。
arguments的功能,可以模擬函數的重載,使用一個函數根據參數的個數不同,有不同的作用。
比如我們設計一個sum函數:
如果傳進來一個參數,就得到當前值+1
如果傳進來兩個參數,就返回兩個數的和
function sum(a,b){ switch(arguments.length){ case 1: return ++a; break; case 2: return a + b; break; } // if(arguments.length == 1){ // return ++a; // }else if(arguments.length == 2){ // return a + b; // return arguments[0] + arguments[1]; // } } console.log(sum(10)); console.log(sum(10,88));
設計一個無限參的函數:累加和
function sum(){ var count = 0; //累加器 for(var i = 0; i < arguments.length;i++){ count += arguments[i]; } return count; } console.log(sum(10,20,30,88,99,100,888,999));
設計一個函數,check如果只有一個參數,那麼就檢測這個數是否是偶數,如果有兩個參數,檢測這兩個參數奇偶性是否相同:
function check(){ switch(arguments.length){ case 1: return arguments[0] % 2 == 0 ? true : false; break; case 2: return (arguments[0] + arguments[1]) % 2 == 0 ? true : false; break; default: // console.log("輸入錯誤,請檢測,只支持1到2個參數!"); throw new Error("輸入錯誤,請檢測,只支持1到2個參數!"); } } console.log(check(8)); console.log(check(8,8)); console.log(check(8,8,8));
1.2 IIFE
IIFE:Immediately-Invoked Function Expression,即時調用函數表達式。
如果一個函數,在定義的時候,就想直接調用它,就是一個IIFE。
函數執行方法:在函數名或變數名後面加()運算符。
函數關鍵字形式:定義時直接在後面加()執行。
function fun(){ console.log("哈哈"); }(); |
不能給函數關鍵字方法直接()調用。
函數表達式形式:能立即執行,函數在賦值給變數時就已經被矮化成表達式了,可以直接在後面加圓括弧執行
var fun = function(){ console.log("哈哈"); }(); |
結論:如果函數能被矮化成表達式,就能在定義時直接調用,就能實現IIFE。
函數矮化為表達式的方法:在函數定義之前加運算符。
數學運算符中:+ - ()符號,其他不能用。
邏輯運算符中:!
其他:~
註意也可以不寫函數名。
+function (){ console.log("哈哈"); }(); -function (){ console.log("哈哈"); }(); !function (){ console.log("哈哈"); }(); ~function (){ console.log("哈哈"); }(); (function (){ console.log("哈哈"); })(); (function (){ console.log("哈哈"); }());
IIFE還可以鍵函數傳參,IIFE能夠關住函數的作用域。在使用某個變數時,如果變數定義在函數內,或函數的參數,只會使用立即調用的變數值,不會對被人造成影響。
(function fun(a){ console.log(a); })(8); fun(5); //IIFE關住fun的作用域,外面找不到fun函數的定義
IIFE可以不寫函數名,寫匿名函數;IIFE關住函數的作用域,可以用於解決函數閉包帶來的錯誤影響。
最標準常用的IIFE格式:所以IIFE裡面的函數,都是匿名函數。
(function fun(a){ console.log(a); })(8); |
1.3結合數組觀察閉包
我們說過,數組中,什麼都可以放,比如String、Number、Boolean、undefined、function等。
通過動態的方法,遍曆數組,給數組每一項添加一個函數:
var arr = []; //空數組接收函數的定義 for(var i = 0;i <= 10;i++){ //函數定義時,作用域全局的,全局中有個變數i //函數值只是定義給數組的每一項,並不會執行 //函數這個閉包,記住了全局作用域,裡面有個i,記住了自己內部的語句 arr[i] = function(){ console.log(i); } } console.log(arr); arr[0](); //調用了數值中的函數,執行了console.log(i) arr[1](); //調用了數值中的函數,執行了console.log(i) ... arr[9](); //調用了數值中的函數,執行了console.log(i) arr[10]();//調用了數值中的函數,執行了console.log(i)
註意:上面的案例並沒有實現想要的結果,我們希望每一項輸出時,i對應的值應該與每次的下標相同,閉包記住僅僅是一個函數的定義,記住內部的語句輸出i。
輸出的都是11,而不是預想的0~10,原因是每個函數定義時,都產生閉包,函數只認識i,而不是把i這個值複製一份記憶住,而是動態的認識這個i。i調用時得幾,這個函數的i就是幾。
所以在調用函數時,i已經變成11,所以數組中每個函數都是11。
想要實現輸出i與下標相同的值,解決方法:
var arr = []; //空數組接收函數的定義 for(var i = 0;i <= 10;i++){ //函數定義時,作用域全局的,全局中有個變數i //函數值只是定義給數組的每一項,並不會執行 //函數這個閉包,記住了全局作用域,裡面有個i,記住了自己內部的語句 // (arr[i] = function(){ // console.log("下標:"+ i); // })(); (function(a){ arr[a] = function(){ console.log("下標:"+ a); } })(i); } // console.log(arr); arr[0](); //調用了數值中的函數,執行了console.log(i) arr[1](); //調用了數值中的函數,執行了console.log(i) ... arr[9](); //調用了數值中的函數,執行了console.log(i) arr[10](); //調用了數值中的函數,執行了console.log(i)
二、DOM
前期課程中,學習的ECMAscript語言核心部分,都是在控制台,天天console.log()、prompt()等。
之前學的屬於語言,瞭解JS這個語言的特性,從今天開始要學習JS控制頁面上的元素。回歸到操作HTML和CSS。
2.1 DOM概述
DOM(Document Object Model,文檔對象模型)描繪了一個層次化的節點樹,允許開發人員添加、移除和修改頁面的某一部分。使用JavaScript操作HTML,不是在操作字元串,而是在操作節點,極大地降低了編程難度。
DOM規範在1998年10月制定,稱為“DOM1級規範”。隨著ECMAScript的升級,DOM也發展出了2級規範、3級規範。另外,早於1998年的DOM也有事實上的標準,我們稱為0級規範。
DOM對很多東西做了抽象,提供了豐富的API:取得元素、css樣式、事件、運動、元素尺寸位置、節點操作。每個知識體系都非常龐大,千絲萬縷。我們今天的課程,把一些線頭都掐出來,日後的課程深入研究每個線頭。
<body> <div id="box"></div> <img src="images/ssh.jpg" id="timg" title="邵老師" > </body> <script type="text/javascript"> //獲取HTML標簽元素 var timg = document.getElementById("timg"); var oBox = document.getElementById("box"); //給圖片添加點擊事件,讓img標簽修改src和title屬性 timg.onclick = function(){ timg.src = "images/timg.jpg"; timg.title = "考拉吃樹葉"; timg.width = "300"; } //點擊盒子變色 oBox.onclick = function(){ oBox.style.backgroundColor = "skyblue"; } </script>
2.2獲取HTML標簽元素
HTML負責頁面的佈局、結構。JS要操作HTML標簽,第一件事就是要得到這個標簽。
說白了就是把HTML標簽拿到JS裡面來操作。
JS中,最基本的得到標簽元素的方法有兩個:
document.getElementById(); //通id獲取一個標簽元素 document.getElementsByTagName(); //通過標簽名獲取一組元素 |
JS通過document對象(表示文檔集合),它表示整個頁面,有很多屬性和方法,包含絕大多數的特征和操作。
學習DOM說白了就是學習document對象
console.log(document.URL); //獲取當前文件路徑 console.log(document.title); //獲取當前頁面標題 document.title = "愛前端官網"; //設置當前頁面標題 |
DOM操作,往往都是從某個HTML元素開始,然後對這個元素進行一些操作,所以得到元素是非常關鍵,得到元素的操作可以使用document對象的方法。
註意:
1、方法名稱都是駝峰命名法,首個單詞字母都是小寫,後面的單詞首字母都是大寫。
2、方法需要通過參數獲取元素,參數就是標簽的id屬性,必須寫在引號內,不需要寫#
3、獲取元素,一定要在HTML元素位置後面,HTML有載入順序,獲取元素時,元素必須已經找到
4、id不能重覆,頁面中如果設置表單元素的name屬性,也不能與id同名,如果重覆,只會選擇第一個出現。
註意代碼書寫位置,現在要用JS得到oBox元素,所以JS代碼就要寫在HTML標簽後面,這樣瀏覽器先渲染HTML節點,然後再執行到JS,否則會報錯找不到元素。
<script type="text/javascript"> //獲取HTML標簽元素 var oBox = document.getElementById("box"); oBox.onclick = function(){ oBox.style.backgroundColor = "skyblue"; } </script> <body> <div id="box"></div> </body> |
如果頁面上沒有匹配id的HTML元素,將返回null,null就是空對象。
通過id獲得的元素數據類型:
console.log(typeof oBox); //object |
獲取的元素是對象數據類型。
IE7及低版本有一個怪癖,表單元素name屬性也會被當做id,為了避免這個問題,所以頁面上的name不要和id同名。
<input type="text" name="oInput" value="預設文本"> var oInput = document.getElementById("oInput"); oInput.value = "被js改了";
IE6、7都會把name當做id。
2.3操作HTML(內容和屬性)
更多的是操作HTML標簽屬性,JS可以操作HTML任何屬性,比如:src、href、title、style等
操作方法:獲取標簽屬性,更改標簽屬性。
2.3.1操作HTML內容
通過innerHTML屬性獲取和修改標簽內容:
var oBox = document.getElementById("box"); console.log(oBox.innerHTML); //獲取div標簽的內容 console.log(oBox.innerText); //獲取div標簽的文本內容 oBox.innerHTML = "通JS修改標簽內容"; //通過=號給oBox對象賦值
2.3.2操作HTML屬性
得到一個元素後,直接打點調用它的屬性名,就能對HTML相應的屬性進行修改。(有什麼就點什麼)
第一種:“點”語法,獲取和更改,都是同元素打點調用。
//獲取img標簽元素 var oImg = document.getElementById("timg"); //獲取標簽屬性的值 console.log(oImg.src); console.log(oImg.alt); console.log(oImg.title); console.log(oImg.id); console.log(oImg.width); //設置標簽屬性的值,和變數賦值一樣 oImg.src = "images/2.jpg"; oImg.alt = "趙麗穎是大圓臉"; oImg.title = "趙麗穎還是吃貨";
class屬性,要換成className,因為class是JS的保留字,不能用。
console.log(oImg.className); //獲取class類名 oImg.className = "abc"; //設置class類名 |
不僅是class屬性要用className這種方式避諱一下,還有以下幾個屬性:
class 要寫成className for 要寫成htmlFor rowspan 寫成rowSpan colspan 寫成colSpan |
第二種:通過以下兩個方法獲取和設置,需要用元素打點調用方法:
getAttribute() 獲取標簽元素的屬性 setAttribute() 設置標簽元素的屬性 |
//獲取標簽屬性的第二種方法: var oImg = document.getElementById("timg"); console.log(oImg.getAttribute('src')); //獲取圖片src屬性的路徑 oImg.setAttribute('src','images/2.jpg'); //設置圖片src屬性的路徑
getAttribute()、setAttribute()和“點”語法的區別。
第一:所有自定義屬性,都不能通過點語法設置
console.log(oImg.data); //undefined自定義屬性,不是w3c的屬性,所以不能打點調用 console.log(oImg.getAttribute('data')); //自定義屬性用getAttribute()方法可以得到 oImg.setAttribute('data','不知道寫什麼');//自定義屬性用setAttribute()方法可以設置 |
第二:所有行內樣式,點語法.style得到一個樣式對象,我們可以通過.style.background繼續得到小樣式,但是getAttribute()得到的是字元串。
console.log(oBox.style.background); console.log(oBox.getAttribute("style")); console.log(typeof oBox.style); //object console.log(typeof oBox.getAttribute("style")); //String
第三:getAttribute()、setAttribute()設置和獲取class等屬性不需要避諱,直接寫屬性名:
console.log(typeof oBox.getAttribute("class")); typeof oBox.setAttribute("class","box"); //String |
點語法效率高於getAttribute()、setAttribute()
所以,如果要獲取自定義屬性或操作對象,會用到,除此之外都用點語法。
2.4操作CSS樣式
通過給元素對象使用“點”語法調用style屬性,得到的是一個所有行內樣式組成的樣式對象。可以繼續去打點調用css樣式的屬性。
通過點語法調用style屬性,調用的和設置的都是行內樣式。
var oBox = document.getElementById("box"); console.log(oBox.style); //獲取當前div的css樣式集合 oBox.style.color = "red"; //設置文字顏色 oBox.style.backgroundColor = "skyblue"; //獲取當前div的css樣式集合 oBox.style.width = "200px"; oBox.style.height = "200px"; oBox.style.lineHeight = "200px"; oBox.style.textAlign = "center"; oBox.style.marginLeft = "100px";
設置時,添加的新樣式都是添加在行內:
獲取CSS屬性:如果單一屬性直接寫點語法調用對應的屬性名,如果是複合屬性,必須用駝峰命名法:
1 font- line- background- padding- margin- border- 等等都要轉為駝峰命名法 |
正確寫法:
1 oBox.style.backgroundColor = "skyblue"; |
錯誤寫法:
1 oBox.style.background-color = "skyblue"; |
三、事件監聽
JavaScript製作交互效果,離不開事件,所謂的事件就是用戶的某個行為,能夠觸發一個函數的執行。
今天只學DOM標準中的0級綁定事件方法。
綁定事件監聽方法:如果給一個元素添加某個事件,事件就有自己要執行的事件函數。
事件的定義:當什麼時候做什麼事情 事件的作用:可以捕獲用戶的行為 |
事件分為三要素:
事件源:就是這個事件的源頭 事件類型:指的是事件什麼時候發生(點擊、觸摸等) 執行指令:匿名函數function(){} |
中文語法解釋:
事件源.事件類型 = function(){ } |
語法:
var oBox = document.getElementById('box'); oBox.onclick = function(){ alert("點擊事件執行"); //這裡的代碼要被點擊才執行,否則永遠不會被觸發 }
DOM0級規範的事件類型:
onclick 滑鼠單擊事件 ondblclick 滑鼠雙擊事件 onmouseover 滑鼠移入事件 onmouseout 滑鼠移出事件 onmouseenter 滑鼠移入事件 onmouseleave 滑鼠移出事件 onmousedown 滑鼠按下不鬆手事件 onmouseup 滑鼠抬起事件 onmousemove 滑鼠移動事件 onfocus 獲取焦點事件 onblur 失去焦點事件 onkeydown 鍵盤按下事件 onkeyup 鍵盤鬆開事件 onchange 當元素的值發生變化時觸發 onresize 視窗或框架被重新調整大小。 onselect 標簽的文本被選中 onload 載入事件(某個對象載入完後,觸發的事件) |
所有事件都要被觸發才執行,否則匿名函數中的代表永遠都不會生效。
onload載入事件:給元素添加一個載入事件時,代碼只要執行到這個位置,立即添加事件監聽,直到瀏覽器的元素載入完後,才觸發onload事件,不需要用戶的行為參與,它是瀏覽器自己的載入事件。
window.onload = function(){ //這裡的代碼是當瀏覽器載入完HTML和CSS才回頭執行代碼 var oBox = document.getElementById("box"); oBox.onclick = function(){ oBox.style.backgroundColor = "skyblue"; } }
window對象的載入事件,觸發條件:所有的HTML和CSS載入完後,才觸發
特殊用途:幫我們實現事件函數內部的語句需要在HTML結構載入完後,才執行JS代碼。
window 表示瀏覽器視窗 onload 表示載入後的事件 |
總結:其實就是整個頁面都載入完後才執行JS代碼,就是執行了一個頁面載入完成後的事件。
ps:儘量讓它越來越規範,前期的文章都是本人的學習時的筆記整理,希望看完後可以指點一二,提提意見多多交流;
筆記流程:html>css>javascript>jquery>html5/css3>移動端>ajax>面向對象>canvas>nodejs>es678>vue>react>小程式>面試問題
意見請留言,郵箱:[email protected]