偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

JavaScript 中 this 的錯(cuò)誤認(rèn)識(shí)、綁定規(guī)則、常見問題講解

開發(fā) 前端
相信Javascript中的this會(huì)使很多同學(xué)在工作學(xué)習(xí)中產(chǎn)生困惑,筆者經(jīng)過閱讀各種資料及實(shí)際工作中的應(yīng)用,做了以下梳理,主要內(nèi)容包括長(zhǎng)期以來大家對(duì)this的錯(cuò)誤認(rèn)識(shí)及this的綁定規(guī)則,箭頭函數(shù)、實(shí)際工作場(chǎng)景中遇到的問題。

相信 Javascript 中的 this 會(huì)使很多同學(xué)在工作學(xué)習(xí)中產(chǎn)生困惑,筆者也同樣是,經(jīng)過閱讀各種資料及實(shí)際工作中的應(yīng)用,做了以下梳理,主要內(nèi)容包括長(zhǎng)期以來大家對(duì) this 的錯(cuò)誤認(rèn)識(shí)及 this 的綁定規(guī)則,箭頭函數(shù)、實(shí)際工作場(chǎng)景中遇到的問題,希望對(duì)于有此困惑的你能有所幫助。

[[336197]]

一、兩種錯(cuò)誤認(rèn)識(shí)

1. 指向自身

this 的第一個(gè)錯(cuò)誤認(rèn)識(shí)是,很容易把 this 理解成指向函數(shù)自身,其實(shí) this 的指向在函數(shù)定義階段是無法確定的,只有函數(shù)執(zhí)行時(shí)才能確定 this 到底指向誰,實(shí)際 this 的最終指向是調(diào)用它的那個(gè)對(duì)象。

