欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript關(guān)鍵字this的使用方法詳解

 更新時(shí)間:2023年08月25日 08:40:27   作者:IanLew  
與其他語(yǔ)言相比,函數(shù)的 this 關(guān)鍵字在 JavaScript 中的表現(xiàn)略有不同,此外,在嚴(yán)格模式和非嚴(yán)格模式之間也會(huì)有一些差別,本文就給大家講解一下JavaScript關(guān)鍵字中的this,需要的朋友可以參考下

在絕大多數(shù)情況下,函數(shù)的調(diào)用方式?jīng)Q定了 this 的值(運(yùn)行時(shí)綁定)。this 不能在執(zhí)行期間被賦值,并且在每次函數(shù)被調(diào)用時(shí) this 的值也可能會(huì)不同。ES5 引入了 bind 方法來(lái)設(shè)置函數(shù)的 this 值,而不用考慮函數(shù)如何被調(diào)用的。ES2015 引入了箭頭函數(shù),箭頭函數(shù)不提供自身的 this 綁定(this 的值將保持為閉合詞法上下文的值)。

涵義

當(dāng)前執(zhí)行上下文(global、function 或 eval)的一個(gè)屬性,在非嚴(yán)格模式下,總是指向一個(gè)對(duì)象,在嚴(yán)格模式下可以是任意值。

this 可以用在構(gòu)造函數(shù)之中,表示實(shí)例對(duì)象。除此之外,this 還可以用在別的場(chǎng)合。但不管是什么場(chǎng)合,this 都有一個(gè)共同點(diǎn):它總是返回一個(gè)對(duì)象。簡(jiǎn)單說(shuō),this 就是屬性或方法“當(dāng)前”所在的對(duì)象。

const p = {
  name: 'jay',
  describe() {
    console.log(`${this.name} is a good man`)
  }
}
p.describe()  // jay is a good man

上面代碼中,this.name 表示 name 屬性所在的那個(gè)對(duì)象。由于 this.name 是在 describe 方法中調(diào)用,而 describe 方法所在的當(dāng)前對(duì)象是 p,因此 this 指向 p,this.name 就是 p.name

由于對(duì)象的屬性可以賦給另一個(gè)對(duì)象,所以屬性所在的當(dāng)前對(duì)象是可變的,即 this 的指向是可變的。

const n = {
  name: 'jj'
}
n.describe = p.describe
n.describe()  // jj is a good man

上面代碼中,p.describe 屬性被賦給 n,于是 n.describe 就表示 describe 方法所在的當(dāng)前對(duì)象是 n,所以this.name 就指向 n.name。

關(guān)于 this 的指向改變的理解可以參考之前編譯執(zhí)行的相關(guān)文章,這里不做贅述。稍稍重構(gòu)這個(gè)例子,this 的動(dòng)態(tài)指向就能看得更清楚。

function describe () {
  console.log(`${this.name} is a good man`)
}
const p = {
  name: 'jay',
  describe
}
const n = {
  name: 'jj',
  describe
}
p.describe()  // jay is a good man
n.describe()  // jj is a good man

只要函數(shù)被賦給另一個(gè)變量,this 的指向就會(huì)變。

const p = {
  name: 'jay',
  describe: function () {
    console.log(`${this.name} is a good man`)
  }
}
const name = 'jj'
const f = p.describe
f()  // jj is a good man

上面代碼中,p.describe 被賦值給變量 f,內(nèi)部的 this 就會(huì)指向 f 運(yùn)行時(shí)所在的對(duì)象(本例是頂層對(duì)象)。

實(shí)質(zhì)

JavaScript 語(yǔ)言之中,一切皆對(duì)象,運(yùn)行環(huán)境也是對(duì)象,所以函數(shù)都是在某個(gè)對(duì)象之中運(yùn)行,this 就是函數(shù)運(yùn)行時(shí)所在的對(duì)象(環(huán)境)。JavaScript 支持運(yùn)行環(huán)境動(dòng)態(tài)切換,也就是說(shuō),this 的指向是動(dòng)態(tài)的,沒(méi)有辦法事先確定到底指向哪個(gè)對(duì)象。

