iT邦幫忙

2021 iThome 鐵人賽

DAY 30
1
自我挑戰組

JavaScript 核心觀念系列 第 30

【Day30】函式常見的陷阱題

今天來講解 this 相關的陷阱題

第一題

myName = '全域';

var person = {
    myName: 'weiwei',
    getName: function(){
        return this.myName;
    }
}

var getName = person.getName;

console.log(getName());

此時的 this 會指向全域,

因為 getName() 這種呼叫方式為簡易呼叫(Simple Call),

而此時的 this 只會跟呼叫方式有關,與定義過程無關

第二題

myName = '全域';

var obj = {
    myName: 'weiwei',
    fn: function(a, b, c){
        return `${this.myName},${a},${b},${c}`;
    }
}

var fnA = obj.fn;
var fnB = fnA.bind(null, 0);
console.log(fnB(1, 2));

此時會顯示 全域,0,1,2,因為在非嚴謹模式下,

bind 所代入的 this 值為 null,則函式中的 this 會指向全域,

而函式中的參數雖然在定義 fnB 時,只有帶入 0

但在 fnB(1, 2) 會將未取得值的參數依序代入值,

所以此時的 bc 分別代入 12 的值,

如果我們要顯示 null,0,1,2 的話,可以將程式碼改成

myName = '全域';

var obj = {
    myName: 'weiwei',
    fn: function(a, b, c){
        'use strict';
        return `${this},${a},${b},${c}`;
    }
}

var fnA = obj.fn;
var fnB = fnA.bind(null, 0);
console.log(fnB(1, 2));

此時只需將函式改為嚴謹模式,並且將函式中的 myName 去掉,

即可取得 null,0,1,2 這個值

第三題

var value = 'global';

var foo = {
    value: 'local',
    bar: function(){
        return this.value;
    }
}

// 直接執行
console.log(foo.bar());
// 賦值
console.log((foo.bar = foo.bar)());
// or
console.log((false || foo.bar)());

我們先看直接執行的部分,

在直接執行時,物件中 bar()this 會指向前面的 foo

因此會回傳 local

接著講解後面兩個部分,

這兩個的概念基本上是一樣的,

foo.bar = foo.barfalse || foo.bar 都是表達式,

因此都會回傳值,而回傳值都是 bar 函式本身

而它的執行方式就跟簡易呼叫一樣,因此此時 this 會指向全域,

所以會回傳 global

第四題

var arr = [1, 2, 3].map(parseInt);

console.log(arr);

這題會回傳 [1, NaN, NaN]

我們先看 map()map()() 內為 callback function,

而所代入的前兩個參數分別為『陣列的值』、『值的索引位置』,

詳細說明可到 MDN 文件 中觀看,

接者我們看 parseInt()parseInt() 中能帶入兩個參數,分別為『待轉成數字的字串』、『進位數字』,

詳細說明可到 MDN 文件 中觀看,

所以這題的 parseInt() 中,所接收到的參數的值是『陣列的值』以及『值的索引位置』,

看完以上說明,可以將這題寫成以下型式

var arr = [1, 2, 3].map(function(item, i){
    return parseInt(item, i)
});

console.log(arr);

而在 parseInt()MDN 文件 中有寫到,當第二個參數為 0 時的情況:

如果 radix 是 undefined 或 0(或留空)的話,JavaScript 會:

  • 如果 string 由 "0x" 或 "0X" 開始,radix 會變成代表十六進位的 16,並解析字串的餘數。
  • 如果 string 由 0 開始,則 radix 會變成代表八進位的 8 或十進位的 10,但到底會變成 8 還是 10 則取決於各實做。ECMAScript 規定用代表十進位的 10,但也不是所有瀏覽器都支持。因此,使用 parseInt 時一定要指定 radix。
  • 如果 string 由其他字串開始,radix 就會是十進位的 10。

如果第一個字串無法被解析為任何數字,parseInt 會回傳 NaN。

這邊直接針對呈現的結果來說明

parseInt(1, 0):因為第二個參數為 0,而以 MDN 文件說明來看,又因為第一個參數為 1,而非 0 或 0x 開頭,因此會是十進位,所以回傳 1

parseInt(2, 1):使用 1 來進位的數字根本不存在,因此回傳 NaN

parseInt(3, 2):這是使用二進位,而在二進位中不會有 3 這個數,因此回傳 NaN

以上就是今天的內容,終於完賽了,感謝觀看!!


上一篇
【Day29】this - DOM
系列文
JavaScript 核心觀念30

尚未有邦友留言

立即登入留言