1. 程式人生 > 實用技巧 >JavaScript學習筆記【DAY3(2020.8.19)週三】

JavaScript學習筆記【DAY3(2020.8.19)週三】

函式:函式就是一個工具,可以將程式碼放在裡面,隨時執行。

就是封裝了一段可被重複呼叫執行的程式碼塊。通過此程式碼塊可以實現大量程式碼的重複使用。

函式的定義

第一種定義方式: 函式宣告

function 函式名() {
要執行的程式碼
}

第二種定義方式: 函式表示式

var 變數 = function() {
要執行的程式碼
}

注: 第二種方式的本質 其實是定義了一個變數,並將這個函式的地址交給該變數。於是,函式名就是這個變數名。

第三種定義方式:new Function()

var f = new Function('a', 'b', 'console.log(a + b)');
f(1, 2);

var fn = new Function('引數1','引數2'..., '函式體')
注意
/*Function 裡面引數都必須是字串格式
第三種方式執行效率低,也不方便書寫,因此較少使用
所有函式都是 Function 的例項(物件)
函式也屬於物件
*/


函式的呼叫

函式宣告定義出來的函式

既可以在函式之前

也可以在函式之後

函式表示式定義的函式

只能夠在後面呼叫

// 呼叫函式
函式名(); // 通過呼叫函式名來執行函式體程式碼

呼叫的時候千萬不要忘記新增小括號

口訣:函式不呼叫,自己不執行

注意:宣告函式本身並不會執行程式碼,只有呼叫函式時才會執行函式體程式碼。

/* 1. 普通函式 */
function fn() {
console.log('人生的巔峰');
}
fn();
/* 2. 物件的方法 */
var o = {
sayHi: function() {
console.log('人生的巔峰');
}
}
o.sayHi();
/* 3.
建構函式*/
function Star() {};
new Star();
/* 4. 繫結事件函式*/
btn.onclick = function() {}; // 點選了按鈕就可以呼叫這個函式
/* 5. 定時器函式*/
setInterval(function() {}, 1000); 這個函式是定時器自動1秒鐘呼叫一次
/* 6. 立即執行函式(自呼叫函式)*/
(function() {
console.log('人生的巔峰');
})();

函式的封裝:函式的封裝是把一個或者多個功能通過函式的方式封裝起來,對外只提供一個簡單的函式介面

簡單理解:封裝類似於將電腦配件整合組裝到機箱中 ( 類似快遞打包)


函式的引數

函式整體由 關鍵字、 函式名、 形參列表、 函式體組成。

形參列表中,可以放置 形式引數 。簡稱: 形參

// 定義一個函式,計算兩個數字的和
function sum(num1, num2) {
// 形參num1 "代表" 將來函式執行的時候,要傳遞的一個引數
// 形參num2 "代表" 將來函式執行的時候,要傳遞的另一個引數
console.log(num1 + num2);
}
// 函式執行了
sum(1, 2); // 輸出3 1和2是實參

當函式執行的時候,可以往圓括號內填寫資料,這種行為,叫做 傳參, 用於函式執行中使用,這樣的引數叫做 實際引數,簡稱 實參

函式的引數關係

當函式定義時,可以定義形參,當函式執行時,可以傳遞實參。 如果函式在執行時,傳遞的引數與形參不一致,分類如下

當形參比實參多: 多餘的形參的值為undefined

function sum(a, b) {
console.log(a);
console.log(b);
}
sum(10); // a是10 b是undefined

當形參比實參少: 沒有形參接收多餘的實參

function sum(a, b) {

console.log(a);

console.log(b);

}

sum(10, 11, 12); // a是10 b是11 12沒有形參來接收

return關鍵字:該關鍵字是用於在函式內部 返回內容 並 中止函式執行 的。

返回值:函式呼叫整體代表的資料;函式執行完成後可以通過return語句將指定資料返回 。

// 中止函式執行

function demo() {

console.log(1);

console.log(2);

console.log(3);

return;

console.log(4);

console.log(5);

}

demo(); // 只會輸出1 2 3 而不會輸出4 5 因為遇見了return

// 返回內容

var a = 10;

var b = 11;

function sum(num1, num2) {

return num1 + num2;

}

// 進行計算

var result = sum(a, b);

// 使用結果

console.log(result); // 21

注: return關鍵字只能夠在函式內部出現

break ,continue ,return 的區別

break :結束當前的迴圈體(如 for、while)

continue :跳出本次迴圈,繼續執行下次迴圈(如 for、while)

return :不僅可以退出迴圈,還能夠返回 return 語句中的值,同時還可以結束當前的函式體內的程式碼

arguments

(1)arguments是函式內部的一個成員,只有在函式執行的時候才會存在。可以使用它來獲取本次函式在執行時,所有傳遞的實參

arguments.length可以獲取實參的個數

function sum() {

console.log(arguments);

}

sum(1); // => [1]

sum(2); // => [2]

sum(1, 2, 3, 4, 5); // => [1, 2, 3, 4, 5]

(2)arguments是一個類陣列物件,也叫做偽陣列物件。可以使用 arguments[idx] 來獲取對應的值。 idx是 從0開始的。 這個idx,也可以叫做 下標 或者 索引

function sum() {

console.log(arguments[2]);

}

sum(1, 2, 3, 4); // => 3

sum(1, 2); // => undefined

函式的定義過程

(1)在記憶體中開闢一個空間;

(2)把程式碼放進去;

(3)把空間的地址交給函式名或者變數名來儲存。

函式的呼叫過程

(1)根據函式名稱找到記憶體空間

(2)將實參的值傳遞給形參

(3)開始解析記憶體空間中的程式碼

