(Day17) this 介绍下 - 绑定 this 的 call & apply & bind 与严格模式

前言

上篇大致讲解了 this 在不同状况的指向,这篇会来讲讲使用 call/apply/bind 来绑定 this, 以及在严格模式下 this 指向会有所不同。

绑定 this 的 call/apply/bind

当我们遇上某些需求,要求 XX 函式中的 this 是某个特定物件,这时便会使用 call()apply()bind() 来调整特性函式中的 this

这三个方法和 filter()forEach() 一样是藉由原型提供的,因此这三个方法,不需要任何设定便可使用,这边先来看看范例

var name = 'Ryder'
function showName() {
  console.log(this.name) 
}
showName()

这是上一篇文章中 this 指向 window 的一个范例,这边试者使用 call() 方法,并且将一个新增的物件当作参数传入,如:

var name = 'Ryder'
var obj = {
	name : 'Jack'
}
function showName(item1,item2,item3) {
  console.log(this.name,item1,item2,item3) // Jack, test, {}, [0,1,2]
}
showName.call(obj,'test', {}, [0,1,2])

结果 showName 中的 this 会变成指向 obj 要注意的是使用 showName.call(obj) 他会立刻就回传,这是因为 call() 这个方法是使用後,会立刻执行函式,并且修正函式中的 this ,顺带一题在 call() 第一个参数是用来绑定函式中 this 的,第一个参数後面的参数,则都是传递给原本函示的参数。

apply()call() 差异则是刚刚提到的 第一个参数後面的参数部分, 其他地方完全一致,call() 第一个参数後面的参数,是接受任何型别的参数 ,而 apply() 则只能使用第二个参数,并且只能接受阵列写法的参数,如果是阵列以外的都会跳错。

var name = 'Ryder'
var obj = {
	name : 'Jack'
}
function showName(item1,item2,item3){
  console.log(this.name,item1,item2,item3)
}
showName.apply(obj,['test',{}, [0,1,2] ]) // Jack, test, {}, [0,1,2] 
showName.apply(obj,'test', {}, [0,1,2]) // 跳错

bind() 算是比较常用的,和 call()apply() 不同,使用後函示并不会立刻执行,而是会回传要替换 this 的函式,因此我们会需要再使用 () 呼叫替换後的函式,而参数部分则和 call() 接受任何形式的参数。

var name = 'Ryder'
var obj = {
	name : 'Jack'
}
function showName(item1,item2,item3){
  console.log(this.name,item1,item2,item3)
}
var test = showName.bind(obj) 
test('test', {}, [0,1,2])

关於 call()apply() 、 bind() 还有一点要提的是,使用第一个参数绑定 this 时,若如果我们传入的是纯值,那麽被替换的 tihs 会是以建构式的方式建立。

function Fn1(){
   console.log(this) //String {'test'}
}
Fn1.bind('test')()

而传入 undefined 他则会替换成 window

function Fn1(){
   console.log(this) // Window
}
Fn1.call(undefined)

关於这一点 MDN 也有解释:

注意,它可能是一个无法在函数内看到的值:若这个函数是在非严苛模式( non-strict mode ), null 、undefined 将会被置换成全域变数,而原生型态的值将会被封装

严格模式

由於 JavaScript 这个语言特性,算是相对宽松,因此 ES5 新增 严格模式,用来规范 JavaScript 写法,并对程序码做一些限制。

若要使用严格模式会需要再该执行环境添加 'use strict' 的字串,如果我们直接在全域使用 'use strict' 基本上就是全部的程序码都会变为严格模式。

而我们本次介绍的 this 在严格模式下,部分的指向也会有所变动,那麽严格模式下 this 有甚麽更动?

主要有三点:

  • 简易呼叫 this 原本指向 window ,严格模式下一律都会被转为 undefined
  • 使用 call()apply()bind()this 值做绑定时,若绑定的是纯值, this 的值会是建构式,严格模式下则会是纯值本身。
  • 同上透过 call()apply()bind()this 值做绑定时,绑定的是 undefinedNullthis 会是 window,严格模式下则会是传入的 undefinedNull

简易呼叫的范例:

var name = 'Ryder'
var array = [1,2,3]
function Fn() {
	'use strict'
  console.log(this) // undefined 
}
Fn()

array.forEach(function(){
	'use strict'
	console.log(this) //undefined *3
})

this 绑定 undefined 、与纯值的范例

function Fn1(){
	'use strict'
   console.log(this) // undefined
}
Fn1.call(undefined)

function Fn2(){
	'use strict'
   console.log(this) // 'test'
}
Fn2.call('test')

参考文献


<<:  Day17 Laravel - artisan

>>:  [Day 17] IOCP 实作

Day 12 漏洞分析 - Vulnerability Analysis (legion)

今天要介绍的是legion,根据官方介绍,它是斯巴达的叉子 Legion, a fork of SE...

[Day 24] Android Studio 七日陨石开发:安装与创建第一个专案 (下)

前言 昨天我们安装好Android Studio, 并且建立了一个专案叫做AIFER。 现在我们尝试...

【20】从头自己建一个 keras 内建模型 (以 MobileNetV2 为例)

Colab连结 虽然 Tensorflow 提供了几个预训练模型让我们可以很快的完成训练任务,但是有...

我们的基因体时代-AI, Data和生物资讯 Day09-合成生物学与机器学习

上一篇我们的基因体时代-AI, Data和生物资讯 Day08-合成生物学与机器学习分享合成生物学领...

stack heap内存、预编译、作用域链 - 概念介绍

预编译发生在何时? 执行全域前一刻,做全域的预编译;执行function前一刻,做function的...