【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

以上就是今天的内容,终於完赛了,感谢观看!!


<<:  Day15 - BST(Delete Case 1)

>>:  Day 15 - Asynchronous 非同步进化顺序 - Callback 与 Promise

Day07 NAT 类型

NAT 网路位址转换(英语:Network Address Translation,缩写:NAT)是...

[Day04] Vue i18n - Pluralization

在本地化 (localize) 文字讯息时,我们可能会遇到某些语言会有复数型态的状况 (最常见的就是...

[Day 28] 建立注册的画面及功能(十二) - 寄出注册通知信

寄送会员通知信 Laravel基於SwiftMailer函式库开发了一套邮件套件, 可以支援多种服务...

【Day 21】 实作 - 启用 AWS CloudFront 日志

前几天我们已经将 AWS VPC 日志启用并将其资料转换让 BI 工具可以进行视觉化仪表板的建置,那...

DAY 5- 《串流密码1》 - OTP

让我一个字一个字解开你的心。 串流密码(stream cipher)跟区块密码(block ciph...