const o = { n: 1 }

JavaScript 引擎會(huì)先在內(nèi)存里面,生成一個(gè)對(duì)象 { n: 1 },然后把這個(gè)對(duì)象的內(nèi)存地址賦值給變量 o。也就是說(shuō),變量 o 是一個(gè)地址引用(reference)。后面如果要讀取 o.n,引擎先從 o 拿到內(nèi)存地址,然后再?gòu)脑摰刂纷x出原始的對(duì)象,返回它的n 屬性。原始的對(duì)象以字典結(jié)構(gòu)保存,每一個(gè)屬性名都對(duì)應(yīng)一個(gè)屬性描述對(duì)象。

{
  n: {
    [[value]]: 1
    [[writable]]: true
    [[enumerable]]: true
    [[configurable]]: true
  }
}

屬性的值可能是一個(gè)函數(shù)。

const o = { n: function () {} }

這時(shí),引擎會(huì)將函數(shù)單獨(dú)保存在內(nèi)存中,然后再將函數(shù)的地址賦值給n 屬性的 value 屬性。

{
  n: {
    [[value]]: 函數(shù)的地址
    ...
  }
}

由于函數(shù)是一個(gè)單獨(dú)的值,所以它可以在不同的環(huán)境(上下文)執(zhí)行。

const f = function () {}
const o = { f }
f()  // 在全局對(duì)象執(zhí)行
obj.f()  // 在 obj 對(duì)象里面執(zhí)行

由于函數(shù)可以在不同的運(yùn)行環(huán)境執(zhí)行,所以需要有一種機(jī)制,能夠在函數(shù)體內(nèi)部獲得當(dāng)前的運(yùn)行環(huán)境(context)。所以,this 就出現(xiàn)了,它的設(shè)計(jì)目的就是在函數(shù)體內(nèi)部,指代函數(shù)當(dāng)前的運(yùn)行環(huán)境。

使用場(chǎng)合

this 主要有以下幾個(gè)使用場(chǎng)合。

全局上下文

無(wú)論是否在嚴(yán)格模式下,在全局執(zhí)行環(huán)境中(在任何函數(shù)體外部)this 都指向全局對(duì)象。在瀏覽器環(huán)境下,它指的就是頂層對(duì)象 window??梢允褂?globalThis 獲取全局對(duì)象,無(wú)論你的代碼是否在當(dāng)前上下文運(yùn)行。

console.log(this === window)  // true

函數(shù)上下文

在函數(shù)內(nèi)部,this 的值取決于函數(shù)被調(diào)用的方式。

function f () {
  return this
}
// 在瀏覽器中,全局對(duì)象是 window
console.log(f() === window)  // true
//在 Node 中
console.log(f() === globalThis)  // true

然而,在嚴(yán)格模式下,如果進(jìn)入執(zhí)行環(huán)境時(shí)沒(méi)有設(shè)置 this 的值,this 會(huì)保持為 undefined

function f () {
  "use strict"
  return this
}
console.log(f() === undefined)  // true

箭頭函數(shù)

在箭頭函數(shù)中,this 與封閉詞法環(huán)境的 this 保持一致。在全局代碼中,它將被設(shè)置為全局對(duì)象。

const f = () => this
console.log(f() === this)  // true

構(gòu)造函數(shù)

當(dāng)一個(gè)函數(shù)用作構(gòu)造函數(shù)時(shí)(使用new關(guān)鍵字),它的 this 被綁定到正在構(gòu)造的新對(duì)象。

function C() {
  this.a = 37
}
const o = new C()
console.log(o.a)  // 37

DOM 事件處理函數(shù)