(4)執行程式碼

作用域:指的是變數起作用的範圍

作用域的劃分規則: 只有全域性作用域和函式的私有作用域

作用域是根據書寫的單詞和語法來確定的,所以又叫做詞法作用域

所以,通常我們把程式碼寫完,就可以確定每一個作用域的範圍

注: script標籤之間是全域性作用域 多個script標籤共享同一個作用域 但是每一個script標籤中的變數 函式,它們的提升,只能夠在本script標籤的範圍之內

注: 瀏覽器在載入script標籤的程式碼的時候,是一個script標籤載入並執行完畢之後,再去載入執行後面的一個

局作用域:作用於所有程式碼執行的環境(整個 script 標籤內部)或者一個獨立的 js 檔案。

區域性作用域:作用於函式內的程式碼環境,就是區域性作用域。 因為跟函式有關係,所以也稱為函式作用域。

<script>

var a = 10;

</script>

<script>

console.log(a); // 輸出10

</script>

<script>

console.log(a); // ReferenceError: a is not defined

</script>

<script>

var a = 10;

</script>

函式的屬性

name 它是函式的名稱 函式的名稱不論是表示式還是宣告 都是變數的名字

length 它是函式的形參的個數

function demo(a, b, c) {

}

console.log(demo.name); // "demo"

console.log(demo.length); // 3

var fun = function() {

}

console.log(fun.name); // "fun"

console.log(fun.length); // 0


遞迴函式(重要、瞭解)

遞迴函式指的是函式自己在函式體內部呼叫自己

注: 無停止條件的遞迴 就是死迴圈 寫遞迴函式,先寫停止條件return

// a變數一定要定義在函式外部

var a = 0;

function demo() {

a++;

if (a >= 10) {

return;

}

demo();

}

demo(); // 迴圈讓a自加10次 之後就停止

淺複製和深複製:

1.淺拷貝只是拷貝一層,更深層次物件級別的只拷貝引用.

2.深拷貝拷貝多層,每一級別的資料都會拷貝.

3. Object.assign( target, .. sources) es6 新增方法可以淺拷貝


作用域的特點

作用域的機制

作用域是針對變數的生效的範圍。 變數操作又分為使用變數 與 賦值變數

使用變數

出現在表示式中,賦值語句右側。

訪問變數規則

當訪問變數的時候,會先檢視當前作用域中是否存在該變數

如果有,就使用,並終止查詢。

如果沒有,就將會向上一層級作用域中尋找。

依次向上,直到找到,或者到了全域性作用域中還沒有找到,就會報錯。

賦值變數

只出現在賦值語句左側

賦值變數規則

當對一個變數進行賦值的時候,會先檢視當前作用域中是否存在該變數

如果有,就賦值。

如果沒有,就向上一層級查詢。

依次向上,直到找到,或者到了全域性作用域中還沒有找到

就會在全域性作用域中悄悄的宣告這個變數並賦值。

// 當前是全域性作用域
var num = 100; // 在全域性作用域中定義的變數

// 定義一個函式
function demo() {
var num = 101; // 這是在函式作用域中定義的變數
console.log(num);
}
// 執行函式
demo(); // 101

解釋: 當在函式內部訪問變數num的時候,先看當前作用域中是否有num 找到了! 於是就用101 輸出101

var num = 100; // 在全域性作用域中定義的變數
// 定義一個函式
function demo() {
// var num; // 因為宣告提升的原因 程式碼其實是這樣子的
console.log(num);
var num = 101; // 這是在函式作用域中定義的變數 雖然定義是在這裡 但是提升了
}
// 執行函式
demo(); // undefined

解釋: 依舊是作用域的問題,但是因為輸出程式碼在前面,所以有些同學可能會誤以為會輸出100 但是不要忘記變數的查詢規則與預解析!!!

var num = 100; // 在全域性作用域中定義的變數

// 定義一個函式

function demo() {

var num = 101;

}

// 執行函式

demo();

// num是多少

console.log(num); // 100

解釋: 作用域的問題,因為輸出的程式碼是在全域性作用域中的,所以會直接訪問全域性中的變數 而與函式內部的變數無關

var num = 100; // 在全域性作用域中定義的變數

// 定義一個函式

function demo() {

num = 101;

}

console.log(num); // 100

// 執行函式

demo();

// num是多少

console.log(num); // 101


JS的糟粕之一

// 如果一個變數沒有通過var宣告 就直接賦值

num = 101; // 這種不經過宣告就直接賦值而且還不會報錯的特點屬於JS的糟粕之一。一定不要使用。

console.log(num); // 101

console.log(num);

num = 101;

這種情況下會報錯 因為num沒有經過定義就被使用

JavaScript 程式碼是由瀏覽器中的 JavaScript 解析器來執行的。JavaScript 解析器在執行 JavaScript 程式碼的時候分為兩步:預解析程式碼執行

預解析: 在當前作用域下, JS 程式碼執行之前,瀏覽器會預設把帶有 var 和 function 宣告的變數在記憶體中進行提前宣告或者定義。

JS引擎執行程式碼的階段:

通讀程式碼

在通讀程式碼階段,引擎會先檢視是否有語法錯誤,如果有,就報錯。如果沒有,則在這個過程中,就會將程式碼中所有的通過var宣告的變數和通過function宣告的函式提升到程式碼的最前面。這個提升行為,就是發生在預解析階段。

執行程式碼: 從上到下執行JS語句。

變數提升(變數預解析) 變數的宣告會被提升到當前作用域的最上面,變數的賦值不會提升。

函式提升(函式預解析) 函式的宣告會被提升到當前作用域的最上面,但是不會呼叫函式。