Johnson Mao

Day.18 「從函式物件認識 作用域 與 提升!」 —— JavaScript 函式 & 作用域 & 提升

2021年9月27日

「從函式物件認識 作用域 與 提升!」 —— JavaScript 函式 & 作用域 & 提升

函數也是個物件型別,可以封裝一些功能(程式碼),在需要使用的時候執行功能(程式碼)。

例如我們需要把數字相加,在沒有函式的時候,需要用的時候就要重複打程式碼:

複製成功!
let x = 1;
let y = 1;
let result = x + y;
console.log( result );  // 2
x = 3;
y = 2;
result = x + y;
console.log( result );  // 5

而我們學程式,講求的就是效率,所以自己定義一個函式封裝相加功能:

複製成功!
function sum (x, y) {
  let result = x + y;
  console.log( result );
}
sum(1, 1);  // 2
sum(3, 2);  // 5

#認識函式結構

函式結構

從上面的函式結構我們可以看到

#如何建創與調用函式

上面已經使用了一個建創方法

#函式陳述式

複製成功!
function 函式名 (參數) {
  /* 運作程式碼功能 */
}
函式名 (參數);

#函式表達式,匿名函式

上面有說函式名稱不一定會有,匿名函式就是沒有自己的名稱,而是直接賦值給變數使用,又稱函式表達式

複製成功!
const 變數名 = function (參數) {
  /* 運作程式碼功能 */
}
變數名 (參數);

#new Function

跟物件與陣列一樣,使用 new Function 新增函式。 需注意:

複製成功!
const 變數名 = new Function ("參數", "運作程式碼");

但這個方法並不好用,而且效率低,因為程式碼會先把字串轉成它看得懂的程式碼,才進行運算。

#更多更多的 new

看到這裡你會發現~是不是所有型別都可以 new 出來。 沒錯!其實還可以用 new 來新增字串、數字、布林...等,但因為 new 基礎型別非常不常用,這裡就不多介紹 new 基本型別了。

#返回值(return)

我們會運用功能了,但不想一直使用 console.log 印出來,想要讓函式結果繼續在程式碼裡面運算。 可以利用 return 把運算結果返回並終止函式。

複製成功!
function sum (x, y) {
  const res = x + y;
  return res;  // 使用 result 返回值,並終止函式
  console.log("測試有沒有執行")  // return 後的程式碼不會執行
}
const result = sum(1, 1);  // 返回的值 賦予到 result 變數上
console.log( result );  // 2

#立即執行函式,IIFE(Immediately Invoked Function Expression)

有些時候,我們只想在一開始使用一次函式,後續不會調用函式,就像進入超商會聽到歡迎光臨一樣。 此時不想占用變數空間,就可以使用匿名函式立即執行,需注意:

複製成功!
( function(text) {
  console.log(text)
} )("歡迎光臨")

複製成功!
( function(text) {
  console.log(text)
}("歡迎光臨") )

都可以使用,看個人(團體)習慣

#作用域(Scope)與 提升(Hoisting)

在我們宣告變數那一篇有介紹,全局作用域 與 函數作用域。

#全局作用域

#變數提升

我們先從全局作用域看變數,會發現不管有沒有使用 var 宣告都會取得到值

複製成功!
var a = 1;
x = 2;

console.log("a = "+ a);  // "a = 1"
console.log("x = "+ x);  // "x = 2"

這時候我們把變數往後移,因為 Javascript 是由上向下一行一行執行,會發現有沒有宣告的差別。

複製成功!
console.log("a = "+ a);  // "a = undefined"
console.log("x = "+ x);  // 報錯 x is not defined 

var a = 1;
x = 2;

有先進行 var 聲明宣告的變數,在執行程式碼之前會先提升至全局作用域的開頭,才執行程式碼,相當於:

複製成功!
var a  // var 聲明宣告會自動提升

console.log("a = "+ a);  // "a = undefined"
console.log("x = "+ x);  // 報錯 x is not defined 

a = 1;
x = 2;

#函數提升

一樣的,函數也會在程式執行前,會先自行提升,但函式有兩個新增方法,一個是函式陳述式,一個是函式表達式。 與上面一樣正常使用的話是不會報錯,但如果反過來?

複製成功!
fun()  // "我是一個 fun 函式"
fun2() // 報錯 fun2 is not a function

function fun () {
  console.log("我是一個 fun 函式")
}
var fun2 = function () {
  console.log("我是一個 fun2 函式")
}

我想聰明的你,應該馬上就猜想到,沒錯!就是宣告變數提前,但變數的函式要到後面才會賦值,undefined當函式使用當然會報錯!

而使用函式陳述式,會把整個函式提升,在執行程式碼!

複製成功!
function fun () {    // 函式陳述式把整個函式提升
  console.log("我是一個 fun 函式")
}
var fun2;  // var 自動提升宣告 undefined

fun()  // "我是一個 fun 函式"
fun2() // 報錯 fun2 is not a function

fun2 = function () {  // 到這裡才賦值
  console.log("我是一個 fun2 函式")
}

#函式作用域

#總結

這邊已經先瞭解了基礎的函式,但函式的精隨 this 還沒介紹,介紹函式的同時也瞭解了宣告變數 var 的作用域與提升了~但宣告變數還有 letconst 的特性還沒有介紹!這等到後面要認識函式的精隨的時候,在一起解說~明天將先繼續挖深物件型別,加油!我們快脫離基礎篇了。

#參考資料

回首頁