下面示例,聲明函數(shù) foo(),執(zhí)行 foo.count=0 時(shí),像函數(shù)對(duì)象 foo 添加一個(gè)屬性 count。但是函數(shù) foo 內(nèi)部代碼 this.count 中的 this 并不是指向那個(gè)函數(shù)對(duì)象,for 循環(huán)中的 foo(i) 掉用它的對(duì)象是 window,等價(jià)于 window.foo(i),因此函數(shù) foo 里面的 this 指向的是 window。

  1. function foo(num){ 
  2.   this.count++; // 記錄 foo 被調(diào)用次數(shù) 
  3. foo.count = 0
  4. window.count = 0
  5. for(let i=0; i<10; i++){ 
  6.   if(i > 5){ 
  7.     foo(i); 
  8.   } 
  9. console.log(foo.count, window.count); // 0 4 

2. 指向函數(shù)的作用域

對(duì) this 的第二種誤解就是 this 指向函數(shù)的作用域

以下這段代碼,在 foo 中試圖調(diào)用 bar 函數(shù),是否成功調(diào)用,取決于環(huán)境。

  • 瀏覽器:在瀏覽器環(huán)境里是沒有問題的,全局聲明的函數(shù)放在了 window 對(duì)象下,foo 函數(shù)里面的 this 代指的是 window 對(duì)象,在全局環(huán)境中并沒有聲明變量 a,因此在 bar 函數(shù)中的 this.a 自然沒有定義,輸出 undefined。
  • Node.js:在 Node.js 環(huán)境下,聲明的 function 不會(huì)放在 global 全局對(duì)象下,因此在 foo 函數(shù)里調(diào)用 this.bar 函數(shù)會(huì)報(bào) TypeError: this.bar is not a function 錯(cuò)誤。要想運(yùn)行不報(bào)錯(cuò),調(diào)用 bar 函數(shù)時(shí)省去前面的 this。
  1. function foo(){ 
  2.   var a = 2
  3.   this.bar(); 
  4. function bar(){ 
  5.   console.log(this.a); 
  6. foo(); 

二、This 四種綁定規(guī)則

1. 默認(rèn)綁定

當(dāng)函數(shù)調(diào)用屬于獨(dú)立調(diào)用(不帶函數(shù)引用的調(diào)用),無法調(diào)用其他的綁定規(guī)則,我們給它一個(gè)稱呼 “默認(rèn)綁定”,在非嚴(yán)格模式下綁定到全局對(duì)象,在使用了嚴(yán)格模式 (use strict) 下綁定到 undefined。

嚴(yán)格模式下調(diào)用:

  1. 'use strict' 
  2. function demo(){ 
  3.   // TypeError: Cannot read property 'a' of undefined 
  4.   console.log(this.a); 
  5. const a = 1
  6. demo(); 

非嚴(yán)格模式下調(diào)用:

在瀏覽器環(huán)境下會(huì)將 a 綁定到 window.a,以下代碼使用 var 聲明的變量 a 會(huì)輸出 1。

  1. function demo(){ 
  2.   console.log(this.a); // 1 
  3. var a = 1
  4. demo(); 

以下代碼使用 let 或 const 聲明變量 a 結(jié)果會(huì)輸出 undefined

  1. function demo(){ 
  2.   console.log(this.a); // undefined 
  3. let a = 1
  4. demo(); 

在舉例子的時(shí)候其實(shí)想要重點(diǎn)說明 this 的默認(rèn)綁定關(guān)系的,但是你會(huì)發(fā)現(xiàn)上面兩種代碼因?yàn)榉謩e使用了 var、let 進(jìn)行聲明導(dǎo)致的結(jié)果也是不一樣的,歸其原因涉及到 頂層對(duì)象的概念

在 Issue: Nodejs-Roadmap/issues/11 里有童鞋提到這個(gè)疑問,也是之前的疏忽,再簡(jiǎn)單聊下頂層對(duì)象的概念,頂層對(duì)象(瀏覽器環(huán)境指 window、Node.js 環(huán)境指 Global)的屬性和全局變量屬性的賦值是相等價(jià)的,使用 var 和 function 聲明的是頂層對(duì)象的屬性,而 let 就屬于 ES6 規(guī)范了,但是 ES6 規(guī)范中 let、const、class 這些聲明的全局變量,不再屬于頂層對(duì)象的屬性。

2. 隱式綁定

在函數(shù)的調(diào)用位置處被某個(gè)對(duì)象包含,擁有上下文,看以下示例:

  1. function child() { 
  2.   console.log(this.name); 
  3. let parent = { 
  4.   name: 'zhangsan', 
  5.   child, 
  6. parent.child(); // zhangsan 

函數(shù)在調(diào)用時(shí)會(huì)使用 parent 對(duì)象上下文來引用函數(shù) child,可以理解為child 函數(shù)被調(diào)用時(shí) parent 對(duì)象擁有或包含它。

隱式綁定的隱患:

被隱式綁定的函數(shù),因?yàn)橐恍┎恍⌒牡牟僮鲿?huì)丟失綁定對(duì)象,此時(shí)就會(huì)應(yīng)用最開始講的綁定規(guī)則中的默認(rèn)綁定,看下面代碼:

  1. function child() { 
  2.   console.log(this.name); 
  3. let parent = { 
  4.   name: 'zhangsan', 
  5.   child, 
  6. let parentparent2 = parent.child; 
  7. var name = 'lisi'
  8. parent2(); 

將 parent.child 函數(shù)本身賦給 parent2,調(diào)用 parent2() 其實(shí)是一個(gè)不帶任何修飾的函數(shù)調(diào)用,因此會(huì)應(yīng)用默認(rèn)綁定。

3. 顯示綁定

顯示綁定和隱式綁定從字面意思理解,有一個(gè)相反的對(duì)比,一個(gè)表現(xiàn)的更直接,一個(gè)表現(xiàn)的更委婉,下面在看下兩個(gè)規(guī)則各自的含義:

  • 隱式綁定:在一個(gè)對(duì)象的內(nèi)部通過屬性間接引用函數(shù),從而把 this 隱式綁定到對(duì)象內(nèi)部屬性所指向的函數(shù)(例如上例中的對(duì)象 parent 的 child 屬性引用函數(shù) function child(){})。
  • 顯示綁定:需要引用一個(gè)對(duì)象時(shí)進(jìn)行強(qiáng)制綁定調(diào)用,js 有提供 call()、apply() 方法,ES5 中也提供了內(nèi)置的方法 Function.prototype.bind。

call()、apply() 這兩個(gè)函數(shù)的第一個(gè)參數(shù)都是設(shè)置 this 對(duì)象,區(qū)別是 apply 傳遞參數(shù)是按照數(shù)組傳遞,call 是一個(gè)一個(gè)傳遞。

  1. function fruit(...args){ 
  2.   console.log(this.name, args); 
  3. var apple = { 
  4.   name: '蘋果' 
  5. var banana = { 
  6.   name: '香蕉' 
  7. fruit.call(banana, 'a', 'b')  // [ 'a', 'b' ] 
  8. fruit.apply(apple, ['a', 'b']) // [ 'a', 'b' ] 

下面是 bind 綁定的示例,只是將一個(gè)值綁定到函數(shù)的 this 上,并將綁定好的函數(shù)返回,只有在執(zhí)行 fruit 函數(shù)時(shí)才會(huì)輸出信息,例:

  1. function fruit(){ 
  2.   console.log(this.name); 
  3. var apple = { 
  4.   name: '蘋果' 
  5. fruitfruit = fruit.bind(apple); 
  6. fruit(); // 蘋果 

除了以上 call、apply、bind 還可以通過上下文 context,例:

  1. function fruit(name){ 
  2.   console.log(`${this.name}: ${name}`); 
  3. const obj = { 
  4.   name: '這是水果', 
  5. const arr = ['蘋果', '香蕉']; 
  6. arr.forEach(fruit, obj); 
  7. // 這是水果: 蘋果 
  8. // 這是水果: 香蕉 

4. new 綁定

new 綁定也可以影響 this 調(diào)用,它是一個(gè)構(gòu)造函數(shù),每一次 new 綁定都會(huì)創(chuàng)建一個(gè)新對(duì)象。

  1. function Fruit(name){ 
  2.   this.name = name; 
  3.  
  4. const f1 = new Fruit('apple'); 
  5. const f2 = new Fruit('banana'); 
  6. console.log(f1.name, f2.name); // apple banana 

三、優(yōu)先級(jí)

如果 this 的調(diào)用位置同時(shí)應(yīng)用了多種綁定規(guī)則,它是有優(yōu)先級(jí)的:new 綁定 -> 顯示綁定 -> 隱式綁定 -> 默認(rèn)綁定。

四、箭頭函數(shù)

箭頭函數(shù)并非使用 function 關(guān)鍵字進(jìn)行定義,也不會(huì)使用上面所講解的 this 四種標(biāo)準(zhǔn)規(guī)范,箭頭函數(shù)會(huì)繼承自外層函數(shù)調(diào)用的 this 綁定。

執(zhí)行 fruit.call(apple) 時(shí),箭頭函數(shù) this 已被綁定,無法再次被修改。

  1. function fruit(){ 
  2.   return () => { 
  3.     console.log(this.name); 
  4.   } 
  5. var apple = { 
  6.   name: '蘋果' 
  7. var banana = { 
  8.   name: '香蕉' 
  9. var fruitfruitCall = fruit.call(apple); 
  10. fruitCall.call(banana); // 蘋果 

五、This 使用中的幾個(gè)常見問題

1. 通過函數(shù)和原型鏈模擬類

以下示例,定義函數(shù) Fruit,之后在原型鏈上定義 info 方法,實(shí)例化對(duì)象 f1 和定義對(duì)象 f2 分別調(diào)用 info 方法。

  1. function Fruit(name) { 
  2.   this.name = name; 
  3. Fruit.prototype.info = function() { 
  4.   console.log(this.name); 
  5. const f1 = new Fruit('Apple'); 
  6. f1.info(); 
  7. const f2 = { name: 'Banana' }; 
  8. f2.info = f1.info; 
  9. f2.info() 

輸出之后,兩次結(jié)果是不一樣的,原因是 info 方法里的 this 對(duì)應(yīng)的不是定義時(shí)的上下文,而是調(diào)用時(shí)的上下文,根據(jù)我們上面講的幾種綁定規(guī)則,對(duì)應(yīng)的是隱式綁定規(guī)則。

  1. Apple 
  2. Banana 

2. 原型鏈上使用箭頭函數(shù)

如果使用構(gòu)造函數(shù)和原型鏈模擬類,不能在原型鏈上定義箭頭函數(shù),因?yàn)榧^函數(shù)的里的 this 會(huì)繼承外層函數(shù)調(diào)用的 this 綁定。

  1. function Fruit(name) { 
  2.   this.name = name; 
  3. Fruit.prototype.info = () => { 
  4.   console.log(this.name); 
  5. var name = 'Banana' 
  6. const f1 = new Fruit('Apple'); 
  7. f1.info(); 

3. 在事件中的使用

舉一個(gè) Node.js 示例,在事件中使用時(shí),當(dāng)我們的監(jiān)聽器被調(diào)用時(shí),如果聲明的是普通函數(shù),this 會(huì)被指向監(jiān)聽器所綁定的 EventEmitter 實(shí)例,如果使用的箭頭函數(shù)方式 this 不會(huì)指向 EventEmitter 實(shí)例。

  1. const EventEmitter = require('events'); 
  2. class MyEmitter extends EventEmitter { 
  3.   constructor() { 
  4.     super(); 
  5.     this.name = 'myEmitter'
  6.   } 
  7. const func1 = () => console.log(this.name); 
  8. const func2 = function () { console.log(this.name); }; 
  9. const myEmitter = new MyEmitter(); 
  10. myEmitter.on('event', func1); // undefined 
  11. myEmitter.on('event', func2); // myEmitter 
  12. myEmitter.emit('event'); 

 

責(zé)任編輯:趙寧寧 來源: Nodejs技術(shù)棧
相關(guān)推薦

2020-02-19 14:02:49

JavaScriptthis前端

2010-01-15 10:26:08

2019-10-30 14:58:45

MVCAndroid表現(xiàn)層

2013-04-07 10:17:54

WindowsPhon

2011-07-04 08:51:27

編程

2015-06-11 10:33:58

企業(yè)級(jí)云計(jì)算混合云應(yīng)用

2022-07-31 23:54:24

Linux操作系統(tǒng)

2011-07-14 14:15:40

ThreadLocal

2024-07-01 08:23:20

2009-09-07 16:44:28

Linq String

2011-02-22 14:00:16

vsftpd

2015-12-21 11:45:27

C語言常見問題錯(cuò)誤

2019-10-10 15:57:09

云安全混合云架構(gòu)

2013-11-14 15:47:29

SDN問題答疑

2011-04-01 13:55:24

Java

2011-05-06 15:39:55

硒鼓

2010-09-07 15:58:24

DB2數(shù)據(jù)庫性能

2010-07-21 09:10:02

Perl常見問題

2010-09-27 13:45:38

2011-07-21 11:19:51

JAVA
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)