當(dāng)函數(shù)被用作事件處理函數(shù)時(shí),它的 this 指向觸發(fā)事件的元素(一些瀏覽器在使用非 addEventListener 的函數(shù)動(dòng)態(tài)地添加監(jiān)聽(tīng)函數(shù)時(shí)不遵守這個(gè)約定)。

function bluify (e) {
  console.log(this === e.currentTarget)  // true
}
const element = document.getElementById('do')
element.addEventListener('click', bluify, false)

內(nèi)聯(lián)事件處理函數(shù)

當(dāng)代碼被內(nèi)聯(lián) on-event 處理函數(shù)調(diào)用時(shí),它的 this 指向監(jiān)聽(tīng)器所在的 DOM 元素。

<button onclick="alert(this.tagName.toLowerCase());">Show this</button>

類上下文

this 在 class 中的表現(xiàn)與在函數(shù)中類似,因?yàn)轭惐举|(zhì)上也是函數(shù),但也有一些區(qū)別和注意事項(xiàng)。在類的構(gòu)造函數(shù)中,this 是一個(gè)常規(guī)對(duì)象。類中所有非靜態(tài)的方法都會(huì)被添加到 this 的原型中。

class P {
   constructor () {
    const proto = Object.getPrototypeOf(this)
    console.log(Object.getOwnPropertyNames(proto))
   }
   first () {}
   second () {}
   static third () {}
}
new P()  // [ 'constructor', 'first', 'second' ]

不像基類的構(gòu)造函數(shù),派生類的構(gòu)造函數(shù)沒(méi)有初始的 this 綁定。派生類不能在調(diào)用 super() 之前返回,除非其構(gòu)造函數(shù)返回的是一個(gè)對(duì)象,或者根本沒(méi)有構(gòu)造函數(shù)。

class A extends P { }
class B extends P {
  constructor() {
    return { a: 5 }
  }
}
class C extends P {
  constructor() {
    super()
  }
}
class D extends P {
  constructor() { }
}
new A()  // ['constructor']
new B()  // 
new C()  // ['constructor']
new D()  // ReferenceError: Must call super constructor in derived class before

對(duì)象的方法

當(dāng)函數(shù)作為對(duì)象里的方法被調(diào)用時(shí),this 被設(shè)置為調(diào)用該函數(shù)的對(duì)象。

const o = {
  prop: 37,
  f: function () {
    return this.prop
  }
}
console.log(o.f())  // 37

請(qǐng)注意,這樣的行為完全不會(huì)受函數(shù)定義方式或位置的影響。如果對(duì)象的方法里面包含 this,this 的指向就是方法運(yùn)行時(shí)所在的對(duì)象。該方法賦值給另一個(gè)對(duì)象,就會(huì)改變this 的指向。

const o = { prop: 37 }
function independent() {
  return this.prop
}
o.f = independent
console.log(o.f())  // 37

this 的綁定只受最接近的成員引用的影響,如果 this 所在的方法不在對(duì)象的第一層,這時(shí) this 只是指向當(dāng)前一層的對(duì)象,而不會(huì)繼承更上面的層。

a = {
  p: 1,
  b: {
    p: 2,
    m: function() {
      console.log(this, this.p)
    }
  }
}
a.b.m() // { p: 2, m: [Function: m] }, 2

但是,下面這幾種用法,都會(huì)改變 this 的指向。

var o ={
  n: function () {
    console.log(this)
  }
};
o.n()
// 情況一
(o.n = o.n)()  // window
// => (o.n = function () { console.log(this) })()
// => (function () { console.log(this) })()
// 情況二
(false || o.n)()  // window
// => (false || function () { console.log(this) })()
// 情況三
(1, o.n)()  // window
// => (1, function () { console.log(this) })()

原型鏈

對(duì)于在對(duì)象原型鏈上某處定義的方法,同樣的概念也適用。如果該方法存在于一個(gè)對(duì)象的原型鏈上,那么 this 指向的是調(diào)用這個(gè)方法的對(duì)象,就像該方法就在這個(gè)對(duì)象上一樣。

