【JS】函式與參數

函式、立即函式、參數、閉包、this、call、apply、bind、嚴格模式、DOM的this

【JS】函式與參數

函式、立即函式、參數、閉包、this、call、apply、bind、嚴格模式、DOM的this


函式(Function)

  • 是包含{程式碼片段}的物件。

  • 擁有被呼叫、回傳的功能。

  • 函式可細分以下幾種 :

    • 函式陳述式

      • 具名函式。(範例一)
    • 函式表達式

      • 匿名函式。(範例二)

      • 具名函式。(範例三)

具名的函式能夠在函式中被呼叫使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/** 範例一 **/
function fn1(){
  console.log("蘋果");
}
fn1(); //執行

/** 範例二 **/
var fn1 = function(){
  console.log("蘋果");
}
fn1();  //執行

/** 範例三 **/
var fn1 = function fn2(){
  console.log("蘋果");
}
fn1();  //執行
//fn2();不能執行

/** 進階範例一 **/
function fn1(par1){
  par1();
}
fn1(function(){
  console.log("蘋果");
});  //執行

/** 進階範例二 **/
var num = 1;
var fn1 = function fn2(par){
  //1.par=30
  //2.par=60
  //3.par=180
  num += 1;
  //1.num + 1 = 2
  //2.num + 1 = 3
  //3.num + 1 = 4
  return par > 100? par : fn2(num * par);
  //1.30 > 100 = false;
  //1.return (2*30) = 60;回傳到函式
  //2.60 > 100 = false;
  //2.return (3*60) = 180;回傳到函式
  //3.180 > 100 = true;
  //3.return 180;
}
fn2(30);  //執行函式,並帶入30參數
console.log(fn2(30));  //180


立即函式(IIFE)

  • 立刻執行的函式 。(範例一)

  • 可以互相傳參考。(範例二)

  • 可利用 全域環境(window) 傳參考。(範例三)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/** 範例一 **/
(function(){
  console.log("蘋果");  //蘋果
})();

/** 範例二 **/
var obj1 = {};
(function(par1){
  par1.name = "蘋果";
  //{name: "蘋果"}
})(obj1);
//obj1 = {name: "蘋果"}
(function(par2){
  console.log(par2);  //{name: "蘋果"}
})(obj1);

/** 範例三 **/
(function(par1){
  par1.name = "蘋果";
})(window);
//window = {name: "蘋果"}
(function(){
  console.log(name);  //蘋果
})();


參數(Parameter)

  • 是用來接收函式執行帶入的值,可以被賦予新的值。(範例一)

  • 當傳入的值不足時,參數會呈現 undefined 。(範例二)

  • 若傳入的值是物件,則是傳參考。(範例三)

  • 使用 arguments ,可以一次取得所有傳入的值。(範例四)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/** 範例一 **/
function fn1(par1){
  par1 = "香蕉";
  console.log(par1);  //香蕉
}
fn1("蘋果");

/** 範例二 **/
function fn1(par1,par2){
  console.log(par1,par2);  //蘋果,undefined
}
fn1("蘋果");  

/** 範例三 **/
var obj1 = { 
  name:"蘋果" 
};
function fn1(par1){
  par1.name = "香蕉";
  console.log(obj1);  //{name: "香蕉"}
}
fn1(a);
//參數若是傳物件的話,參數指向物件
//所以修改,會一起改變

/** 範例四 **/
function fn1(){
  console.log(arguments);  //["蘋果","香蕉","鳳梨"]
}
fn1("蘋果","香蕉","鳳梨");

/** 進階範例一 **/
function fn1(par1){
  par1("蘋果","香蕉");
}
function fn2(par2,par3){
  console.log(par2,par3);  //蘋果,香蕉
}
fn1(fn2);
//par1 = fn2
//par1的(傳的兩個參數參數)=fn2的(接收兩個參數)

/** 進階範例二 **/
function fn1(){
  for(var i=0 ; i<arguments.length ; i++){
    console.log(arguments);  //蘋果  //香蕉  //鳳梨
  }
}
fn1("蘋果","香蕉","鳳梨");


閉包(Clousure)

  • 在執行函式時才宣告變數,可以減少記憶體。(範例一)

  • 在函式裡執行 重複 動作,又稱 函式工廠 。(延伸範例一)

  • 在函式裡執行 多種 動作,又稱 私有方法 。(延伸範例二)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//* 範例一 **/
function fn1(){
  var a = 5;
  //fn1宣告變數給fn用
  return function fn2(par1){
  //fn1回傳的是fn2的結果
    a = a + par1;
    // fn1宣告的變數a = 5 + 傳進來的值
    return a;
    //最後回傳結果
  }
}
console.log(fn1()(100));  //105
//第一個括弧是fn1,第二個括弧是fn2
var b = fn1();
//宣告b = 回傳的結果
//但因為執行才產生變數
//所以var a;這個變數,是屬於b的
//若再var c = fn1();
//c也會有,屬於自己的var a;
console.log(b(100));  //105
console.log(c(500));  //501

/** 延伸範例一 **/
function fn1(init){
  var a = init || 5;
  //新增一個參數為初始值
  // init有值就用自己,沒有值就用5
  return function fn2(par1){
    a = a + par1;
    return a;
  }
}
console.log(fn1()(100));  //105
//5 + 100
console.log(fn1(20)(100));  //120
//20 + 100

