iT邦幫忙

2022 iThome 鐵人賽

DAY 7
0
Modern Web

JS 忍者訓練計畫系列 第 7

函示乃基本礎石(下) Day6

  • 分享至 

  • xImage
  •  

根據開發使用到不同的技術,可能會用到 this 或 建構式等更深入的 JS 寫法,函式做為大部分模組化的單位,有更多的細部的功能可以去了解,也可以更深入理解 JS 作為一個函數式程式語言是怎樣的感覺。

這章想學到什麼?

  • 你能想出幾種執行函示的方法? (5)
  • 好玩的 arguments 參數、函示的 .length 屬性、this 是什麼東東?
  • 函式的上下文範圍整理
  • apply 跟 call 能做的事幾乎一模一樣,我們該如何選擇?

程式碼閱讀練習與撰寫

你能想出幾種執行函示的方法?(5)

//作為函示呼叫
foo();

//作為方法呼叫
obj.foo();

//生成器函示呼叫
const genFoo = foo(); genFoo.next().value;

//作為建構式執行呼叫
let handler = new Foo();

//使用 apply 呼叫
foo.apply();

//使用 call 呼叫
foo.call();

好玩的 arguments 參數、函示的 .length 屬性、this 是什麼東東

arguments 參數

arguments 儲存了傳入的參數有哪些,我們可以用他去做更多參數的處理跟判斷。
但另外需要注意的是,它的資料格式不是陣列,是一個類陣列(Array-Likes),具有 length 屬性,但是並沒有 forEach 陣列方法。

延續前面 call 的使用,可以讓沒有 forEach 方法的 arguments 使用 forEach

function foo() {
  return Array.prototype.forEach.call(arguments, (item)=>{
    console.log(item) 
  }) 
}

函示的 .length 屬性

我們宣告一個函式,可以使用 length 去抓到他宣告的參數格是有幾筆。而沒有則為 0。

我們再結合兩個東西之後,可以針對更多參數進行判斷,例如以下

function whatever (you, say) {
    if (arguments.length < 2) {
         console.log(you + ' ' + say);
    } else {
         console.log(Array.prototype.join.call(arguments).replaceAll(",", " "));
    }
}

this 是什麼東東

每當執行函事實,除了呼叫明確提供的實際參數外,暗地裡還有個隱性的形式參數,就叫做 this ,也被傳入函式。這個 this 代表目前與該函式呼叫相關聯的物件,稱之為函式上下文 (function context)。

JavaScript 的 this 形式參數所指向的東西並非根據函示宣告來決定,而是根據「呼叫的形式」來決定。

  • 作為一般函式來呼叫的話,上下文是全域物件(this 指向 window)
function hello () {
    console.log(this)
}
  • 作為一個方法來呼叫的話,上下文是擁有方法的物件 (但方法若是箭頭函式則為上層物件)
const foo = {
    name: 'Peter',
    hello: function(){
        console.log(this)
    }
}
  • 作為建構式來呼叫的話,上下文是新建立的物件
const Foo = function(name, age){
    this.name = name;
    this.age = age;
    this.hello = function(){
        console.log(this)
    }
}
let James = new Foo('James', 32)
let Peter = new Foo('Peter', 18)

James.hello()
VM436:5 Foo {name: 'James', age: 32, hello: ƒ}

Peter.hello()
VM436:5 Foo {name: 'Peter', age: 18, hello: ƒ}

  • 透過 apply() 或 call() 來呼叫的話,上下文可以是任何你想要的東西。

James 也可以變成 Andy

James.hello.call({name: 'Andy'})
VM436:5 {name: 'Andy'}

apply 跟 call 能做的事幾乎一模一樣,我們該如何選擇?

選擇能夠增進程式碼、更清楚易懂的作法。至於實用性答案則是根據參考參數的形式來挑選適當的那一個,若有一堆不相干的變數值、或是以字面值的形式指定,那麼就該使用 call(
),因為可以直接寫進參數理:但若參數值已經放在陣列理了,或是放進陣列裡較為便利,那麼就應該選擇 apply() 。

參考資料

https://daily.dev/blog/why-do-you-need-to-know-about-array-like-objects
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function/call
https://www.w3schools.com/js/js_object_constructors.asp
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor


上一篇
函示乃基本礎石(上) Day5
下一篇
揮舞函式之劍(上) Day7
系列文
JS 忍者訓練計畫30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言