const o = {
  f: function () {
    return this.a + this.b
  }
}
const p = Object.create(o)
p.a = 1
p.b = 4
console.log(p.f())  // 5

getter 與 setter

再次,相同的概念也適用于當(dāng)函數(shù)在一個(gè) getter 或者 setter 中被調(diào)用。用作 getter 或 setter 的函數(shù)都會(huì)把 this 綁定到設(shè)置或獲取屬性的對(duì)象。

function sum() {
  return this.a + this.b + this.c
}
const o = {
  a: 1,
  b: 2,
  c: 3,
  get average() {
    return (this.a + this.b + this.c) / 3
  }
}
Object.defineProperty(o, 'sum', {
  get: sum,
  enumerable: true,
  configurable: true
})
console.log(o.average, o.sum)  // 2, 6

使用注意項(xiàng)

this 的動(dòng)態(tài)切換,為 JavaScript 創(chuàng)造了巨大的靈活性,但也使得編程變得困難和模糊。所以在使用的時(shí)候,需要特別注意以下幾點(diǎn)。

注意多層this

由于 this 的指向是不確定的,所以切勿在函數(shù)中包含多層的 this。

var o = {
  f1: function () {
    console.log(this)  // {f1: ?}
    var f2 = function () {
      console.log(this)  // Window
    }()
  }
}
o.f1()

f2 在編譯的時(shí)候提升到全局,所以是 window。如果要使用 o 作為 this,可以在 f1 記錄 this 然后使用。使用一個(gè)變量固定 this 的值,然后內(nèi)層函數(shù)調(diào)用這個(gè)變量,是非常常見(jiàn)的做法,請(qǐng)務(wù)必掌握。

JavaScript 提供了嚴(yán)格模式,也可以硬性避免這種問(wèn)題。嚴(yán)格模式下,如果函數(shù)內(nèi)部的 this 指向頂層對(duì)象,就會(huì)報(bào)錯(cuò)。

const counter = { count: 0 }
counter.inc = function () {
  'use strict'
  this.count++
}
const f = counter.inc
f()
// TypeError: Cannot read properties of undefined (reading 'count')

注意數(shù)組處理方法中的this

數(shù)組的 map 和 foreach 方法,允許提供一個(gè)函數(shù)作為參數(shù)。這個(gè)函數(shù)內(nèi)部不應(yīng)該使用 this

const o = {
  v: 'hello',
  p: [ 'a1', 'a2' ],
  f: function f() {
    this.p.forEach(function (item) {
      console.log(this, `${this.v} ${item}`)
    })
  }
}
o.f()
// window, undefined a1
// window, undefined a2

forEach 方法會(huì)調(diào)用數(shù)組中每一項(xiàng)的 toString 方法,所以 this 指向頂層對(duì)象 window。解決辦法同樣可以記錄 fthis,然后使用。另一種方法是將 this 當(dāng)作 foreach 方法的第二個(gè)參數(shù),固定它的運(yùn)行環(huán)境。

注意回調(diào)函數(shù)中的this

回調(diào)函數(shù)中的 this 往往會(huì)改變指向,最好避免使用。

var o = new Object()
o.f = function () {
  console.log(this)  // $('#button')
}
// jQuery 寫(xiě)法
$('#button').on('click', o.f)

點(diǎn)擊按鈕以后,此時(shí) this 不再指向 o 對(duì)象,而是指向按鈕的 DOM 對(duì)象,因?yàn)閒方法是在按鈕對(duì)象的環(huán)境中被調(diào)用的。為了解決這個(gè)問(wèn)題,可以采用 call、apply、bind 方法對(duì) this 進(jìn)行綁定,也就是使得 this 固定指向某個(gè)對(duì)象,減少不確定性。

以上就是JavaScript關(guān)鍵字this的使用方法詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript關(guān)鍵字this的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論