/** 延伸範例二 **/
function fn1(init){
  var a = init || 5;
  return {
    add: function(par1){
      a += par1;
    },
    reduce: function(par2){
      a -= par2;
    },
    watch: function(){
      return a;
    }
  }
}
var b = fn1(100);
b.add(100)
b.reduce(25)
console.log(b.watch());  //175

/** 進階範例一 **/
function fn1(){
  var a =[];
  for(var i=0 ; i<3 ; i++){
    (function(par1){
      a.push(function(){
        consolo.log(par1);  //0  //1  //2
      });
    })(i);
  }
  return a;
}
var b = fn1();
b[0]();
b[1]();
b[2]();


this

  • 是一個關鍵字,當執行函式時自動產生,不需要宣告。

  • 函式在哪執行,決定 this 是什麼。

  • 直接執行的函式,稱為 簡易呼叫(Simple Call) :

    • 函式在物件內執行,this等於物件。(範例一)

    • 函式在全域環境下執行,this等於window。(範例二)

    • 函式在物件內執行非同步事件,this等於window。(範例三)

    • 在立即函式裡的this等於window。(範例四)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/** 範例一 **/
var name = "鳳梨";
var a = {
  name: "蘋果",
  fn1: {
    name: "香蕉",
    fn2: function(){
      console.log(this.b);  //香蕉
    }
  }
}
a.fn1.fn2();
//fn2函式在物件裡,this是fn1

/** 範例二 **/
var name = "鳳梨";
var a = {
  name: "蘋果",
  fn1: {
    name: "香蕉",
    fn2: function(){
      console.log(this);  //鳳梨
    }
  }
}
var b = a.fn1.fn2;
b();
//b=function(){console.log(this)};
//b函式在全域環境下執行,this是window

/** 範例三 **/
var name = "鳳梨";
var a = {
  name: "蘋果",
  fn1: {
    name: "香蕉",
    fn2: function(){
      setTimeout(function(){
        console.log(this.name);  //鳳梨
      },1000);
    }
  }
}
a.fn1.fn2();
//非同步執行的函式,this是window
//可以在父函式中宣告var vm = this;
//最後console.log(vm.name);  //香蕉

/** 範例四 **/
var name = "香蕉";
function fn1(){
  var name = "蘋果";
  console.log(this.name);  //香蕉
}
(function(){
  var fn2 = fn1;
  fn2();
})();


call、apply、bind

  • 改變函式this的方法。

  • 傳入的第一個值,會以 建構式 帶入 this

傳入的值 物件 數字 字串 布林值 undefined、null、null
帶入方式 new Object() new Number() new String() new Boolean() window

  • 傳入的第二個值,會帶入參數。

    • call()將傳入的值帶入參數,直接執行。(範例一)

    • apply()將傳入的值以陣列方式帶入參數,直接執行。(範例二)

    • bind()將傳入的值帶入參數,但還 不會執行 ,要再加()才會執行,若再帶入值,則會依需填補空缺,不會覆蓋。(範例三)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var a = {
  name:"蘋果"
}

/** 範例一 **/
function fn1(par1,par2){
  console.log(this,par1,par2);  //{name: "蘋果"},1,2
}
fn1.call(a,1,2);

/** 範例二 **/
function fn1(par1,par2){
  console.log(this,par1,par2);  //{name: "蘋果"},1,2
}
fn1.apply(a,[1,2]);
//若傳陣列改數字,會undefined

/** 範例三 **/
function fn1(par1,par2){
  console.log(this,par1,par2);  //{name: "蘋果"},1,2 
}
fn1.bind(a,1,2)();
//console.log不會執行


嚴格模式(Strict Mode)

  • 可立即函式,使用"use strict"來執行環境。(範例一)

  • 遇到不會顯示在console.log上的 靜默錯誤 時,會停止運行。(範例二)

  • 使用call、apply、bind方法傳入的值不會改變 。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/** 範例一 **/
(function(){
  "use strict";
  console.log("嚴格模式");  //嚴格模式
})();

/** 範例二 **/
(function(){
  "use strict";
  a = "蘋果";  //錯誤,必須先宣告變數
})();

/** 範例二 **/
function fn1(par1,par2){
  "use strict"
  console.log(this,par1,par2);  
}
fn1.call(a,1,2);  //a,1,2
fn1.call(undefined,1,2);  //undefined,1,2
fn1.("蘋果",1,2);  //undefined,1,2

用call、apply、bind以外的方式傳入值,都是undefined


DOM的this

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/** 範例一 **/
button(onclick="console.dir(this)") 按鈕

/** 進階範例二 **/
// <-----html----->
ul

// <-----js----->
var a = ["蘋果","香蕉","鳳梨"];
var ul = document.querySelector("ul");
//宣告一個空字串
var str = "";
//用for迴圈印出所有陣列在ul裡
for(let i=0 ; i<a.length ; i++){
  str += `<li>${a[i]}</li>`; 
  ul.innerHTML = str;
}
//抓取li
var li = document.querySelectorAll("li");
for(let i=0 ; i<a.length ; i++){
  //綁定(點擊)監聽事件在每一個(i)li上
  li[i].addEventListener("click",function(){
    this.style.backgroundColor = "red";
  });
}

其他相關