欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

無人不識又無人不迷糊的this

freeflydom
2024年3月28日 17:20 本文熱度 605

本文分享自華為云社區(qū)《3月閱讀周·你不知道的JavaScript | 無人不識又無人不迷糊的this》,作者: 葉一一。

關(guān)于this

this關(guān)鍵字是JavaScript中最復(fù)雜的機(jī)制之一。它是一個(gè)很特別的關(guān)鍵字,被自動定義在所有函數(shù)的作用域中。

為什么要用this

隨著開發(fā)者的使用模式越來越復(fù)雜,顯式傳遞上下文對象會讓代碼變得越來越混亂,使用this則不會這樣。

比如下面的例子:

function identify() {

  return this.name.toUpperCase();

}


function speak() {

  var greeting = "Hello, I'm " + identify.call(this);

  console.log(greeting);

}


var me = {

  name: 'Kyle',

};


var you = {

  name: 'Reader',

};


console.log(identify.call(me)); 

console.log(identify.call(you)); 


speak.call(me); 

speak.call(you);

打印一下結(jié)果:

 

上面的代碼可以在不同的上下文對象(me和you)中重復(fù)使用函數(shù)identify()和speak(),不用針對每個(gè)對象編寫不同版本的函數(shù)。如果不使用this,那就需要給identify()和speak()顯式傳入一個(gè)上下文對象。

誤解

有兩種常見的對于this的解釋,但是它們都是錯(cuò)誤的。

1、指向自身

人們很容易把this理解成指向函數(shù)自身。

那么為什么需要從函數(shù)內(nèi)部引用函數(shù)自身呢?常見的原因是遞歸(從函數(shù)內(nèi)部調(diào)用這個(gè)函數(shù))或者可以寫一個(gè)在第一次被調(diào)用后自己解除綁定的事件處理器。

看下面這段代碼,思考foo會被調(diào)用了多少次?

function foo(num) {

  console.log('foo: ' + num);


  // 記錄foo被調(diào)用的次數(shù)

  this.count++;

}


foo.count = 0;


var i;

for (i = 0; i < 10; i++) {

  if (i > 5) {

    foo(i);

  }

}


// foo被調(diào)用了多少次?

console.log(foo.count);

打印結(jié)果:

 

console.log語句產(chǎn)生了4條輸出,證明foo(..)確實(shí)被調(diào)用了4次,但是foo.count仍然是0。顯然從字面意思來理解this是錯(cuò)誤的。

執(zhí)行foo.count = 0時(shí),的確向函數(shù)對象foo添加了一個(gè)屬性count。但是函數(shù)內(nèi)部代碼this.count中的this并不是指向那個(gè)函數(shù)對象。

2、它的作用域

第二種常見的誤解是,this指向函數(shù)的作用域。這個(gè)問題有點(diǎn)復(fù)雜,因?yàn)樵谀撤N情況下它是正確的,但是在其他情況下它卻是錯(cuò)誤的。

this在任何情況下都不指向函數(shù)的詞法作用域。

function foo() {

  var a = 2;

  this.bar();

}


function bar() {

  console.log(this.a);

}


foo();

直接打印上面的代碼會得到一個(gè)報(bào)錯(cuò):

 

這段代碼試圖通過this.bar()來引用bar()函數(shù)。這是不可能實(shí)現(xiàn)的,使用this不可能在詞法作用域中查到什么。

每當(dāng)開發(fā)者想要把this和詞法作用域的查找混合使用時(shí),一定要提醒自己,這是無法實(shí)現(xiàn)的。

this到底是什么

this的綁定和函數(shù)聲明的位置沒有任何關(guān)系,只取決于函數(shù)的調(diào)用方式。

當(dāng)一個(gè)函數(shù)被調(diào)用時(shí),會創(chuàng)建一個(gè)活動記錄(有時(shí)候也稱為執(zhí)行上下文)。這個(gè)記錄會包含函數(shù)在哪里被調(diào)用(調(diào)用棧)、函數(shù)的調(diào)用方式、傳入的參數(shù)等信息。this就是這個(gè)記錄的一個(gè)屬性,會在函數(shù)執(zhí)行的過程中用到。

this全面解析

調(diào)用位置

在理解this的綁定過程之前,首先要理解調(diào)用位置:調(diào)用位置就是函數(shù)在代碼中被調(diào)用的位置(而不是聲明的位置)。

尋找調(diào)用位置就是尋找“函數(shù)被調(diào)用的位置”。最重要的是要分析調(diào)用棧(就是為了到達(dá)當(dāng)前執(zhí)行位置所調(diào)用的所有函數(shù))。調(diào)用位置就在當(dāng)前正在執(zhí)行的函數(shù)的前一個(gè)調(diào)用中。

通過下面的代碼來看什么是調(diào)用棧和調(diào)用位置:

function baz() {

  // 當(dāng)前調(diào)用棧是:baz

  // 因此,當(dāng)前調(diào)用位置是全局作用域


  console.log('baz');

  bar(); // <-- bar的調(diào)用位置

}


function bar() {

  // 當(dāng)前調(diào)用棧是baz -> bar

  // 因此,當(dāng)前調(diào)用位置在baz中


  console.log('bar');

  foo(); // <-- foo的調(diào)用位置

}


function foo() {

  // 當(dāng)前調(diào)用棧是baz -> bar -> foo

  // 因此,當(dāng)前調(diào)用位置在bar中


  console.log('foo');

}


baz(); // <-- baz的調(diào)用位置

打印的結(jié)果如下:

 

綁定規(guī)則

來看看在函數(shù)的執(zhí)行過程中調(diào)用位置如何決定this的綁定對象。

首先必須找到調(diào)用位置,然后判斷需要應(yīng)用下面四條規(guī)則中的哪一條。

充分理解四條規(guī)則之后,再理解多條規(guī)則都可用時(shí)它們的優(yōu)先級如何排列。

1、默認(rèn)綁定

首先要介紹的是最常用的函數(shù)調(diào)用類型:獨(dú)立函數(shù)調(diào)用。可以把這條規(guī)則看作是無法應(yīng)用其他規(guī)則時(shí)的默認(rèn)規(guī)則。

var a = 2;


function foo() {

  console.log(this.a);

}


foo(); // 2

打印結(jié)果是2。也就是當(dāng)調(diào)用foo()時(shí),this.a被解析成了全局變量a。函數(shù)調(diào)用時(shí)應(yīng)用了this的默認(rèn)綁定,因此this指向全局對象。

2、隱式綁定

另一條需要考慮的規(guī)則是調(diào)用位置是否有上下文對象,或者說是否被某個(gè)對象擁有或者包含,不過這種說法可能會造成一些誤導(dǎo)。

思考下面的代碼:

function foo() {

  console.log(this.a);

}


var obj = {

  a: 2,

  foo: foo,

};


obj.foo(); // 2

當(dāng)foo()被調(diào)用時(shí),它的前面確實(shí)加上了對obj的引用。當(dāng)函數(shù)引用有上下文對象時(shí),隱式綁定規(guī)則會把函數(shù)調(diào)用中的this綁定到這個(gè)上下文對象。因?yàn)檎{(diào)用foo()時(shí)this被綁定到obj,因此this.a和obj.a是一樣的。

3、顯式綁定

JavaScript提供的絕大多數(shù)函數(shù)以及你自己創(chuàng)建的所有函數(shù)都可以使用call(..)和apply(..)方法。

它們的第一個(gè)參數(shù)是一個(gè)對象,是給this準(zhǔn)備的,接著在調(diào)用函數(shù)時(shí)將其綁定到this。

因?yàn)榭梢灾苯又付╰his的綁定對象,因此我們稱之為顯式綁定。

思考下面的代碼:

function foo() {

  console.log(this.a);

}


var obj = {

  a: 2,

};


foo.call(obj); // 2

通過foo.call(..),我們可以在調(diào)用foo時(shí)強(qiáng)制把它的this綁定到obj上。

4、new綁定

在傳統(tǒng)的面向類的語言中,“構(gòu)造函數(shù)”是類中的一些特殊方法,使用new初始化類時(shí)會調(diào)用類中的構(gòu)造函數(shù)。通常的形式是這樣的:

something = new MyClass(..);

在JavaScript中,構(gòu)造函數(shù)只是一些使用new操作符時(shí)被調(diào)用的函數(shù)。它們并不會屬于某個(gè)類,也不會實(shí)例化一個(gè)類。實(shí)際上,它們甚至都不能說是一種特殊的函數(shù)類型,它們只是被new操作符調(diào)用的普通函數(shù)而已。

優(yōu)先級

1、四條規(guī)則的優(yōu)先級

new綁定 > 顯式綁定 > 隱式綁定 > 默認(rèn)綁定。

2、判斷this

可以根據(jù)優(yōu)先級來判斷函數(shù)在某個(gè)調(diào)用位置應(yīng)用的是哪條規(guī)則。可以按照下面的順序來進(jìn)行判斷:

(1)函數(shù)是否在new中調(diào)用(new綁定)?如果是的話this綁定的是新創(chuàng)建的對象。

var bar = new foo();

(2)函數(shù)是否通過call、apply(顯式綁定)或者硬綁定調(diào)用?如果是的話,this綁定的是指定的對象。

var bar = foo.call(obj2);

(3)函數(shù)是否在某個(gè)上下文對象中調(diào)用(隱式綁定)?如果是的話,this綁定的是那個(gè)上下文對象。

var bar = obj1.foo();

(4)如果都不是的話,使用默認(rèn)綁定。如果在嚴(yán)格模式下,就綁定到undefined,否則綁定到全局對象。

var bar = foo();

綁定例外

