Web前端學習筆記——JavaScript之陣列、函式、作用域
陣列
為什麼要學習陣列
之前學習的資料型別,只能儲存一個值(比如:Number/String。我們想儲存班級中所有學生的姓名,此時該如何儲存?
陣列的概念
所謂陣列,就是將多個元素(通常是同一型別)按一定順序排列放到一個集合中,那麼這個集合我們就稱之為陣列。
陣列的定義
陣列是一個有序的列表,可以在陣列中存放任意的資料,並且陣列的長度可以動態的調整。
通過陣列字面量建立陣列
// 建立一個空陣列
var arr1 = [];
// 建立一個包含3個數值的陣列,多個數組項以逗號隔開
var arr2 = [1, 3, 4];
// 建立一個包含2個字串的陣列
var arr3 = ['a', 'c' ];
// 可以通過陣列的length屬性獲取陣列的長度
console.log(arr3.length);
// 可以設定length屬性改變陣列中元素的個數
arr3.length = 0;
獲取陣列元素
陣列的取值
// 格式:陣列名[下標] 下標又稱索引
// 功能:獲取陣列對應下標的那個值,如果下標不存在,則返回undefined。
var arr = ['red',, 'green', 'blue'];
arr[0]; // red
arr[2]; // blue
arr[3]; // 這個陣列的最大下標為2,因此返回undefined
遍歷陣列
遍歷:遍及所有,對陣列的每一個元素都訪問一次就叫遍歷。
陣列遍歷的基本語法:
for(var i = 0; i < arr.length; i++) {
// 陣列遍歷的固定結構
}
陣列中新增元素
陣列的賦值
// 格式:陣列名[下標/索引] = 值;
// 如果下標有對應的值,會把原來的值覆蓋,如果下標不存在,會給陣列新增一個元素。
var arr = ["red", "green", "blue"];
// 把red替換成了yellow
arr[0] = "yellow";
// 給陣列新增加了一個pink的值
arr[3] = "pink";
氣泡排序,從小到大
<!DOCTYPE html>
<html lang="en">
< head>
<meta charset="UTF-8">
<title>$永遠的24k純帥$</title>
<script>
//氣泡排序:把所有的資料按照一定的順序進行排列(從小到大,從大到下)
var arr = [10, 0, 100, 20, 60, 30];
//迴圈控制比較的輪數
for (var i = 0; i < arr.length - 1; i++) {
//控制每一輪的比較的次數
for (var j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] < arr[j + 1]) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
console.log(arr);
</script>
</head>
<body>
</body>
</html>
函式
為什麼要有函式
如果要在多個地方求1-100之間所有數的和,應該怎麼做?
什麼是函式
把一段相對獨立的具有特定功能的程式碼塊封裝起來,形成一個獨立實體,就是函式,起個名字(函式名),在後續開發中可以反覆呼叫
函式的作用就是封裝一段程式碼,將來可以重複使用
函式的定義
- 函式宣告
function 函式名(){
// 函式體
}
- 函式表示式
var fn = function() {
// 函式體
}
-
特點:
函式宣告的時候,函式體並不會執行,只要當函式被呼叫的時候才會執行。 函式一般都用來幹一件事情,需用使用動詞+名詞,表示做一件事情
tellStory
sayHello
等
函式的呼叫
- 呼叫函式的語法:
函式名();
-
特點:
函式體只有在呼叫的時候才會執行,呼叫需要()進行呼叫。 可以呼叫多次(重複使用)
程式碼示例:
// 宣告函式
function sayHi() {
console.log("吃了沒?");
}
// 呼叫函式
sayHi();
// 求1-100之間所有數的和
function getSum() {
var sum = 0;
for (var i = 0; i < 100; i++) {
sum += i;
}
console.log(sum);
}
// 呼叫
getSum();
函式的引數
- 為什麼要有引數
function getSum() {
var sum = 0;
for (var i = 1; i <= 100; i++) {
sum += i;
}
console.log();
}
// 雖然上面程式碼可以重複呼叫,但是隻能計算1-100之間的值
// 如果想要計算n-m之間所有數的和,應該怎麼辦呢?
- 語法:
// 函式內部是一個封閉的環境,可以通過引數的方式,把外部的值傳遞給函式內部
// 帶引數的函式宣告
function 函式名(形參1, 形參2, 形參...){
// 函式體
}
// 帶引數的函式呼叫
函式名(實參1, 實參2, 實參3);
-
形參和實參
- 形式引數:在宣告一個函式的時候,為了函式的功能更加靈活,有些值是固定不了的,對於這些固定不了的值。我們可以給函式設定引數。這個引數沒有具體的值,僅僅起到一個佔位置的作用,我們通常稱之為形式引數,也叫形參。
- 實際引數:如果函式在宣告時,設定了形參,那麼在函式呼叫的時候就需要傳入對應的引數,我們把傳入的引數叫做實際引數,也叫實參。
var x = 5, y = 6;
fn(x,y);
function fn(a, b) {
console.log(a + b);
}
//x,y實參,有具體的值。函式執行的時候會把x,y複製一份給函式內部的a和b,函式內部的值是複製的新值,無法修改外部的x,y
函式的返回值
當函式執行完的時候,並不是所有時候都要把結果列印。我們期望函式給我一些反饋(比如計算的結果返回進行後續的運算),這個時候可以讓函式返回一些東西。也就是返回值。函式通過return返回一個返回值
返回值語法:
//宣告一個帶返回值的函式
function 函式名(形參1, 形參2, 形參...){
//函式體
return 返回值;
}
//可以通過變數來接收這個返回值
var 變數 = 函式名(實參1, 實參2, 實參3);
函式的呼叫結果就是返回值,因此我們可以直接對函式呼叫結果進行操作。
返回值詳解: 如果函式沒有顯示的使用 return語句 ,那麼函式有預設的返回值:undefined 如果函式使用 return語句,那麼跟再return後面的值,就成了函式的返回值 如果函式使用 return語句,但是return後面沒有任何值,那麼函式的返回值也是:undefined 函式使用return語句後,這個函式會在執行完 return 語句之後停止並立即退出,也就是說return後面的所有其他程式碼都不會再執行。
推薦的做法是要麼讓函式始終都返回一個值,要麼永遠都不要返回值。
arguments的使用
JavaScript中,arguments物件是比較特別的一個物件,實際上是當前函式的一個內建屬性。也就是說所有函式都內建了一個arguments物件,arguments物件中儲存了傳遞的所有的實參。arguments是一個偽陣列,因此及可以進行遍歷
案例
求斐波那契數列Fibonacci中的第n個數是多少? 1 1 2 3 5 8 13 21…
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>$永遠的24k純帥$</title>
<script>
//求斐波那契數列,12---144
//1 1 2 3 5 8 13 21 34 55 89 144
function getFib(num) {
var num1=1;
var num2=1;
var sum=0;
for(var i=3;i<=num;i++){
sum=num1+num2;
num1=num2;
num2=sum;
}
return sum;
}
console.log(getFib(12));
</script>
</head>
<body>
</body>
</html>
輸入某年某月某日,判斷這一天是這一年的第幾天?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>$永遠的24k純帥$</title>
<script>
//輸入,年月日,獲取這個日期是這一年的第多少天
//判斷這個年份是不是閏年
function isLeapYear(year) {
return year%4==0&&year%100!=0||year%400==0;
}
//年---月---日:2017年4月28日
function getDays(year, month, day) {
//定義變數儲存對應的天數
var days = day;
//如果使用者輸入的是一月份,沒必要向後算天數,直接返回天數
if (month == 1) {
return days;
}
//程式碼執行到這裡-----說明使用者輸入的不是1月份
//使用者輸入的是7月份23日----1,2,3 +23
//定義一個數組,儲存每個月份的天數
var months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
//小於的是輸入的月份-1
for (var i = 0; i < month - 1; i++) {
days += months[i];
}
//需要判斷這個年份是不是閏年
if(isLeapYear(year)&&month>2){
days++;
}
return days;
}
console.log(getDays(2000,3,2));
//函式裡面可以呼叫其他的函式
// function f1() {
// console.log("我是一個函式");
// f2();//函式的呼叫
// }
// function f2() {
// console.log("我也是一個函式");
// }
//
// f1();
</script>
</head>
<body>
</body>
</html>
函式其它
匿名函式
匿名函式:沒有名字的函式
匿名函式如何使用:
將匿名函式賦值給一個變數,這樣就可以通過變數進行呼叫
匿名函式自呼叫
關於自執行函式(匿名函式自呼叫)的作用:防止全域性變數汙染。
自呼叫函式
匿名函式不能通過直接呼叫來執行,因此可以通過匿名函式的自呼叫的方式來執行
(function () {
alert(123);
})();
函式是一種資料型別
function fn() {}
console.log(typeof fn);
- 函式作為引數
因為函式也是一種型別,可以把函式作為兩一個函式的引數,在兩一個函式中呼叫
- 函式做為返回值
因為函式是一種型別,所以可以把函式可以作為返回值從函式內部返回,這種用法在後面很常見。
function fn(b) {
var a = 10;
return function () {
alert(a+b);
}
}
fn(15)();
程式碼規範
1.命名規範
2.變數規範
var name = 'zs';
3.註釋規範
// 這裡是註釋
4.空格規範
5.換行規範
var arr = [1, 2, 3, 4];
if (a > b) {
}
for(var i = 0; i < 10; i++) {
}
function fn() {
}
作用域
作用域:變數可以起作用的範圍
全域性變數和區域性變數
-
全域性變數
在任何地方都可以訪問到的變數就是全域性變數,對應全域性作用域
-
區域性變數
只在固定的程式碼片段內可訪問到的變數,最常見的例如函式內部。對應區域性作用域(函式作用域)
不使用var宣告的變數是全域性變數,不推薦使用。
變數退出作用域之後會銷燬,全域性變數關閉網頁或瀏覽器才會銷燬
塊級作用域
任何一對花括號({和})中的語句集都屬於一個塊,在這之中定義的所有變數在程式碼塊外都是不可見的,我們稱之為塊級作用域。 在es5之前沒有塊級作用域的的概念,只有函式作用域,現階段可以認為JavaScript沒有塊級作用域
詞法作用域
變數的作用域是在定義時決定而不是執行時決定,也就是說詞法作用域取決於原始碼,通過靜態分析就能確定,因此詞法作用域也叫做靜態作用域。
在 js 中詞法作用域規則:
- 函式允許訪問函式外的資料.
- 整個程式碼結構中只有函式可以限定作用域.
- 作用域規則首先使用提升規則分析
- 如果當前作用規則中有名字了, 就不考慮外面的名字
var num = 123;
function foo() {
console.log( num );
}
foo();
if ( false ) {
var num = 123;
}
console.log( num ); // undefiend
作用域鏈
只有函式可以製造作用域結構, 那麼只要是程式碼,就至少有一個作用域, 即全域性作用域。凡是程式碼中有函式,那麼這個函式就構成另一個作用域。如果函式中還有函式,那麼在這個作用域中就又可以誕生一個作用域。
將這樣的所有的作用域列出來,可以有一個結構: 函式內指向函式外的鏈式結構。就稱作作用域鏈。
// 案例1:
function f1() {
function f2() {
}
}
var num = 456;
function f3() {
function f4() {
}
}
// 案例2
function f1() {
var num = 123;
function f2() {
console.log( num );
}
f2();
}
var num = 456;
f1();
預解析
JavaScript程式碼的執行是由瀏覽器中的JavaScript解析器來執行的。JavaScript解析器執行JavaScript程式碼的時候,分為兩個過程:預解析過程和程式碼執行過程
預解析過程:
- 把變數的宣告提升到當前作用域的最前面,只會提升宣告,不會提升賦值。
- 把函式的宣告提升到當前作用域的最前面,只會提升宣告,不會提升呼叫。
- 先提升var,在提升function
JavaScript的執行過程
var a = 25;
function abc (){
alert(a);//undefined
var a = 10;
}
abc();
// 如果變數和函式同名的話,函式優先
console.log(a);
function a() {
console.log('aaaaa');
}
var a = 1;
console.log(a);
全域性解析規則
函式內部解析規則
變數提升
-
變數提升
定義變數的時候,變數的宣告會被提升到作用域的最上面,變數的賦值不會提升。
-
函式提升
JavaScript解析器首先會把當前作用域的函式宣告提前到整個作用域的最前面
// 1、-----------------------------------
var num = 10;
fun();
function fun() {
console.log(num);
var num = 20;
}
//2、-----------------------------------
var a = 18;
f1();
function f1() {
var b = 9;
console.log(a);
console.log(b);
var a = '123';
}
// 3、-----------------------------------
f1();
console.log(c);
console.log(b);
console.log(a);
function f1() {
var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}