在某些場景下this的綁定行為會出乎意料,你認(rèn)為應(yīng)當(dāng)應(yīng)用其他綁定規(guī)則時(shí),實(shí)際上應(yīng)用的可能是默認(rèn)綁定規(guī)則。

被忽略的this

如果你把null或者undefined作為this的綁定對象傳入call、apply或者bind,這些值在調(diào)用時(shí)會被忽略,實(shí)際應(yīng)用的是默認(rèn)綁定規(guī)則:

function foo() {

  console.log(this.a);

}


var a = 2;


foo.call(null); // 2

那么什么情況下會傳入null呢?

一種非常常見的做法是使用apply(..)來“展開”一個(gè)數(shù)組,并當(dāng)作參數(shù)傳入一個(gè)函數(shù)。類似地,bind(..)可以對參數(shù)進(jìn)行柯里化(預(yù)先設(shè)置一些參數(shù)),這種方法有時(shí)非常有用。

間接引用

另一個(gè)需要注意的是,你有可能(有意或者無意地)創(chuàng)建一個(gè)函數(shù)的“間接引用”,在這種情況下,調(diào)用這個(gè)函數(shù)會應(yīng)用默認(rèn)綁定規(guī)則。

間接引用最容易在賦值時(shí)發(fā)生:

function foo() {

  console.log(this.a);

}

var a = 2;

var o = { a: 3, foo: foo };

var p = { a: 4 };


o.foo(); // 3

(p.foo = o.foo)(); // 2

賦值表達(dá)式p.foo = o.foo的返回值是目標(biāo)函數(shù)的引用,因此調(diào)用位置是foo()而不是p.foo()或者o.foo()。根據(jù)我們之前說過的,這里會應(yīng)用默認(rèn)綁定。

軟綁定

如果可以給默認(rèn)綁定指定一個(gè)全局對象和undefined以外的值,那就可以實(shí)現(xiàn)和硬綁定相同的效果,同時(shí)保留隱式綁定或者顯式綁定修改this的能力。

function foo() {

  console.log('name: ' + this.name);

}


var obj = { name: 'obj' },

  obj2 = { name: 'obj2' },

  obj3 = { name: 'obj3' };


var fooOBJ = foo.softBind(obj);


fooOBJ(); // name: obj


obj2.foo = foo.softBind(obj);

obj2.foo(); // name: obj2 <---- 看!! !


fooOBJ.call(obj3); // name: obj3 <---- 看!


setTimeout(obj2.foo, 10);

// name: obj   <---- 應(yīng)用了軟綁定

可以看到,軟綁定版本的foo()可以手動將this綁定到obj2或者obj3上,但如果應(yīng)用默認(rèn)綁定,則會將this綁定到obj。

this詞法

ES6中介紹了一種無法使用這些規(guī)則的特殊函數(shù)類型:箭頭函數(shù)。箭頭函數(shù)并不是使用function關(guān)鍵字定義的,而是使用被稱為“胖箭頭”的操作符=>定義的。箭頭函數(shù)不使用this的四種標(biāo)準(zhǔn)規(guī)則,而是根據(jù)外層(函數(shù)或者全局)作用域來決定this。

箭頭函數(shù)的詞法作用域:

function foo() {

  // 返回一個(gè)箭頭函數(shù)

  return a => {

    //this繼承自foo()

    console.log(this.a);

  };

}


var obj1 = {

  a: 2,

};


var obj2 = {

  a: 3,

};


var bar = foo.call(obj1);

bar.call(obj2); // 2, 不是3!

foo()內(nèi)部創(chuàng)建的箭頭函數(shù)會捕獲調(diào)用時(shí)foo()的this。由于foo()的this綁定到obj1,bar(引用箭頭函數(shù))的this也會綁定到obj1,箭頭函數(shù)的綁定無法被修改。

總結(jié)

我們來總結(jié)一下本篇的主要內(nèi)容:

  • this實(shí)際上是在函數(shù)被調(diào)用時(shí)發(fā)生的綁定,它指向什么完全取決于函數(shù)在哪里被調(diào)用。

  • 如果要判斷一個(gè)運(yùn)行中函數(shù)的this綁定,就需要找到這個(gè)函數(shù)的直接調(diào)用位置。找到之后就可以順序應(yīng)用下面這四條規(guī)則來判斷this的綁定對象。

  • ES6中的箭頭函數(shù)并不會使用四條標(biāo)準(zhǔn)的綁定規(guī)則,而是根據(jù)當(dāng)前的詞法作用域來決定this,具體來說,箭頭函數(shù)會繼承外層函數(shù)調(diào)用的this綁定(無論this綁定到什么)。這其實(shí)和ES6之前代碼中的self = this機(jī)制一樣。

 

轉(zhuǎn)自博客園,作者華為云開發(fā)聯(lián)盟https://www.cnblogs.com/huaweiyun/p/18096240


該文章在 2024/3/28 17:20:08 編輯過
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved